pbd_constraints.h

  • compareIntArrays
    2つの整数配列が等しいかどうかを比較
  • sortRemoveDuplicates
    整数配列から重複する要素を削除し、要素をソートした新しい配列を返す
  • calcConstraintTopology
    拘束トポロジーに関するデータIDを取得
  • constraintAlias
    入力された拘束タイプの文字列に対応するエイリアスを返す
  • constraintHash
    拘束タイプのエイリアスに基づいてハッシュ値を生成する
  • isTriARAP
    拘束タイプがTriARAP(三角形の角度による最小二乗法)であるかどうかを判別
  • isTetARAPVol
    TetARAPにおける体積維持に使用する拘束の種類を判別
  • isTetARAP
    拘束タイプがTetARAP(四面体における剛体補間)であるかどうかを判別
  • isNonLinearARAP
    拘束タイプが非線形ARAPであるかどうかを判別
  • isTetFiber
    拘束タイプがTetFiber(特定方向に沿って圧縮することができる四面体拘束)であるかどうかを判別
  • computeDistanceRestLength
    2ポイント間の距離を計算
  • createDistanceConstraint
    入力ポイントから最も近いプリミティブ上の位置を計算し、restvectorrestlengthなどを作成
  • createAttachConstraint
    入力ポイントから最も近いプリミティブ上の位置を計算し、restvectorrestlengthなどを作成
  • projectToLine
    与えられた位置ベクトルを指定方向の直線上に射影
  • fromTriangleSpaceXform
    三角形からワールド空間への変換行列を返す
  • fromTriangleSpace
    3ポイントで構成される平面からワールド空間への回転ベクトルを返す
  • computeDistanceLineRestLength
    与えられたポイントと、指定された直線間の距離に基づいてrestlengthを計算
  • createAttachNormalConstraint
    対象プリミティブの法線情報を考慮したAttach拘束を作成
  • pointPrimTargetPos
    UV座標と対象プリミティブのポイント位置からターゲット位置を計算
  • pointPrimTargetPos
    pointPrimTargetPos関数のpattribPとしてオーバーロードしたもの
  • computePointPrimRestLength
    与えられたポイントとターゲットプリミティブ間の距離を計算
  • remapPolyLineUVs
    ポリライン上のUV座標を、対象となる線分内のパラメトリック値に変換
  • createStitchConstraint
    指定された条件に基づいて、2ポイント間にStitch(縫合)拘束を作成
  • oppositepoint
    与えられたハーフエッジに対して、反対側にあるポリゴンのポイントを返す
  • computeDihedralRestLength
    隣接する三角形の法線ベクトルから二面角を計算
  • createDihedralConstraint
    与えられたジオメトリ内のポイントに接続された隣接三角形間におけるDihedral(二面角)拘束を作成
  • createDihedralConstraintFromNewlyWeldedPrimitives
    新しくWeldされたプリミティブからDihedral(二面角)拘束を作成
  • computeOrientRodlengths
    連続する2つのポイント間の各セグメントの回転と長さを計算
  • computeBendTwistRestVector
    2ポイントのオリエンテーションを取得し、それらの間における最も近い回転を計算
  • createOutEdgeConstraint
    ポリライン上のポイントに対して、Distance(距離)拘束やBend(曲げ)拘束を作成
  • createStretchShearConstraint
    エッジに対して距離拘束と曲げ拘束を組み合わせたStretch-Shear拘束を作成
  • createBendTwistConstraint
    エッジ上のポイントの向きが同じになるようなBend-Twist(曲げ・捻じれ)拘束を作成
  • findBranchBendPoints
    ポリラインの分岐ポイントにおけるBend(曲げ)拘束を作成するために必要な2ポイントを見つける
  • createBranchWeldConstraints
    枝分かれ構造を維持するためのBranchstitch拘束および曲げ・捻じれ(Bend-Twist)拘束を作成
  • removeBranchWeldConstraints
    Branchstitch拘束および曲げ・捻じれ(Bend-Twist)拘束を削除
  • findVolumePoints
    三角形上のポイントを体積と勾配を求めるのに適した順番にする
  • computeVolume
    三角形の体積を計算
  • computePressureRestLength
    Pressure(圧力)拘束に必要な体積を計算
  • computePressureRestLength (volume)
    computePressureRestLength関数の計算モードをvolumeとしてオーバーロードしたもの
  • createPressureConstraint
    体積を維持するPressure(圧力)拘束を作成
  • createShapeMatchConstraint
    オブジェクトの形状を維持するShape Match拘束を作成
  • computeTetVolumeRestLength
    四面体の体積を計算
  • createTetVolumeConstraint
    四面体の体積を維持するTet Volume拘束を作成
  • computeAngleRestLength
    3つの連続するポイントを受け取り、その間の角度を計算
  • computeVertexCentroidDistance
    三角形の座標を受け取り、その座標から重心までの距離を計算
  • computeTriangleBendRestLength
    三角形のインデックスを受け取り、その座標から重心までの距離を計算
  • computeTriangleBendRestLengthFromAngle
    与えられた角度と仮定される三角形の辺の長さに基づいてrestlengthを計算
  • createTriangleBendConstraints
    与えられたポイントとその隣接ポイントの間にBend(曲げ)拘束を作成
  • createGlueConstraints
    指定された条件に基づいて、Glue(接着)拘束を作成
  • createStrutConstraints
    指定された条件に基づいて、Strut(支柱)拘束を作成
  • computeTetRestMatrix
    四面体のrestmatrix形状情報と体積を計算
  • computeTetFiberRestLength
    四面体の体積と圧縮方向であるmaterialWを計算
  • createTetFiberConstraint
    指定された条件に基づいて、Tet Fiber拘束を作成
  • computeTriRestMatrix
    三角形のrestmatrix(形状情報)と面積を計算
  • polardecomp2d
    2次元行列の極分解を計算
  • computeTriAreaRestLength
    指定されたスケーリング係数に基いて三角形の面積を計算
  • createTriStretchConstraint
    指定された条件に基づいて、Triangle Stretch拘束を作成
  • createTetStretchConstraint
    指定された条件に基づいて、Tetrahedral Stretch拘束を作成
  • orientedRestDifference
    ポイント間におけるオリエンテーションの差を計算
  • logscaleStiffness
    ログスケール変換
  • invlogscaleStiffness
    logscaleStiffnessの逆変換
  • updateRestVectorOrient
    角度/軸の差分ベクトルをもとにrestvectorを更新し、その角度を返す
  • squaredNorm2
    2x2行列におけるFrobeniusノルムの二乗を返す
  • squaredNorm3
    3x3行列におけるFrobeniusノルムの二乗を返す
  • updateRestMatrix2
    差分ベクトルをもとにrestvectorrestlengthを更新しノルムの差を返す
  • updateRestMatrix
    差分ベクトルをもとにrestmatrixrestlengthを更新しノルムの差を返す
  • computeRestVectorDifference
    四面体または三角形のcurrent-rest間におけるベクトル差分を計算
  • computeRestMatrixDifference
    四面体のcurrent-rest間におけるmatrix差分を計算
  • plasticDeformation
    塑性変形における塑性流動量を計算し、拘束の剛性値を更新する
  • getSourcePoints
    拘束タイプがdistance/stretchshear/weld/ptprimであったときに、最初の配列要素を返す
  • getTargetPoints
    拘束タイプがdistance/stretchshear/weld/ptprimであったときに、最初以外の配列要素を返す
  • accumScaleValues
    アトリビュートを指定されたモード(最小・最大・平均・乗算)で累積させる
  • falseColor
    入力値を指定した範囲に基づいてfalseを示すためのRGB値へ変換
  • weldTarget
    接合の目標となるポイント番号の取得
  • computeStress
    物体の変形や歪みによって生じる拘束に対するstress(応力)を計算
  • maxConstraintStress
    拘束ジオメトリに含まれるstress(応力)の最大値を返す
  • computeRestLengthDifference
    与えられた拘束タイプに基づいて、current-rest間における長さや角度の差分またはノルムを計算
  • updateFromRest
    与えられた拘束タイプに基づいて、restlengthrestvectorなどの値を更新
  • computeStiffnessDropoff
    Stiffness Dropoffを考慮した場合の剛性値を計算
  • restMetric
    塑性変形などの可視化に用いるためのrest状態におけるメトリックを計算
  • constraintMetric
    指定タイプにおける拘束ジオメトリの変化量を計算
  • maxConstraintMetric
    指定タイプにおける拘束ジオメトリの最大変化量を計算
  • warpWeftScale
    マテリアルUV座標に基づいて、織り方向のスケーリング値を計算
  • findwelds
    Weldに使用されているポイント配列を返す
  • walkdist
    目標ポイントから指定プリミティブまでの最短距離やそのプリミティブにおけるUV座標を計算
  • closestpttriangle
    指定したポイントpから三角形までの最も近いポイント座標を計算し、頂ポイントまたは辺の番号とバリセントリック座標を計算
  • closestpttriangle
    closestpttriangleのラッパー関数であり、対応するポイント番号やハーフエッジを求める機能が追加されている
  • ispolytri
    三角ポリゴンであるかどうか判別
  • triwalkdist
    三角プリミティブを対象として、与えられたジオメトリ内で目標位置に最も近いポイントを取得
  • extractRotation
    入力行列から回転成分を抽出
  • accumVec
    カハンの加算アルゴリズムを利用してベクトルの和を計算
  • accumMat3
    カハンの加算アルゴリズムを利用して3x3行列の和を計算
  • computeCmAndRot
    与えられたポイント集合に対して、rest-currentにおける重心を計算し、その最適な回転を求める
  • updateFromRestShapeMatch
    rest-current間における形状マッチングを行い、rest状態におけるポイントを更新
  • plasticDeformationShapeMatch
    Shape Match拘束を対象として塑性変形における塑性流動量を計算し、拘束の剛性値を更新
  • hasSmoothing
    与えられた拘束タイプが拘束解決時にスムージングが行えるか判別

compareIntArrays

2 つの整数配列が等しいかどうかを比較し、等しければ 1 を、そうでなければ 0 を返す

引数名説明
aint[]比較する最初の整数配列
bint[]比較する 2 番目の整数配列
int compareIntArrays(const int a[], b[])
{
    // 配列aとbの大きさが異なっている場合
    if (len(a) != len(b))
        return 0;

    foreach(int idx; int i; a)
    {
        // 要素を比較
        if (i != b[idx])
            return 0;
    }

    return 1;
}

sortRemoveDuplicates

整数配列から重複する要素を削除し、要素をソートした新しい配列を返す

引数名説明
aint[]ソートおよび重複削除を行う整数配列
int [] sortRemoveDuplicates(const int a[])
{
    int b[];
    resize(b, len(a));  // 配列の大きさを合わせる
    int sorted[] = sort(a); // 並べ替え
    int last = 0, first = 1;
    int idx = 0;

    foreach(int c; sorted)
    {
        // 最初の要素でなく、
        // 取り出した要素が前回の取り出した要素と同じ場合
        if (!first && c == last)
            continue;

        b[idx] = c; // 配列を更新
        idx++; // インクリメント
        
        // 次のループのため更新
        first = 0;
        last = c;
    }

    resize(b, idx); // 配列の大きさを合わせる
    return b;
}

calcConstraintTopology

拘束トポロジーに関するデータIDを取得

引数名説明
constraintgeoint拘束ジオメトリのデータID
pointgeointポイントジオメトリのデータID
int [] calcConstraintTopology(const int constraintgeo, pointgeo)
{
    // meta
    int topo[] = attribdataid(constraintgeo, "meta", "topology");
    append(topo, attribdataid(constraintgeo, "meta", "primitivelist"));

    // point
    append(topo, attribdataid(pointgeo, 'point', 'id'));
    append(topo, attribdataid(pointgeo, 'point', 'weld'));
    append(topo, attribdataid(pointgeo, 'point', 'branchweld'));

    return topo;
}

constraintAlias

入力された拘束タイプの文字列に対応するエイリアスを返す

引数名説明
typestring拘束タイプの文字列
string constraintAlias(const string type)
{
    // Handle alias conversion.
    if (type == "attach")
        return "pin";
    if (type == "stitch" || type == "branchstitch")
        return "distance";
    if (type == "attachnormal")
        return "distanceline";

    return type;
}

constraintHash

拘束タイプのエイリアスに基づいてハッシュ値を生成する

引数名説明
typestring拘束タイプの文字列
int constraintHash(const string type)
{
    return random_shash(constraintAlias(type));
}

isTriARAP

拘束タイプがTriARAP(三角形の角度による最小二乗法)であるかどうかを判別

  1. triarap: 三角形に対するARAPアルゴリズム
  2. triarapnl: 非線形変形を考慮した三角形に対するARAPアルゴリズム
  3. triarapnorm: 法線情報を維持しながら変形を行う三角形に対するARAPアルゴリズム
引数名説明
typestring拘束タイプの文字列
int isTriARAP(const string type)
{
    return type == "triarap" || type == "triarapnl" || type == "triarapnorm";
}

isTetARAPVol

TetARAPにおける体積維持に使用する拘束の種類を判別

  1. tetarapvol: 体積維持を考慮した四面体に対するARAPアルゴリズム
  2. tetarapnlvol: 非線形変形と体積維持を考慮した四面体に対するARAPアルゴリズム
  3. tetarapnormvol: 体積と法線を維持しながら変形を行う四面体に対するARAPアルゴリズム
引数説明
typestring判定対象の拘束タイプを表す文字列

isTetARAP

拘束タイプがTetARAP(四面体における剛体補間)であるかどうかを判別

  1. tetarap: 四面体に対するARAPアルゴリズム
  2. tetarapnl: 非線形変形を考慮した四面体に対するARAPアルゴリズム
  3. tetarapnorm: 法線情報を維持しながら変形を行う四面体に対するARAPアルゴリズム
引数名説明
typestring拘束タイプの文字列

int isTetARAP(const string type)
{
    return type == "tetarap" || type == "tetarapnl" || type == "tetarapnorm" || isTetARAPVol(type);
}

isNonLinearARAP

拘束タイプが非線形ARAPであるかどうかを判別

引数名説明
typestring拘束タイプの文字列
int isNonLinearARAP(const string type)
{
    return type == "triarapnl" || type == "tetarapnl" || type == "tetarapnlvol";
}


isTetFiber

拘束タイプがTetFiber(特定方向に沿って圧縮することができる四面体拘束)であるかどうかを判別

  1. tetfiber: 圧縮を考慮した四面体拘束
  2. tetfibernorm: 圧縮と法線情報を考慮しながら変形を行う四面体拘束
引数名説明
typestring拘束タイプの文字列
int isTetFiber(const string type)
{
    return type == "tetfiber" || type == "tetfibernorm";
}

computeDistanceRestLength

2ポイント間の距離を計算

引数名説明
geoint距離を計算するジオメトリのデータID
p0intジオメトリ内の1つ目のポイントのインデックス
p1intジオメトリ内の2つ目のポイントのインデックス
float
computeDistanceRestLength(const int geo; const int p0, p1)
{
    return distance(vector(point(geo, "P", p0)), vector(point(geo, "P", p1)));
}

createDistanceConstraint

隣接ポイントを結合し、polylineを作成

引数名説明
geoint距離拘束を生成する元のジオメトリ
ptnumintジオメトリ内のポイントのインデックス
srcgrpstring入力ジオメトリ内のポイントグループ名
outgeoint距離拘束を追加する出力ジオメトリ
outgrpstring出力ジオメトリ内の生成されたプリミティブのグループ名

void createDistanceConstraint(const int geo; const int ptnum; const string srcgrp;
                              const int outgeo; const string outgrp)
{
    // 隣接ポイント
    int nbrs[] = neighbours(geo, ptnum);

    foreach(int n; nbrs)
    {
        // 隣接ポイントがptnumより小さく、
        // グループに属していない場合
        if (n <= ptnum || !inpointgroup(geo, srcgrp, n))
            continue;
        
        // polyline
        int prim = addprim(outgeo, "polyline", array(ptnum, n));
        // outgrp (prim) <- 1
        setprimgroup(outgeo, outgrp, prim, 1);
        // restlength (prim) <- computeDistanceRestLength
        setprimattrib(outgeo, "restlength", prim, computeDistanceRestLength(geo, ptnum, n));
    }
}

createAttachConstraint

入力ポイントから最も近いプリミティブ上の位置を計算し、Attach拘束を作成

引数名説明
geointアタッチ拘束を生成する元のジオメトリ
attachgeointアタッチ先のジオメトリ
ptnumintジオメトリ内のポイントのインデックス
srcidxintソースインデックス
attachgrpstringアタッチ先ジオメトリ内のポイントまたはプリミティブグループ名
useclosestptint最も近いポイントを使用するかどうか(1:真、0:偽)
useclosestprimint最も近いプリミティブを使用するかどうか(1:真、0:偽)
maxdistcheckint最大距離チェックを行うかどうか(1:真、0:偽)
maxdistfloat最大距離制限
outgeointアタッチ拘束を追加する出力ジオメトリ
outgrpstring出力ジオメトリ内の生成されたプリミティブのグループ名

void
createAttachConstraint(const int geo, attachgeo; const int ptnum, srcidx; const string attachgrp;
                      const int useclosestpt, useclosestprim, maxdistcheck; const float maxdist;
                      const int outgeo; const string outgrp)
{
    int targetprim = -1, targetpt = -1;
    vector targetuv, targetpos;
    float dist;

    // 座標取得
    vector pos = point(geo, "P", ptnum);

    // 近接ポイントの使用
    if (useclosestpt)
    {
        // 近接プリミティブの使用
        if (useclosestprim)
        {
            // 探索範囲の指定
            if (maxdistcheck)
                // 対象となるプリミティブの距離やパラメトリックUV情報の取得
                dist = xyzdist(attachgeo, attachgrp, pos, targetprim, targetuv, maxdist);
            else
                dist = xyzdist(attachgeo, attachgrp, pos, targetprim, targetuv);
        }
        else
        {
            // 探索範囲指定
            if (maxdistcheck)
                // 近接ポイント番号の取得
                targetpt = nearpoint(attachgeo, attachgrp, pos, maxdist);
            else
                targetpt = nearpoint(attachgeo, attachgrp, pos);
        }
    }
    else
    {
        // attachgrpに属するポイント番号の取得と
        // srcidxに対応するポイントをtargetptへ
        int tgtpts[] = expandpointgroup(attachgeo, attachgrp);
        if (srcidx < len(tgtpts))
            targetpt = tgtpts[srcidx];
    }
    
    // targetprim, targetptが更新されなかった場合
    if (targetprim < 0 && targetpt < 0)
        return;

    // sphereプリミティブの作成
    int prim = addprim(outgeo, "sphere", ptnum);
    matrix3 t = 0.01;
    // transform (prim) <- t
    setprimintrinsic(outgeo, "transform", prim, t);
    // outgrp (prim) <- 1
    setprimgroup(outgeo, outgrp, prim, 1);

    // targetprimが存在
    if (targetprim >= 0)
    {
        // target_prim(prim) <- targetprim
        setprimattrib(outgeo, "target_prim", prim, targetprim);

        // target_uv(prim) <- targetuv
        setprimattrib(outgeo, "target_uv", prim, targetuv);

        // 座標取得
        targetpos = primuv(attachgeo, "P", targetprim, targetuv);
    }
    else if (targetpt >= 0) // targetptのみが存在
    {
        // target_pt(prim) <- target_pt
        setprimattrib(outgeo, "target_pt", prim, targetpt);

        // 座標取得
        targetpos = point(attachgeo, "P", targetpt);

        // 距離取得
        dist = distance(pos, targetpos);
    }

    // restvector(prim) <- targetpos
    setprimattrib(outgeo, "restvector", prim, (vector4)targetpos);

    // restlength(prim) <- dist
    setprimattrib(outgeo, "restlength", prim, dist);
}

projectToLine

与えられた位置ベクトルを指定方向の直線上に射影

引数名説明
posvector射影する位置ベクトル
origvector直線上の任意のポイントを表すベクトル
dirvector正規化された方向ベクトル(直線の方向を示す)
// dirは正規化されている必要がある
// Returns projection of pos onto the line, assuming dir is normalized.
vector projectToLine(const vector pos, orig, dir)
{
    return orig + dir * dot(pos - orig, dir);
}

fromTriangleSpaceXform

3ポイントで構成される平面からワールド空間への変換行列を返す
pbd_constraints.cl の toTriangleSpaceXformと一致させる必要がある

引数名説明
p0vector三角形の頂ポイント1の座標
p1vector三角形の頂ポイント2の座標
p2vector三角形の頂ポイント3の座標
// Returns the matrix to transform from triangle to world space.
// This MUST match toTriangleSpaceXform in pbd_constraints.cl.
matrix3 fromTriangleSpaceXform(const vector p0, p1, p2)
{
    // 2ポイントからベクトルを作成
    vector e0 = p1 - p0; 
    vector e1 = p2 - p0;
    
    // 外積を用いてe0とe1と直行するベクトルを作成しz軸として使用
    // x軸、y軸は、z軸と同様の方法で作成
    vector e2 = cross(e1, e0); 
    vector z  = normalize(e2); // 正規化
    vector y = normalize(cross(e0, z));
    vector x = cross(y, z);
    return set(x, y, z);
}


fromTriangleSpace

3ポイントで構成される平面からワールド空間への回転ベクトルを返す

引数名説明
pathstringジオメトリのパス
primintポリゴンを指定するプリミティブのインデックス
dirvector三角形空間からワールド空間へ回転させるベクトル
invertint逆変換を行うかどうか(1:真、0:偽)
// 入力プリミティブ最初の3ポイントから構成される面を用いてワールド座標系への変換行列を作成
// 変換行列を用いてdirベクトルを回転

// Rotate the vector from triangle space using the first three points of the polygon
// specified in prim.  Invert from world space to triangle if directed.
vector
fromTriangleSpace(const string path; const int prim; const vector dir; const int invert)
{
    // ポリゴンを構成しているポイント3ポイントを取得し、ワールド座標系への変換行列を作成
    int pts[] = primpoints(path, prim);
    vector p0 = point(path, "P", pts[0]);
    vector p1 = point(path, "P", pts[1]);
    vector p2 = point(path, "P", pts[2]);

    // 変換行列
    matrix3 xform = fromTriangleSpaceXform(p0, p1, p2);

    // invertが有効の場合は、作成した変換行列を転置
    if (invert)
        return dir * transpose(xform);
    return dir * xform;
}

computeDistanceLineRestLength

与えられたポイントと指定された直線間の距離に基づいてrestlengthを計算

引数名説明
geoint距離を計算する元のジオメトリ
pt0intジオメトリ内のポイントのインデックス
origvector直線上の任意のポイントを表すベクトル
indirvector直線の方向を示すベクトル
pathstringジオメトリのパス(三角形空間の変換が必要な場合)
primintポリゴンを指定するプリミティブのインデックス
float
computeDistanceLineRestLength(const int geo; const int pt0; const vector orig, indir;
                              const string path; const int prim)
{
    vector pos = point(geo, "P", pt0);

    // Transform from triangle space if needed.
    // 三角面からなる空間の変換が必要な場合は、
    // pathとプリミティブ番号を指定し
    // fromTriangleSpaceを用いてdirベクトルを変換
    vector dir = indir;
    if (path != "" && prim >=0)
        dir = fromTriangleSpace(path, prim, dir, 0);

    // posと直線上に射影したポイントとの距離を返す
    return distance(pos, projectToLine(pos, orig, dir));
}

createAttachNormalConstraint

ターゲットジオメトリの法線を考慮したAttach拘束を作成

引数名説明
geoint入力ジオメトリ
ptnumintジオメトリ内のポイントのインデックス
targetpathstringターゲットジオメトリのパス
targetprimintターゲットジオメトリのプリミティブインデックス
targetuvvectorターゲットジオメトリのプリミティブ上のUV座標
outgeoint出力ジオメトリ
outgrpstring出力ジオメトリのプリミティブグループ名
// Create an AttachNormal constraint that stores the line direction in restdir
// in triangle space.
// NOTE: Possibly more convenient would be to store restdir in world space, but also
// store a 3x3 matrix that would transform it back to triangle space.  Then on each
// timestep we would update restdir from the current target geometry with:
// v@restdir *= 3@restmatrix * curmatrix;
// where curmatrix is the current triangle-to-world transform, then:
// 3@restmatrix = invert(curmatrix);
// But this would require storing an extra matrix per constraint.
int
createAttachNormalConstraint(const int geo; const int ptnum;
                            const string targetpath;
                            const int targetprim; const vector targetuv;
                            const int outgeo; const string outgrp)
{
    vector pos = point(geo, "P", ptnum);
    // Orig is point on target attach geometry.
    vector orig = primuv(targetpath, "P", targetprim, targetuv);
    // Dir is ray from orig to point position.  This will be close to the normal
    // for convex geometry, but might vary quite a bit for non-convex. We use
    // this instead of the normal so the rest state is stable in the latter case.
    vector dir = normalize(pos - orig);

    // Transform to triangle space; the solver will transform back to world space
    // based on current target geometry point positions.
    // Only polygons.
    // ポリゴンのみ
    if (primintrinsic(targetpath, "typeid", targetprim) != 1) // typeid: 1 -> Poly
        return -1;
    // With at least three points to form a basis.
    // 少なくとも3ポイントから構成
    if (len(primpoints(targetpath, targetprim)) < 3)
        return -1;

    // dirベクトルの回転(invert)
    dir = fromTriangleSpace(targetpath, targetprim, dir, /*invert=*/ 1);

    // sphereプリミティブの作成
    int prim = addprim(outgeo, "sphere", ptnum);
    matrix3 t = 0.01;

    // transform (prim) <- t
    setprimintrinsic(outgeo, "transform", prim, t);
    // target_prim (prim) <- targetprim
    setprimattrib(outgeo, "target_prim", prim, targetprim);
    // target_uv (prim) <- targetuv
    setprimattrib(outgeo, "target_uv", prim, targetuv);
    // target_path (prim) <- targetpath
    setprimattrib(outgeo, "target_path", prim, targetpath);

    // Restlength is always zero to constraint directly to line to closest point.
    // 接ポイントは0
    // restlength (prim) <- 0.0 
    setprimattrib(outgeo, "restlength", prim, 0.0f);
    // restvector (prim) <- orig 接地ポイント
    setprimattrib(outgeo, "restvector", prim, (vector4) orig);
    // restdir (prim) <- dir 更新した方向ベクトル
    setprimattrib(outgeo, "restdir", prim, dir);
    // outgrp (prim) <- 1
    setprimgroup(outgeo, outgrp, prim, 1);

    return prim; // プリミティブ番号
}

pointPrimTargetPos

UV座標と対象プリミティブのポイント位置からターゲット位置を計算

引数名説明
geointジオメトリ
ptsint[]プリミティブのポイントインデックスの配列
ufloatUV座標のU値
vfloatUV座標のV値
pattribstring対象のポイント属性名
// Compute the target position directly from the uv coords and the primitive's
// point positions.  (We can't use primuv because we don't know the primitive
// number, and don't want to try to track it.)
vector pointPrimTargetPos(const int geo; const int pts[]; const float u, v; const string pattrib)
{
    vector p0 = point(geo, pattrib, pts[0]);
    vector p1 = point(geo, pattrib, pts[1]);
    // Only line segments, triangles and quads.
    int npts = len(pts);

    if (npts == 2)  // ライン
    {
        float w0 = (1 - u);
        float w1 = u;
        return w0 * p0 + w1 * p1;
    }
    else if (npts == 3)  // 三角ポリゴン
    {
        vector p2 = point(geo, pattrib, pts[2]);
        float w0 = (1 - u - v);
        float w1 = u;
        float w2 = v;
        return w0 * p0 + w1 * p1 + w2 * p2;
    }
    else if (npts == 4) // 四角ポリゴン
    {
        vector p2 = point(geo, pattrib, pts[2]);
        vector p3 = point(geo, pattrib, pts[3]);
        float u1 = 1 - u;
        float v1 = 1 - v;
        float w0 = (u1 * v1);
        float w1 = (u1 * v);
        float w2 = (u * v);
        float w3 = (u * v1);
        return w0 * p0 + w1 * p1 + w2 * p2 + w3 * p3;
    }
    return 0;
}

pointPrimTargetPos

pointPrimTargetPos関数のpattribを"P" としてオーバーロードしたもの

引数名説明
geointジオメトリ
ptsint[]プリミティブのポイントインデックスの配列
ufloatUV座標のU値
vfloatUV座標のV値
// オーバーロード
vector pointPrimTargetPos(const int geo; const int pts[]; const float u, v)
{
    return pointPrimTargetPos(geo, pts, u, v, "P");
}

computePointPrimRestLength

与えられたポイントとターゲットプリミティブ間の距離を計算

引数名説明
geointジオメトリ
ptint計算する距離の基準となるポイントのインデックス
tgtptsint[]ターゲットプリミティブのポイントインデックスの配列
restvectorvector4ターゲットプリミティブのUV座標 (x, y) とW座標 (z, w)
// pointPrimTargetPosで求めた接地ポイントとの距離を計算

float computePointPrimRestLength(const int geo; const int pt; const int tgtpts[]; const vector4 restvector)
{
    int npts = len(tgtpts);
    // Only line segments, triangles, and quads.
    // ライン、三角ポリゴン、四角ポリゴンのみ
    if (npts < 2 || npts > 4)
        return 0;

    // 入力ジオメトリの座標
    vector pos = point(geo, "P", pt);
    // 接地ポイントの座標
    vector tgtpos = pointPrimTargetPos(geo, tgtpts, restvector.x, restvector.y);
    // 距離計算
    return distance(pos, tgtpos);
}

remapPolyLineUVs

ポリライン上のUV座標を、対象となる線分内のパラメトリック値に変換

引数名説明
geostringジオメトリのパス
targetprimint対象のプリミティブインデックス
targetptsint[]ターゲットプリミティブのポイントインデックスの配列
targetuvvectorターゲットプリミティブのUV座標
// Map from uv's over an entire polyline to a single parametric value along the
// line segment in which the uv point falls.  Targetpts should contain all the line
// points as input, but will have the segment points as output.
void
remapPolyLineUVs(const string geo; const int targetprim; int targetpts[]; vector targetuv)
{
    vector2 uv = set(targetuv.x, 0);

    // Convert to segment based mapping
    // ポリライン全体のUV座標を線分ベースのマッピングに変換
    // 正規化された値からセグメントへ (0-1 range -> actual point number)
    uv = primuvconvert(geo, uv, targetprim, PRIMUV_UNIT_TO_REAL);
    int pt0 = floor(uv.x);

    // If on last point we need to back up 1.
    if (pt0 >= len(targetpts) - 1)
        pt0 -= 1;

    uv.x -= pt0;

    targetpts = array(targetpts[pt0], targetpts[pt0 + 1]);
    targetuv = set(uv.x, 0, 0);
}

createStitchConstraint

指定された条件に基づいて、2ポイント間にStitch(縫合)拘束を作成

引数名説明
geointソースジオメトリのインデックス
ptnumintソースポイントのインデックス
srcidxintソースインデックス
targetgrpstringターゲットポイントグループの名前
useclosestptint最も近いポイントまたはプリミティブを使用するかどうかを示すフラグ
useclosestprimint最も近いプリミティブを使用するかどうかを示すフラグ
maxdistcheckint最大距離チェックを使用するかどうかを示すフラグ
maxdistfloat最大距離
outgeoint出力ジオメトリのインデックス
outgrpstring出力プリムグループの名前
void
createStitchConstraint(const int geo; const int ptnum, srcidx; const string targetgrp;
                      const int useclosestpt, useclosestprim, maxdistcheck; const float maxdist;
                      const int outgeo; const string outgrp)
{
    int targetprim = -1, targetpt = -1;
    vector targetuv, targetpos;
    float dist;
    int tgtpts[];

    // 座標取得
    vector pos = point(geo, "P", ptnum);

    // 近接ポイントの使用
    if (useclosestpt)
    {
        // 近接プリミティブの使用
        if (useclosestprim)
        {
            // 探索範囲の指定
            if (maxdistcheck)
                // 対象プリミティブの距離やパラメトリックUV情報の取得
                dist = xyzdist(geo, targetgrp, pos, targetprim, targetuv, maxdist);
            else
                dist = xyzdist(geo, targetgrp, pos, targetprim, targetuv);
        
            // targetprimの値が更新されない場合
            if (targetprim < 0)
                return;

            // Poly
            if (primintrinsic(geo, "typeid", targetprim) != 1)
                return;

            // 対象プリミティブ上のポイント取得
            tgtpts = primpoints(geo, targetprim);

            // polyline, remap to line segment.
            if (!primintrinsic(geo, "closed", targetprim))

                // UV座標を線分ベース(point number)へ変換
                // PRIMUV_UNIT_TO_REAL
                remapPolyLineUVs(sprintf("opinput:%d", geo), targetprim, tgtpts, targetuv);

            // Line segment, triangle, or quad polygons only.
            int npts = len(tgtpts);
            if (npts < 2 || npts > 4)
                return;
        }
        else
        {
            // 探索範囲の指定
            if (maxdistcheck)
                // 近接ポイント番号の取得
                targetpt = nearpoint(geo, targetgrp, pos, maxdist);
            else
                targetpt = nearpoint(geo, targetgrp, pos);
        }
    }
    else
    {
        // targetgrpに属するポイント番号の取得
        tgtpts = expandpointgroup(geo, targetgrp);

        // srcidxに対応するポイントをtargetptへ
        if (srcidx < len(tgtpts))
            targetpt = tgtpts[srcidx];
    }

    // targetprim, targetptが更新されなかった場合
    if (targetprim < 0 && targetpt < 0)
        return;

    int prim = -1;

    // targetprimが存在
    if (targetprim >= 0)
    {
        int pts[];
        append(pts, ptnum);
        append(pts, tgtpts);

        // UV座標のセット
        vector4 restvec = set(targetuv.x, targetuv.y, 0, 0);

        // polylineの作成
        prim = addprim(outgeo, "polyline", pts);

        // すでにxyzdistで距離は求めているが再度計算
        // Just to ensure these match exactly, even though we already know dist.
        dist = computePointPrimRestLength(geo, ptnum, tgtpts, restvec);

        // restlength (prim) <- dist
        setprimattrib(outgeo, "restlength", prim, dist);

        // restvector (prim) <- restvec 
        setprimattrib(outgeo, "restvector", prim, restvec);

        // type: ptprim
        setprimattrib(outgeo, "type", prim, "ptprim");
    }
    else if (targetpt >= 0) // targetptが存在
    {
        // polylineの作成
        prim = addprim(outgeo, "polyline", array(ptnum, targetpt));

        // restlength <- computeDistanceRestLength
        setprimattrib(outgeo, "restlength", prim, computeDistanceRestLength(geo, ptnum, targetpt));

        // type: stitch
        setprimattrib(outgeo, "type", prim, "stitch");
    }

    // outgrp (prim) <- 1
    setprimgroup(outgeo, outgrp, prim, 1);
}

oppositepoint

与えられたハーフエッジに対して、反対側にあるポリゴンのポイントを返す

引数名説明
geointジオメトリを参照する整数
hedgeintハーフエッジを参照する整数
int oppositepoint(const int geo; const int hedge)
{
    // hedgeの後に続くハーフエッジを取得し、ゴールポイント番号を取得
    return hedge_dstpoint(geo, hedge_next(geo, hedge));
}

computeDihedralRestLength

隣接する三角形の法線ベクトルから二面角を計算

引数名説明
geointジオメトリのID
pt0, pt1, pt2, pt3int2つの隣接三角形を構成する4つのポイントのインデックス
restlengthfloat計算された二面角の初期値(rest angle)を格納するための変数

// 指定した4つのポイントが形成する二面角の初期角度を計算
int computeDihedralRestLength(const int geo;
                              const int pt0, pt1, pt2, pt3;
                              float restlength)
{
    vector p0 = point(geo, "P", pt0);
    vector p1 = point(geo, "P", pt1);
    vector p2 = point(geo, "P", pt2);
    vector p3 = point(geo, "P", pt3);

    vector e = p3 - p2;
    float elen = length(e);

    // 長さが短すぎるものは0
    if (elen < 1e-6)
        return 0;

    float invElen = 1 / elen;

    // Find initial rest angle.
    // 平面の法線ベクトルを計算
    vector n1 = cross(p3 - p0, p2 - p0);
    vector n2 = cross(p2 - p1, p3 - p1);

    // 2つの法線ベクトルから二面角を計算
    float d = dot(normalize(n1), normalize(n2));
    d = clamp(d, -1, 1);
    float phi = acos(d);

    // We want to xpress phi a -PI..PI
    // 二面角は-PiからPiまで
    if (dot(cross(n1, n2), e) < 0)
        phi = -phi;

    // restlength <- 角度に変換した二面角
    restlength = degrees(phi);
    return 1;
}

createDihedralConstraint

与えられたジオメトリ内のポイントに接続された隣接三角形間におけるDihedral(二面角)拘束を作成

引数名説明
geoint入力ジオメトリのID
ptnumint拘束を作成するポイントのインデックス
srcgrpstring入力ジオメトリ内で拘束を作成するポイントを含むグループ名
outgeoint出力ジオメトリのID
outgrpstring作成された拘束プリミティブを含む出力ジオメトリのグループ名
void
createDihedralConstraint(const int geo; const int ptnum; const string srcgrp;
                        const int outgeo; const string outgrp)
{

    // 指定したポイントに属するプリミティブの配列を取得
    int prims[] = pointprims(geo, ptnum);

    // 取得したプリミティブごとに処理
    foreach(int prim; prims)
    {
        // プリミティブに属するポイントの配列を取得
        int primpts[] = primpoints(geo, prim);

        // Process triangles where this point is minimum point number,
        // and all points are in src group.
        // そのプリミティブが三角形であり、
        // 指定ポイントが最小のポイント番号であり、
        // 他の2つのポイントがsrcgrpというグループに属している
        if (len(primpts) != 3)
            continue;
        if (ptnum != min(primpts))
            continue;
        if (!inpointgroup(geo, srcgrp, primpts[1]) ||
            !inpointgroup(geo, srcgrp, primpts[2]))
            continue;

        // そのプリミティブに属する最初のハーフエッジ番号を取得
        int starthedge = primhedge(geo, prim);

        // ハーフエッジ番号が負ならreturn
        if (starthedge < 0)
            return;

        // Ignore open curves as the hedge function won't give us
        // the setup we expect with them.
        // 閉じているか
        if (primintrinsic(geo, 'closed', prim) == 0)
            return;

        int h = starthedge;
        int p = prim;
        int hasgrp = strlen(outgrp) > 0;

        while (1)
        {
            // Giving half edge h, add a bend polygon.
            // 隣接するハーフエッジを取得
            int oh = hedge_nextequiv(geo, h);

           // Skip boundary edges, invalid hedges, and non-manifold
           // edges
            if (h != oh && oh >= 0 && h == hedge_nextequiv(geo, oh))
            {
                int op = hedge_prim(geo, oh);
                // Always build in ascending direction.
                if (op >= 0 && p < op)
                {
                    // ハーフエッジと隣接するハーフエッジが形成する4つのポイント番号を取得
                    int pt0 = oppositepoint(geo, h);
                    int pt1 = oppositepoint(geo, oh);
                    int pt2 = hedge_srcpoint(geo, h);
                    int pt3 = hedge_dstpoint(geo, h);

                   // ポイントがすべてsrcgrpに属している
                    if (inpointgroup(geo, srcgrp, pt0) &&
                        inpointgroup(geo, srcgrp, pt1) &&
                        inpointgroup(geo, srcgrp, pt2) &&
                        inpointgroup(geo, srcgrp, pt3))
                    {
                        // 二面角の計算
                        float restlength;
                        if (computeDihedralRestLength(geo, pt0, pt1, pt2, pt3,
                                                      restlength))
                        {
                            // polyline
                            int newprim = addprim(outgeo, 'polyline', array(pt0, pt1, pt2, pt3));
                            // restlength (prim) <- restlength
                            setprimattrib(outgeo, "restlength", newprim, restlength);
                            
                            // グループが存在
                            if (hasgrp)
                                setprimgroup(outgeo, outgrp, newprim, 1);
                        }
                    }
                }
            }

            // 次のハーフエッジ取得
            int nh = hedge_next(geo, h);

            // Stop the loop when we complete the polygon
            // Closed polygons won't complete.
            // nhが最初のハーフエッジと同じか、無効ならループから抜ける
            if (nh == starthedge || nh < 0)
                break;

            // 次のループへ
            h = nh;
        }
    }
}

createDihedralConstraintFromNewlyWeldedPrimitives

新しくWeldされたプリミティブからDihedral(二面角)拘束を作成

引数名説明
geoint入力ジオメトリのID
oldgeoint元のジオメトリのID
primint処理対象のプリミティブインデックス
outgeoint出力ジオメトリのID
outgrpstring作成された拘束プリミティブを含む出力ジオメトリのグループ名

// この関数の目的は、ソフトボディシミュレーションに使用できる、
// 新しく溶接されたプリミティブの間の二面体拘束を作成することです
// この拘束は、複雑なオブジェクトが外力を受けて変形する際に、その形状を保持するのに役立ちます

void
createDihedralConstraintFromNewlyWeldedPrimitives(const int geo; const int oldgeo; const int prim;
                                                  const int outgeo; const string outgrp)
{
    // ポイント番号の取得
    int primpts[] = primpoints(geo, prim);

    // プリミティブが3つのポイントを持っていた場合は何もしない
    if (len(primpts) != 3)
      return;

    // ハーフエッジの取得
    int starthedge = primhedge(geo, prim);

    // ハーフエッジがなければ何もしない
    if (starthedge < 0)
      return;

    // Ignore open curves as the hedge function won't give us
    // the setup we expect with them.
    // 閉じているか
    if (primintrinsic(geo, 'closed', prim) == 0)
      return;

    int h = starthedge;
    int p = prim;
    int hasgrp = strlen(outgrp) > 0; // グループを持っていた場合

    // hedge_next を用いて、プリミティブ上すべてのハーフエッジをループし、
    // 各ハーフエッジ (h) に対して、別のプリミティブ (op) 上と同等の半辺 (oh) を hedge_nextequiv 関数で探索
    while (1)
    {
      // Giving half edge h, add a bend polygon.
      // starthedgeに対応する次のハーフエッジを取得
      int oh = hedge_nextequiv(geo, h);

      // Skip boundary edges, invalid hedges, and non-manifold
      // edges
      // 境界のエッジ、無効なハーフエッジ、非多様体エッジはスキップ
      if (h != oh && oh >= 0 && h == hedge_nextequiv(geo, oh))
      {
        // ハーフエッジ (oh)に含まれるプリミティブ (op) を取得
        int op = hedge_prim(geo, oh);

        // Always build in ascending direction.
        // 常に方向は昇順
        // プリミティブインデックス (p) が他のプリミティブインデックス (op) よりも小さい場合のみ、
        // ベンドポリゴン (4ポイントを持つポリライン) を構築
        if (op >= 0 && p < op)
        **{
          // 二面角を計算するためのポイントを取得**
          int pt0 **=** oppositepoint(geo, h);
          int pt1 = oppositepoint(geo, oh);
          int pt2 = hedge_srcpoint(geo, h);
          int pt3 = hedge_dstpoint(geo, h);

          // See if we became welded.  Because hedges are
          // linear vertex numbers, these will match in the
          // two and we can find the corresponding half edge
          // in the other geometry directly.
          // So, if our h & oh don't have matching points
          // in the old geo, we know we are a newly welded edge.
          // ハーフエッジが新しくウェルドされたかどうかは、
          // 両方のジオメトリ(geoとoldgeo)のソースポイントとデスティネーションポイントを比較
          // もし一致しない場合は、何らかの操作(ブール演算など)によりマージされたことを意味
          if (hedge_srcpoint(oldgeo, h) != hedge_dstpoint(oldgeo, oh) ||
              hedge_dstpoint(oldgeo, h) != hedge_srcpoint(oldgeo, oh))
          {
              float restlength;

              // computeDihedralRestLength というカスタム関数を使用して、ベンドポリゴンの二面角を計算
              // この関数は、変形時に元の形状を維持するために、ベンドポリゴンをどれだけ伸縮させるべきかを計算
              if (computeDihedralRestLength(geo, pt0, pt1, pt2, pt3, restlength))
              {
                  // 出力ジオメトリ(outgeo)にタイプ 'polyline' の新しいプリミティブを追加し、
                  // その属性 'restlength' を計算されたものと同じに設定
                  int newprim = addprim(outgeo, 'polyline', array(pt0, pt1, pt2, pt3));
                  setprimattrib(outgeo, "restlength", newprim, restlength);

                  // 出力グループ名 (outgrp) が与えられている場合は、
                  // この新しいプリミティブもそのグループに追加
                  if (hasgrp)
                      setprimgroup(outgeo, outgrp, newprim, 1);
              }
            }
          }
        }
  
      // 次のハーフエッジを取得
      int nh = hedge_next(geo, h);
    
      // Stop the loop when we complete the polygon
      // Closed polygons won't complete.
      // プリミティブ上のハーフエッジを一周したらループから抜ける
      if (nh == starthedge || nh < 0)
        break;

      // 次のstarthedgeとする
      h = nh;
    }
}

computeOrientRodlengths

連続する2つのポイント間の各セグメントの回転と長さを計算

引数名説明
geoint入力ジオメトリのID
primnumint処理対象のプリミティブインデックス
srcgrpstring入力ジオメトリで対象とするポイントグループの名前
outgeoint出力ジオメトリのID
// inertia: パーティクルの回転ヘアー拘束の抵抗力

// Compute point orients and store the rodlengths in the inertia attribute.
// vellum constraint: compute_orient_rodlengths
// computeOrientRodlengths(0, @primnum, "__constraintsrc", geoself())

void
computeOrientRodlengths(const int geo; const int primnum; const string srcgrp;
                        const int outgeo)
{ 
    // Ignore anything but open polylines.
    // 開いているポリラインのみ処理対象とする
    if (primintrinsic(geo, "typename", primnum) != "Poly" ||
        primintrinsic(geo, "closed", primnum) == 1)
        return;

    // Only test group if it's not all points.
    // グループを持っているか
    int hasgrp = npointsgroup(geo, srcgrp) < npoints(geo);

    // Check if the points have an incoming orient attribute. If os, we assume
    // that it provides a stable basis in which to calculate our rod-aligned orients.
    // ジオメトリがorientアトリビュートを持っているかどうか
    int hasporient = haspointattrib(geo, "orient");
    vector from = {0, 0, 1};

    // Iterate over pts in vertex order.
    // 頂ポイント順にイテレーション
    int pts[] = primpoints(geo, primnum); // 各プリミティブ上のポイントを取得
    int npts = len(pts); // 頂ポイントの総数
    vector4 orients[];  
    float rodlens[];
    resize(orients, npts - 1);  // 配列をリサイズ
    resize(rodlens, npts - 1); // 配列をリサイズ

    int lastpt = pts[npts - 1];  // 最後のポイントインデックス
    int loop = 0;

   // 連続する2ポイント間の各セグメントについて回転と長さを計算
    for(int i=0; i < npts - 1; i++)
    {
        // 
        vector d = point(geo, "P", pts[i + 1]) - point(geo, "P", pts[i]);
        vector to = normalize(d);

        // ポイントがorientを持っていた場合は向きを変換
        if (hasporient)
        {
            // Transform vectors back to rest orientation.
            vector4 porient = point(geo, "orient", pts[i]);
            to = qrotate(qinvert(porient), to);
        }
  
        // {0, 0, 1} から toベクトルへのクォータニオンを作成
        vector4 dq = dihedral(from, to);

        // 始ポイント以外は、前のorient分に傾ける
        if (i == 0)
            orients[i] = dq;
        else
            orients[i] = qmultiply(dq, orients[i-1]);
  
        // rodlens <- 2ポイント間の距離
        rodlens[i] = length(d);

        from = to;  // 次のループで使用するベクトル方向

        // Check if this is a loop.
        // ポリラインがループしているかどうか
        loop |= (pts[i] == lastpt); 
    }

    for(int i=0; i < npts - 1; i++)
    {
        // orientを持っていた場合は、ワールド空間に戻す
        if (hasporient)
        {
            // Rotate new orientation back to current world orientation.
            vector4 porient = point(geo, "orient", pts[i]);
            orients[i] = qmultiply(porient, orients[i]);
        }

        // Make sure to do the above rotation in the orients array
        // before possibly skipping this point based on group membership,
        // otherwise if we then grab the rotation for the last point from
        // the previous vertex, it could be incorrect if the previous
        // vertex wasn't in srcgrp. (Exiting too early caused bug 97655.)
        // 最後のポイントの回転を前の頂ポイントから取得する際に,
        // 前の頂ポイントが srcgrp に含まれていない場合に不正確な回転が発生する
        if (hasgrp && !inpointgroup(geo, srcgrp, pts[i]))
            continue;

        // Set new orientation, possibly overwriting input orientation.
        // orient <- orients[i] of pts[i]
        setpointattrib(geoself(), "orient", pts[i], orients[i]);

        float inertia = point(geo, "inertia", pts[i]);

        // Don't overwrite pinned inertia
        // pin固定されている場合(inertiaが0)、上書きしない
        if (inertia == 0.0)
            continue;

        // 距離をinertiaとして設定
        // inertia <- rodlens[i] of pts[i]
        setpointattrib(geoself(), "inertia", pts[i], rodlens[i]);
    }

    // Set inertia and orient for last point if not already seen as part of a loop.
    // ポイント総数が1以上で、最終ポイントがsrcgrpに属しており、かつポリラインがループしていない
    if (npts > 1 && inpointgroup(geo, srcgrp, lastpt) && !loop)
    {
        float inertia = point(geo, "inertia", lastpt);
        // Don't overwrite pinned inertia
        if (inertia != 0.0)
            setpointattrib(geoself(), "inertia", lastpt, rodlens[npts - 2]);
        // Copy previous orient so final bend/twist rest relative orient is
        // identity, which reduces flipping when final vertex orientation is
        // otherwise unconstrained.
        setpointattrib(geoself(), "orient", lastpt, orients[npts - 2]);
    }
}

computeBendTwistRestVector

2ポイントのオリエンテーションを取得し、それらの間における最も近い回転を計算

引数名説明
geoint入力ジオメトリのインデックス
pt0int最初のポイントのインデックス
pt1int2番目のポイントのインデックス
computeBendTwistRestVector(const int geo; const int pt0, pt1)
{
    // Discrete Darbeaux vector is just closest rotation from
    // first orientation to second.

    // pt0の共役
    vector4 q0conj = point(geo, "orient", pt0) * {-1, -1, -1, 1};
    vector4 q1 = point(geo, "orient", pt1);

    // q0からq1への回転
    vector4 restDarbeaux = qmultiply(q0conj, q1);

    // quaternion: (x, y, z, w)
    // wの範囲が-1から1であることを利用し単位クォータニオンを加算・減算
    vector4 omegaplus = restDarbeaux + {0, 0, 0, 1}; // 正の方向
    vector4 omegaminus = restDarbeaux - {0, 0, 0, 1}; // 負の方向

    // もしomegaminusのdot積がomegaplusのdot積より大きい場合、
    // 最も近い回転ではないので-1を掛けて反転
    if (dot(omegaminus, omegaminus) > dot(omegaplus, omegaplus))
        restDarbeaux *= -1;

    return restDarbeaux;
}

createOutEdgeConstraint

ポリライン上のポイントに対して、Distance(距離)拘束やBend(曲げ)拘束を作成

引数名説明
geoint入力ジオメトリのインデックス
ptnumintポイントのインデックス
srcgrpstring入力ジオメトリのソースグループ名
typestring拘束タイプ("stretchshear"またはその他)
outgeoint出力ジオメトリのインデックス
outgrpstring出力ジオメトリの出力グループ名
// Create a single constraint of the specified type along the (first and only) output edge from
// the provided point, assuming we're dealing with points on polylines.
// ポリライン上のポイントを処理対象として想定し、
// Constraintを作成(Type: stretchshear or bendtwist)
void
createOutEdgeConstraint(const int geo; const int ptnum; const string srcgrp; const string type;
                        const int outgeo; const string outgrp)
{
    // 隣接しているポイント番号の取得
    int nbrs[] = neighbours(geo, ptnum);

    foreach(int n; nbrs)
    {
        // Only create if the in-group neighbor is the destination of an edge.
        // srcgrpに所属していない、またはハーフエッジが無効
        if (!inpointgroup(geo, srcgrp, n) || pointhedge(geo, ptnum, n) < 0)
            continue;

        // polylineの作成
        int prim = addprim(outgeo, "polyline", array(ptnum, n));

        // stretchshear
        if (type == "stretchshear")
            // 長さを保持
            // restlength (prim) <- computeDistanceRestLength
            setprimattrib(outgeo, "restlength", prim, computeDistanceRestLength(geo, ptnum, n));
        else // bendtwist
            // 角度を保持
            // restvector (prim) <- computeBendTwistRestVector
            setprimattrib(outgeo, "restvector", prim, computeBendTwistRestVector(geo, ptnum, n));
        
        // outgrp <- 1
        setprimgroup(outgeo, outgrp, prim, 1);

        // Only one constraint per point.
        return;
    }
}

createStretchShearConstraint

エッジに対して距離拘束と曲げ拘束を組み合わせたStretch-Shear拘束を作成

引数名説明
geoint入力ジオメトリのインデックス
ptnumintポイントのインデックス
srcgrpstring入力ジオメトリのソースグループ名
outgeoint出力ジオメトリのインデックス
outgrpstring出力ジオメトリの出力グループ名
void
createStretchShearConstraint(const int geo; const int ptnum; const string srcgrp;
                            const int outgeo; const string outgrp)
{
    createOutEdgeConstraint(geo, ptnum, srcgrp, "stretchshear", outgeo, outgrp);
}

createBendTwistConstraint

エッジ上のポイントの向きが同じになるようなBend-Twist(曲げ・捻じれ)拘束を作成

引数名説明
geoint入力ジオメトリのインデックス
ptnumintポイントのインデックス
srcgrpstring入力ジオメトリのソースグループ名
outgeoint出力ジオメトリのインデックス
outgrpstring出力ジオメトリの出力グループ名
// Constraintを作成(Type: bendtwist)

void
createBendTwistConstraint(const int geo; const int ptnum; const string srcgrp;
                          const int outgeo; const string outgrp)
{
    createOutEdgeConstraint(geo, ptnum, srcgrp, "bendtwist", outgeo, outgrp);
}

findBranchBendPoints

ポリラインの分岐ポイントにおけるBend(曲げ)拘束を作成するために必要な2ポイントを見つける

引数名説明
geoint入力ジオメトリのインデックス
ptnumintポイントのインデックス
weldint溶接ポイントのインデックス
pt0int拘束を作成するための最初のポイントのインデックス(出力)
pt1int拘束を作成するための2番目のポイントのインデックス(出力)

// bend or twist constraintを作成するためのポイントを探す

int
findBranchBendPoints(const int geo; const int ptnum; const int weld;
                    int pt0, pt1)
{
    // weldの隣接ポイントを取得
    int nbrs[] = neighbours(geo, weld);
    
    foreach(int n; nbrs)
    {
        // Check if there's an edge pointing from n to the weld.
        // 隣接ポイントを含むハーフエッジがある場合
        if (pointhedge(geo, n, weld) >= 0)
        {
            // We need to create a constraint from n to this point also.
            pt0 = n;
            pt1 = ptnum;
            return 1;
        }
    }
    // If only one neighbor and there's no edge with weld as the destination,
    // then punt and make the constraint between the weld and ptnum
    // 隣接ポイントが1つだけで、目的のエッジが見つからなかった場合は、
    // pt0にweldを代入し、pt1にptnumを代入する
    if (len(nbrs) == 1)
    {
        pt0 = weld;
        pt1 = ptnum;
        return 1;
    }
    return 0;
}

createBranchWeldConstraints

枝分かれ構造を維持するためのBranchstitch拘束および曲げ・捻じれ(Bend-Twist)拘束を作成

引数名説明
geoint入力ジオメトリのインデックス
ptnumintポイントのインデックス
srcgrpstring入力ポイントのグループ名
maxbranchanglefloat最大ブランチ角度(度)
outgeoint出力ジオメトリのインデックス
outbendgrpstring出力プリミティブのベンドグループ名
void
createBranchWeldConstraints(const int geo; const int ptnum;
                            const string srcgrp; const float maxbranchangle;
                            const int outgeo; const string outbendgrp)
{
    // 結合ポイント
    int weld = point(geo, "branchweld", ptnum);

    // weldが無効、またはsrcgrpに属していない場合はreturn
    if (weld < 0 || !inpointgroup(geo, srcgrp, weld))
        return;

    // Stitch points together with stiff distance constraint.
    // TODO - do we need to parameterize this somehow?
    // プリミティブの作成(type: branchstitch)
    int cprim = addprim(outgeo, "polyline", array(weld, ptnum));
    setprimattrib(outgeo, "restlength", cprim, 0); // restlength <- 0
    setprimattrib(outgeo, "stiffness", cprim, 1e20);  // stiffness <- 1e20
    setprimattrib(outgeo, "dampingratio", cprim, 0.001); // dampingratio <- 0.001
    setprimattrib(outgeo, "type", cprim, "branchstitch"); // type <- branchstitch

    // Find the appropriate points for creating a bend/twist
    // constraint on the geometry.
    // 捻じれの回転角を計算するために
    // 曲げ・捻じれ拘束に適しているpt0, pt1を探す
    int pt0, pt1;
    if (!findBranchBendPoints(geo, ptnum, weld, pt0, pt1))
        return;

    // Compute Darbeaux vector for rotation.
    // 回転角の計算
    vector4 restvec = computeBendTwistRestVector(geo, pt0, pt1);

    // Skip creation if greater than max branching angle.
    // ラジアンへ変換
    float maxang = radians(maxbranchangle);

    // Compare against axis/angle represenation of quaternion.
    // 回転量がmaxang以上であれば、return
    if (length(qconvert(restvec)) > maxang)
        return;

    // polylineの作成
    cprim = addprim(outgeo, "polyline", array(pt0, pt1));

    // restvector (vector4) <- restvec
    setprimattrib(outgeo, "restvector", cprim, restvec);

    // outbendgrp (prim) <- 1
    setprimgroup(outgeo, outbendgrp, cprim, 1);
}

removeBranchWeldConstraints

Branchstitch拘束および曲げ・捻じれ(Bend-Twist)拘束を削除

引数名説明
congeoint拘束ジオメトリのインデックス
ptgeointポイントジオメトリのインデックス
primnumintプリミティブのインデックス
outgeoint出力ジオメトリのインデックス
// Called with the primitive representing the branchweld stitch/distance constraint.
void
removeBranchWeldConstraints(const int congeo, ptgeo; const int primnum; const int outgeo)
{
    // プリミティブ上のポイント取得
    int pts[] = primpoints(congeo, primnum);

    // If pt is not still branchwelded to weld, we need to delete constraints.
    int weld = pts[0];
    int pt = pts[1];
    int bw = point(ptgeo, "branchweld", pt);

    // branchweldに対応するポイント番号を取得
    if (bw >= 0)
        bw = idtopoint(ptgeo, bw);

    // Still welded, nothing to do.
    // まだweldされていた場合は、return
    if (weld == bw)
        return;

    // Remove this constraint stitching them together.
    // weldされていなかったものに関しては、プリミティブを削除する
    removeprim(outgeo, primnum, 0);

    // Look for bend/twist constraints joining the bend points,
    // assume it was created for branchwelding and remove.
    
    int bendpt0, bendpt1;
    if (!findBranchBendPoints(ptgeo, pt, weld, bendpt0, bendpt1))
        return;

    // ptに対応するプリミティブの取得
    int prims[] = pointprims(congeo, pt);

    // typeがbendtwistであるもの(曲げ/捻じれ拘束)に関しても削除する
    foreach(int prim; prims)
    {
        string type = prim(congeo, "type", prim);

        // typeがbendtwistのみ
        if (type != "bendtwist")
            continue;

        // // プリミティブ上のポイント取得
        int primpts[] = primpoints(congeo, prim);

        if (bendpt0 == primpts[0] && bendpt1 == primpts[1])
            removeprim(outgeo, prim, 0);
    }
}

findVolumePoints

三角形上のポイントを体積と勾配を求めるのに適した順番にする

引数名説明
geointジオメトリのインデックス
ptnumint対象となるポイントのインデックス
// Returns array of neighboring points on triangles that can
// be iterated through to calculate volume and gradients
// using cross products.
int []
findVolumePoints(const int geo; const int ptnum)
{
    // プリミティブ取得
    int prims[] = pointprims(geo, ptnum);
    int volpts[];

    foreach(int prim; prims)
    {
        // ポイント番号の取得
        int pts[] = primpoints(geo, prim);

        // Only triangles.
        // 三角形のみ
        if (len(pts) != 3)
            continue;

        // ptnumにマッチするポイント番号を取得
        int ppos = find(pts, ptnum);
        vector n = 0;

        // ppos以外のポイントをvolptsに追加
        if (ppos == 0)
            append(volpts, array(pts[2], pts[1]));
        if (ppos == 1)
            append(volpts, array(pts[0], pts[2]));
        if (ppos == 2)
            append(volpts, array(pts[1], pts[0]));
    }
    return volpts;
}

computeVolume

三角形の体積を計算

引数名説明
geointジオメトリのインデックス
ptnumint対象となるポイントのインデックス
volumeptsint[]体積計算に使用される三角形のポイントを表す配列
// Compute the volume for all triangles specified in the
// volumepts array for each point.  The volume is only
// counted if the current points is the lowest index of the tri.
float
computeVolume(const int geo; const int ptnum; const int volumepts[])
{
    int ntris = len(volumepts) / 2; // 三角形の数

    float volume = 0;
    vector pos = point(geo, "P", ptnum);

    for(int i = 0; i < ntris; i++)
    {
        int pt1 = volumepts[i * 2];
        int pt2 = volumepts[i * 2 + 1];

        // ポイントが最もインデックスの小さいポイントである場合にのみ体積を加算
        if (ptnum < pt1 && ptnum < pt2)
            volume += dot(pos,
                          cross(point(geo, "P", pt1), point(geo, "P", pt2)));
    }
    return volume / 6; // 体積
}

computePressureRestLength

Pressure(圧力)拘束に必要な体積を計算

引数名説明
geointジオメトリのインデックス
inptsint[]静止状態の体積を計算するためのポイントのインデックスの配列
modestring計算モード("volume"、"volumepts"、または他の任意の文字列)
float
computePressureRestLength(const int geo; const int inpts[]; const string mode)
{
    float restvol = 0;
    // Remove any duplicates that can arise from welding.
    // 重複しているポイントを削除しソート
    int pts[] = sortRemoveDuplicates(inpts);
    int volumepts[];

    foreach(int pt; pts)
    {
        if (mode == "volume")
        {
            // ポイントがvolume attributeを持っている場合はそのまま加算
            restvol += point(geo, "volume", pt);
        }
        else
        {
            // volumepts attributeを持っている場合は体積計算に利用
            // 持っていない場合はfindVolumePoints関数を用いてvolumeptsを見つける
            if (mode == "volumepts")
                volumepts = point(geo, "volumepts", pt);
            else // Use topology.
                volumepts = findVolumePoints(geo, pt);

            // 体積計算
            restvol += computeVolume(geo, pt, volumepts);
        }
    }
    return restvol;
}

computePressureRestLength (volume)

computePressureRestLength関数の計算モードをvolumeとしてオーバーロードしたもの

引数名説明
geointジオメトリのインデックス
inptsint[]静止状態の体積を計算するためのポイントのインデックスの配列

float
computePressureRestLength(const int geo; const int inpts[])
{
    // modeをvolumeとし体積計算
    return computePressureRestLength(geo, inpts, "volume");
}

createPressureConstraint

体積を維持するPressure(圧力)拘束を作成

引数名説明
geoint入力ジオメトリのインデックス
srcgrpstring対象となるポイントのグループ名
outgeoint出力ジオメトリのインデックス
outgrpstring作成された圧力拘束のプリミティブを含むグループ名
// Create a pressure constraint over the provided group of points.
void
createPressureConstraint(const int geo; const string srcgrp;
                        const int outgeo; const string outgrp)
{
    // srcgrpに属するポイント番号の取得
    int pts[] = expandpointgroup(geo, srcgrp);

    // Don't create empty constraint.
    // srcgrpに属するポイントがない場合はreturn
    if (len(pts) == 0)
        return;
    
    // polylineの作成
    int prim = addprim(outgeo, "polyline", pts);
    
    // volume attributeを用いて体積計算
    float restvol = computePressureRestLength(geo, pts, "volume");
    
    // restlength (prim) <- restvole
    setprimattrib(outgeo, "restlength", prim, restvol);
    
    // outgrp <- 1
    setprimgroup(outgeo, outgrp, prim, 1);
}

createShapeMatchConstraint

オブジェクトの形状を維持するShape Match拘束を作成

引数名説明
geoint入力ジオメトリのインデックス
srcgrpstring対象となるポイントのグループ名
outgeoint出力ジオメトリのインデックス
outgrpstring作成された形状マッチ拘束のプリミティブを含むグループ名
// srcgrpに属するポイントからShapematch Constraintを作成
// point attrs: rest <- P
// grp: outgrp <- 1

// Create a shapematch constraint over the provided group of points.
void
createShapeMatchConstraint(const int geo; const string srcgrp;
                          const int outgeo; const string outgrp)
{
    // srcgrpに属するポイント番号の取得
    int pts[] = expandpointgroup(geo, srcgrp);

    // Don't create empty constraint.
    // srcgrpに属するポイントがない場合はreturn
    if (len(pts) == 0)
        return;

    // Set rest for each point from current geo position.
    // 現在のポイントポジションからrest attributeを設定
    foreach(int pt; pts)
    {
        vector pos = point(geo, "P", pt);
        
        // rest (pt) <- pos
        setpointattrib(outgeo, "rest", pt, pos);
    }

    // polylineの作成
    int prim = addprim(outgeo, "polyline", pts);

    // outgrp <- 1
    setprimgroup(outgeo, outgrp, prim, 1);
}

computeTetVolumeRestLength

四面体の体積を計算

引数名説明
geoint入力ジオメトリのインデックス
pt0intテトラヘドロンの頂ポイント1のインデックス
pt1intテトラヘドロンの頂ポイント2のインデックス
pt2intテトラヘドロンの頂ポイント3のインデックス
pt3intテトラヘドロンの頂ポイント4のインデックス
float
computeTetVolumeRestLength(const int geo; const int pt0, pt1, pt2, pt3)
{
    vector p0 = point(geo, "P", pt0);
    vector p1 = point(geo, "P", pt1);
    vector p2 = point(geo, "P", pt2);
    vector p3 = point(geo, "P", pt3);

    return dot(cross(p0 - p1, p0 - p2), p0 - p3) / 6;
}

createTetVolumeConstraint

四面体の体積を維持するTet Volume拘束を作成

引数名説明
geoint入力ジオメトリのインデックス
ptnumint対象のポイントのインデックス
srcgrpstringソースポイントグループ名
outgeoint出力ジオメトリのインデックス
outgrpstring出力プリミティブグループ名
void
createTetVolumeConstraint(const int geo; const int ptnum; const string srcgrp;
                          const int outgeo; const string outgrp)
{
    // プリミティブの取得
    int prims[] = pointprims(geo, ptnum);

    foreach(int prim; prims)
    {
        // Process tets where this point is minimum point number,
        // and all points are in src group.
        // Typeid: 21 -> Tetrahedron のみ処理対象
        if(primintrinsic(geo, "typeid", prim) != 21)
            continue;

        // プリミティブからポイント取得
        int pts[] = primpoints(geo, prim);

        // 4つのポイントを持ち、
        // 指定されたポイント番号が最小であり、
        // 残りのポイントがすべてsrcgrpに属している場合のみ処理対象
        if (len(pts) != 4 ||
            ptnum != min(pts) ||
            !inpointgroup(geo, srcgrp, pts[1]) ||
            !inpointgroup(geo, srcgrp, pts[2]) ||
            !inpointgroup(geo, srcgrp, pts[3]))
            continue;

        // Tetrahedron Primitiveの作成
        int cprim = addprim(outgeo, "tet", pts);

        // 体積計算
        float volume = computeTetVolumeRestLength(geo, pts[0], pts[1], pts[2], pts[3]);
        
        // restlength (prim) <- volume
        setprimattrib(outgeo, "restlength", cprim, volume);

        // outgrp <- 1
        setprimgroup(outgeo, outgrp, cprim, 1);
    }
}

computeAngleRestLength

3つの連続するポイントを受け取り、その間の角度を計算

引数名説明
geointジオメトリのインデックス
pt0int1つ目のポイントのインデックス
pt1int2つ目のポイントのインデックス(中心ポイント)
pt2int3つ目のポイントのインデックス
float
computeAngleRestLength(const int geo;
                      const int pt0, pt1, pt2)
{
    vector p0 = point(geo, "P", pt0);
    vector p1 = point(geo, "P", pt1);
    vector p2 = point(geo, "P", pt2);

    vector n1 = normalize(p1 - p0);
    vector n2 = normalize(p2 - p1);

    // n1とn2の角度を計算
    // theta = acos(dot)
    return degrees(acos(clamp(dot(n1, n2), -1, 1)));
}

computeVertexCentroidDistance

三角形の座標を受け取り、その座標から重心までの距離を計算

引数名説明
p0vector1つ目のポイントの座標
p1vector2つ目のポイントの座標(対象の頂ポイント)
p2vector3つ目のポイントの座標
// Compute distance from vertex to centroid for triangle
float
computeVertexCentroidDistance(const vector p0, p1, p2)
{
    vector c = (p0 + p1 + p2) / 3;

    // Distance from vertex to centroid.
    return length(p1 - c);
}

computeTriangleBendRestLength

三角形のインデックスを受け取り、その座標から重心までの距離を計算

引数名説明
geointジオメトリのインデックス
pt0int1つ目のポイントのインデックス
pt1int2つ目のポイントのインデックス(対象の頂ポイント)
pt2int3つ目のポイントのインデックス
// Compute the rest length for the provided triangle.
float
computeTriangleBendRestLength(const int geo; const int pt0, pt1, pt2)
{
    vector p0 = point(geo, "P", pt0);
    vector p1 = point(geo, "P", pt1);
    vector p2 = point(geo, "P", pt2);

    return computeVertexCentroidDistance(p0, p1, p2);
}

computeTriangleBendRestLengthFromAngle

与えられた角度と仮定される三角形の辺の長さに基づいてrestlengthを計算

引数名説明
geointジオメトリのインデックス
pt0int1つ目のポイントのインデックス
pt1int2つ目のポイントのインデックス(対象の頂ポイント)
pt2int3つ目のポイントのインデックス
anglefloat与えられた角度(度数法)
// Compute the rest length for the provided angle (degrees), assuming the provided
// triangle edge lengths.
float
computeTriangleBendRestLengthFromAngle(const int geo; const int pt0, pt1, pt2; const float angle)
{
    vector p0 = point(geo, "P", pt0);
    vector p1 = point(geo, "P", pt1);
    vector p2 = point(geo, "P", pt2);

    // Re-create a triangle with vertex at 0 and the given side lengths and angle and
    // compute vertex/centroid distance.
    // 三角形を再構築
    float a = radians(angle);
    float r0 = length(p1 - p0);
    float r2 = length(p2 - p1);

    // 重心
    vector c = set(r2 * cos(a) - r0, r2 * sin(a), 0) / 3;

    // 距離
    return length(c);
}

createTriangleBendConstraints

与えられたポイントとその隣接ポイントの間にBend(曲げ)拘束を作成

引数名説明
geoint入力ジオメトリのインデックス
ptnumint中心となるポイントのインデックス
typestring拘束のタイプ
srcgrpstring対象となるポイントグループ名
maxbranchanglefloat最大枝分かれ角度(度数法)
outgeoint出力ジオメトリのインデックス
outgrpstring作成された拘束を格納するプリミティブグループ名

void
createTriangleBendConstraints(const int geo; const int ptnum; const string type;
                              const string srcgrp; const float maxbranchangle;
                              const int outgeo; const string outgrp)
{
    int midpt = ptnum;

    // 隣接ポイントの取得
    int nbrs[] = neighbours(geo, midpt);

    foreach(int startpt; nbrs)
    {
        foreach(int endpt; nbrs)
        {
            // もし両方の隣接ポイントがソースグループに属しており、
            // かつその角度が最大枝角度以下であれば、
            // 「polyline」プリミティブを追加し、
            // 「restlength」属性にその角度を設定
            if (startpt < endpt
                && inpointgroup(geo, srcgrp, startpt)
                && inpointgroup(geo, srcgrp, endpt))
            {
                float restlen = computeAngleRestLength(geo, startpt, midpt, endpt);
                
                
                if (restlen <= maxbranchangle)
                {
                    // polylineの作成
                    int cprim = addprim(outgeo, "polyline", array(startpt, midpt, endpt));
                    
                    // 拘束タイプが「trianglebend」であれば、
                    //「restlength」属性は三角形の曲げ拘束長さに設定
                    if (type == "trianglebend")
                        restlen = computeTriangleBendRestLength(geo, startpt, midpt, endpt);
                    
                    // restlength (prim) <- restlen
                    setprimattrib(outgeo, "restlength", cprim, restlen);
                    // type <- type
                    setprimattrib(outgeo, "type", cprim, type);
                    // outgrp <- 1
                    setprimgroup(outgeo, outgrp, cprim, 1);
                }
            }
        }
    }
}

createGlueConstraints

指定された条件に基づいて、Glue(接着)拘束を作成

引数名説明
geoint入力ジオメトリのインデックス
congeoint接続をチェックするジオメトリのインデックス
ptint拘束を作成するポイントのインデックス
srcgrpstring入力ジオメトリのポイントグループ名
dstgrpstring接続先ポイントグループ名
primgrpstring既存の拘束をチェックするためのプリミティブグループ名
classnamestringクラス名を格納するポイントアトリビュート名
useclusterintクラスタリングを使用するかどうか(0:使用しない、1:使用する)
clusterattribstringクラスタ名を格納するポイントアトリビュート名
numconstraintint作成する拘束の最大数
minradfloat最小距離制限
maxradfloat最大距離制限
maxptint近傍ポイントの最大数
prefint順序設定(1:最も遠いポイントから)
seedfloat乱数シード
thresholdfloat拘束を作成するためのしきい値
ptthresholdfloatしきい値をポイント接続に適用するためのパラメータ
outgeoint出力ジオメトリのインデックス
outgrpstring作成された拘束を格納するプリミティブグループ名
void
createGlueConstraints(const int geo, congeo; const int pt; const string srcgrp, dstgrp, primgrp, classname;
                      const int usecluster; const string clusterattrib;
                      const int numconstraint;
                      const float minrad, maxrad; const int maxpt; const int pref;
                      const float seed, threshold, ptthreshold;
                      const int outgeo; const string outgrp)
{
    vector pos = point(geo, "P", pt);

    // ポイント毎に作成するGlue Constraintの数
    int nconstraints = numconstraint;

    // Constraintが存在しない場合はreturn
    if (nconstraints <= 0)
        return;

    // 所属しているClassの取得
    int myclass = point(geo, classname, pt);
    string myclass_s = point(geo, classname, pt);

    int mycluster = -2;
    string mycluster_s = "";
    string clustername = clusterattrib;

    // clusterを使用
    if (usecluster)
    {
        mycluster = point(geo, clustername, pt);
        mycluster_s = point(geo, clustername, pt);
        // Cluster=-1 turns off gluing.
        if (mycluster == -1)
            return;
    }

    // thresholdより小さければreturn
    // threshold <- detach chance
    if ( float(rand(set(myclass, seed+M_PI))) < threshold)
    {
        return;
    }

    int indstgrp = inpointgroup(geo, dstgrp, pt);
    int hasprimgrp = strlen(primgrp) > 0;
    int nearpts[]  = nearpoints(geo, dstgrp, pos, maxrad, maxpt);

    // 最も遠いポイントから含まれるように反転
    if (pref == 1) // Farthest first
        nearpts = reverse(nearpts);

    foreach (int npt; nearpts)
    {
        // Skip this point.
        if (pt == npt)
            continue;

        // minradより小さければcontinue
        if (minrad > 0 && distance(pos, point(geo, "P", npt)) < minrad)
            continue;

        // If src is in dest group, and dst is in source group, then
        // the nearpoints lookup will be symmetric, so only create for lower point number
        // to avoid duplicates.
        // 重複を避ける
        if (indstgrp && inpointgroup(congeo, srcgrp, npt) && npt < pt)
            continue;

        // Compare classes.
        // 同じクラスであればcontinue
        int oclass = point(geo, classname, npt);
        string oclass_s = point(geo, classname, npt);
        if (oclass == myclass && oclass_s == myclass_s)
            continue;

        // Ignore disabled classes.
        // thresholdより小さければcontinue
        if (float(rand(set(oclass, seed+M_PI))) < threshold)
            continue;

        // Ignore disabled point connections, ensuring any two unique pointsets
        // are always used for the seed.
        // 接合箇所にバリエーションを与える
        // ptthresholdより小さければcontinue
        if (float(rand(set(min(pt, npt), max(pt, npt), seed))) < ptthreshold)
            continue;

        // Clustering.
        // 同じClusterに所属するポイント間で結合が行われるようにする
        if (usecluster)
        {
            int ocluster = point(geo, clustername, npt);
            string ocluster_s = point(geo, clustername, npt);
            if ((ocluster != mycluster) || (ocluster_s != mycluster_s))
            {
                continue;
            }
        }

        // Check for already existing constraint primitive connecting the points.
        // 既にConstraintプリミティブがある場合は、重複を避ける
        if (hasprimgrp)
        {
            int h = pointhedge(congeo, pt, npt);
            if (h < 0)
                h = pointhedge(congeo, npt, pt);
            if (h >= 0 && inprimgroup(congeo, primgrp, hedge_prim(congeo, h)))
                continue;
        }

        vector opos = point(geo, "P", npt);

        // Generate connecting line.
        int prim = addprim(outgeo, "polyline", array(pt, npt));
        setprimgroup(geoself(), outgrp, prim, 1);  // outgrp (prim) <- 1
        float rlen = distance(pos, opos);
        setprimattrib(geoself(), "restlength", prim, rlen);  // restlength (prim) <- rlen

        // Found a good constraint, decrement.
        nconstraints--;
        if (nconstraints <= 0)
            break;
    }
}

createStrutConstraints

指定された条件に基づいて、Strut(支柱)拘束を作成

引数名説明
geoint入力ジオメトリのインデックス
ptnumintStrut拘束を作成するポイントのインデックス
srcgrpstring入力ジオメトリのポイントグループ名
classnamestringクラス名を格納するポイントアトリビュート名
dirattribstring方向ベクトルを格納するポイントアトリビュート名
revnmlint法線を反転するかどうか(0:反転しない、1:反転する)
checknmlint法線チェックを行うかどうか(0:行わない、1:行う)
numconstraintint作成する拘束の最大数
maxlenfloat最大距離制限
jitterfloat方向ベクトルのジッター(ランダムノイズ)
rayofffloatレイのオフセット距離
seedfloat乱数シード
ptthresholdfloatしきい値をポイント接続に適用するためのパラメータ
outgeoint出力ジオメトリのインデックス
outgrpstring作成された拘束を格納するプリミティブグループ名
void
createStrutConstraints(const int geo; const int ptnum;
                      const string srcgrp, classname, dirattrib;
                      const int revnml, checknml;
                      const int numconstraint;
                      const float maxlen, jitter, rayoff;
                      const float seed, ptthreshold;
                      const int outgeo; const string outgrp)
{
    vector pos = point(geo, 'P', ptnum);

    vector nml = -point(geo, dirattrib, ptnum);
    nml = normalize(nml);
  
   // revnmlが有効の場合、normalを反転
    if (revnml)
        nml *= -1;

    // バリエーションの追加
    // ptthresholdより小さければreturn
    if ( float(rand(set(ptnum, ptnum/1024, seed))) < ptthreshold )
    {
        return;
    }

    // Classの取得
    int myclass = point(geo, classname, ptnum);
    string myclass_s = point(geo, classname, ptnum);

    // numconstraintで設定した数だけStrut Constraintを作成する
    for (int i = 0; i < numconstraint; i++)
    {
        vector hitpos;
        vector hituv;
        vector dir = nml;

        // レイキャストで使用する方向ベクトルにバリエーションをもたせる
        dir += (vector(rand( set(i, ptnum, ptnum/1024, seed) )) - 0.5) * jitter;

        // レイキャスト
        int hitprim = intersect(geo, pos + dir * rayoff, dir * maxlen, hitpos, hituv);

        // 交差が取得できなかった場合はcontinue
        if (hitprim < 0)
            continue;

        // Valid hit!
        // ヒットしたプリミティブのポイントを取得
        int nearpts[] = primpoints(geo, hitprim);
        if (len(nearpts) == 0)
            continue;

        int bestpt = -1;
        float bestdist = 1e23;

        // 同じClassでsrcgrpに属する
        // ptnumに最も近いポイントを見つける
        foreach (int npt; nearpts)
        {
            if (!inpointgroup(geo, srcgrp, npt))
                continue;
            int oclass = point(geo, classname, npt);
            string oclass_s = point(geo, classname, npt);
            if (oclass != myclass || oclass_s != myclass_s)
                continue;
            float dist = distance( vector(point(geo, 'P', npt)), pos);
            if (dist < bestdist)
            {
                bestdist = dist;
                bestpt = npt;
            }
        }
        
        // bestptを見つけることができなかった場合はcontinue
        if (bestpt < 0)
            continue;

        // 取得したbestptのnormalが、dirと同じ方向にあるかチェック
        if (checknml)
        {
            vector onml = point(geo, 'N', bestpt);
            if (revnml)
                onml *= -1;
            if (dot(onml, dir) < 0)
                continue;
        }

        // Connect ptnum and bestpt.
        vector opos = point(geo, 'P', bestpt);

        // Generate connecting line.
        int prim = addprim(outgeo, 'polyline', array(ptnum, bestpt));
        setprimgroup(outgeo, outgrp, prim, 1);  // outgrp (prim) <- 1
        float rlen = distance(opos, pos);
        setprimattrib(outgeo, 'restlength', prim, rlen); // restlength (prim) <- rlen
    }
}

computeTetRestMatrix

四面体のrestmatrix形状情報と体積を計算

引数名説明
geoint入力ジオメトリのインデックス
pt0intテトラヘドロンの頂ポイント0のインデックス
pt1intテトラヘドロンの頂ポイント1のインデックス
pt2intテトラヘドロンの頂ポイント2のインデックス
pt3intテトラヘドロンの頂ポイント3のインデックス
scalefloatスケーリング係数
restmatrixmatrix3計算された逆材料行列(出力パラメータ)
volumefloat計算されたテトラヘドロンの体積(出力パラメータ)
int
computeTetRestMatrix(const int geo; const int pt0, pt1, pt2, pt3; const float scale;
                    matrix3 restmatrix; float volume)
{
    // Compute inverse material matrix.
    vector p0 = point(geo, "P", pt0);
    vector p1 = point(geo, "P", pt1);
    vector p2 = point(geo, "P", pt2);
    vector p3 = point(geo, "P", pt3);

    // 列ベクトルにしたほうが扱いやすいため転置
    matrix3 M = transpose(scale * set(p0 - p3, p1 - p3, p2 - p3));

    // 行列式
    float detM = determinant(M);

    // 存在しない場合は、0
    if (detM == 0)
        return 0;
    
    // 逆行列
    restmatrix = invert(M);

    // 体積
    volume = detM / 6;

    return 1;
}

computeTetFiberRestLength

四面体の体積と圧縮方向であるmaterialWを計算

引数名説明
geointジオメトリオブジェクトのID
pt0, pt1, pt2, pt3int四面体を構成するポイントのインデックス
volumefloat四面体の体積
materialWvector材料の方向ベクトル
int
computeTetFiberRestLength(const int geo; const int pt0, pt1, pt2, pt3; float volume; vector materialW)
{
    matrix3 restm;

    // 四面体のrest matrixと体積を取得
    // 存在しない場合は、0を返す
    if (!computeTetRestMatrix(geo, pt0, pt1, pt2, pt3, 1, restm, volume))
        return 0;

    // Compute material uv
    materialW = {0, 0, 1};
    string wattrib = "materialW";

    // materialWが存在する場合
    // 各ポイントのmaterialWを加算し、正規化
    if (haspointattrib(geo, wattrib))
    {
        materialW = point(geo, wattrib, pt0);
        materialW += point(geo, wattrib, pt1);
        materialW += point(geo, wattrib, pt2);
        materialW += point(geo, wattrib, pt3);
        materialW = normalize(materialW);
    }

    // Equivalent to mat3vecmul(Dm^-1, w) in OpenCL.
    materialW = transpose(restm) * materialW;
    return 1;
}

createTetFiberConstraint

指定された条件に基づいて、Tet Fiber拘束を作成

引数名説明
geoint入力ジオメトリのインデックス
ptnumint処理対象のポイント番号
srcgrpstring入力ジオメトリのポイントグループ名
outgeoint出力ジオメトリのインデックス
outgrpstring出力ジオメトリのプリミティブグループ名
void
createTetFiberConstraint(const int geo; const int ptnum; const string srcgrp;
                        const int outgeo; const string outgrp)
{
    int prims[] = pointprims(geo, ptnum);
    foreach(int prim; prims)
    {
        // Process tets where this point is minimum point number,
        // and all points are in src group.
        // Tetrahedronでない場合はcontinue
        if(primintrinsic(geo, "typeid", prim) != 21) // Tetrahedron
            continue;
        int pts[] = primpoints(geo, prim);

        // プリミティブが4つのポイントを持ちsrcgrp属していなければcontinue
        if (len(pts) != 4 ||
            ptnum != min(pts) ||
            !inpointgroup(geo, srcgrp, pts[1]) ||
            !inpointgroup(geo, srcgrp, pts[2]) ||
            !inpointgroup(geo, srcgrp, pts[3]))
            continue;

        // Compute inverse material matrix.
        // 体積とmaterialWを計算
        vector materialW;
        float volume;
        if (!computeTetFiberRestLength(geo, pts[0], pts[1], pts[2], pts[3], volume, materialW))
            continue;

        int cprim = addprim(outgeo, "tet", pts);

        // restlength (prim) <- vol
        setprimattrib(outgeo, "restlength", cprim, volume);
        
        // restvector (prim) <- vector4(materialW)
        setprimattrib(outgeo, "restvector", cprim, vector4(materialW));

        // outgrp (prim) <- 1
        setprimgroup(outgeo, outgrp, cprim, 1);
    }
}

computeTriRestMatrix

三角形のrestmatrix(形状情報)と面積を計算

引数名説明
geoint入力ジオメトリのインデックス
pt0, pt1, pt2int三角形の頂ポイントのポイント番号
scalefloatスケーリング係数
restmatrixmatrix2計算されたrest状態における行列(出力)
areafloat計算された三角形の面積(出力)
int
computeTriRestMatrix(const int geo; const int pt0, pt1, pt2; const float scale;
                    matrix2 restmatrix; float area)
{
    vector p0 = point(geo, "P", pt0);
    vector p1 = point(geo, "P", pt1);
    vector p2 = point(geo, "P", pt2);

    // Xform from world to 2-d triangle space.
    // ワールド空間から三角形空間への変換行列を得る
    matrix3 xform = fromTriangleSpaceXform(p0, p1, p2);  // 直交行列
    xform = transpose(xform);

    // 各頂ポイント座標をXY平面へ変換し次元を落とす
    vector2 P0 = (vector2)(p0 * xform);
    vector2 P1 = (vector2)(p1 * xform);
    vector2 P2 = (vector2)(p2 * xform);

    // 転置
    matrix2 M = transpose(scale * set(P0 - P2, P1 - P2));
    
    // 行列式
    float detM = determinant(M);
    
    // 存在しない場合は0
    if (detM == 0)
        return 0;

    // 逆行列
    restmatrix = invert(M);

    // 面積
    area = abs(detM / 2);

    return 1;
}

polardecomp2d

2次元行列の極分解を計算

引数名説明
Amatrix2入力となる2次元行列
// Closed form 2d polar decomposition.
// See http://www.cs.cornell.edu/courses/cs4620/2014fa/lectures/polarnotes.pdf
matrix2
polardecomp2d(matrix2 A)
{
    vector2 m = set(A.xx + A.yy, A.yx - A.xy);
    m = normalize(m);
    return set(m.x, -m.y, m.y, m.x);
}

computeTriAreaRestLength

指定されたスケーリング係数に基いて三角形の面積を計算

引数名説明
geoint入力ジオメトリのインデックス
pt0, pt1, pt2int三角形の頂ポイントのポイント番号
scalefloat三角形のスケーリング係数
// Scales a triangle and returns its area.
float
computeTriAreaRestLength(const int geo; const int pt0, pt1, pt2; const float scale)
{
    vector p0 = point(geo, "P", pt0);
    vector p1 = point(geo, "P", pt1);
    vector p2 = point(geo, "P", pt2);
    vector e0 = scale * (p1 - p0);
    vector e1 = scale * (p2 - p0);
    vector e2 = cross(e1, e0); // 外積
    float area = length(e2) / 2;  // 面積計算
    return area;
}

createTriStretchConstraint

指定された条件に基づいて、Triangle Stretch拘束を作成

引数名説明
geoint入力ジオメトリのインデックス
ptnumint処理対象のポイント番号
srcgrpstring入力ジオメトリのポイントグループ名
typestring拘束タイプ(ストレッチ)
restscalefloatrest状態におけるスケーリング係数
outgeoint出力ジオメトリのインデックス
outgrpstring出力ジオメトリのプリミティブグループ名

void
createTriStretchConstraint(const int geo; const int ptnum; const string srcgrp, type;
                          const float restscale;
                          const int outgeo; const string outgrp)
{
    // プリミティブの取得
    int prims[] = pointprims(geo, ptnum)

    foreach(int prim; prims)
    {
        // Process triangles where this point is minimum point number,
        // and all points are in src group.
        // Polyのみ
        if(primintrinsic(geo, "typeid", prim) != 1)
            continue;
        
        // ポイント取得
        int pts[] = primpoints(geo, prim);

        // 頂ポイントが3つ、ptnumが最小の頂ポイント番号で
        // すべての頂ポイントがsrcgrpに属していること
        if (len(pts) != 3 ||
            ptnum != min(pts) ||
            !inpointgroup(geo, srcgrp, pts[1]) ||
            !inpointgroup(geo, srcgrp, pts[2]))
            continue;

        // restmatrixと面積の計算
        matrix2 restmatrix;
        float area;
        if (!computeTriRestMatrix(geo, pts[0], pts[1], pts[2], restscale, restmatrix, area))
            continue;

        int cprim = addprim(outgeo, "poly", pts);
        setprimattrib(outgeo, "restlength", cprim, area);  // restlength (prim) <- area

        // Store 2x2 matrix in restvector.
        vector4 restvec = set(restmatrix.xx, restmatrix.xy,
                              restmatrix.yx, restmatrix.yy);

        // restvector (prim) <- restvec
        setprimattrib(outgeo, "restvector", cprim, restvec);
        setprimattrib(outgeo, "type", cprim, type);  // type (prim) <- type
        setprimgroup(outgeo, outgrp, cprim, 1);  // outgrp (prim) <- 1
    }
}

createTetStretchConstraint

指定された条件に基づいて、Tetrahedral Stretch拘束を作成

引数名説明
geoint入力ジオメトリのインデックス
ptnumint処理対象のポイント番号
srcgrpstring入力ジオメトリのポイントグループ名
typestring拘束タイプ(ストレッチ)
restscalefloatrest状態におけるスケーリング係数
outgeoint出力ジオメトリのインデックス
outgrpstring出力ジオメトリのプリミティブグループ名
void
createTetStretchConstraint(const int geo; const int ptnum; const string srcgrp, type;
                          float restscale;
                          const int outgeo; const string outgrp)
{
    int prims[] = pointprims(geo, ptnum);
    foreach(int prim; prims)
    {
        // Process tets where this point is minimum point number,
        // and all points are in src group.
        // Tetrahedronのみ
        if(primintrinsic(geo, "typeid", prim) != 21)
            continue;

          
        int pts[] = primpoints(geo, prim);
        
        // 頂ポイントが4つで、ptnumが最小のインデックスであり、
        // 全ての頂ポイントがsrcgrpに含まれている
        if (len(pts) != 4 ||
            ptnum != min(pts) ||
            !inpointgroup(geo, srcgrp, pts[1]) ||
            !inpointgroup(geo, srcgrp, pts[2]) ||
            !inpointgroup(geo, srcgrp, pts[3]))
            continue;

        // restmatrixと四面体の体積を計算
        matrix3 restmatrix;
        float volume;
        if (!computeTetRestMatrix(geo, pts[0], pts[1], pts[2], pts[3], restscale, restmatrix, volume))
            continue;

        int cprim = addprim(outgeo, "tet", pts);

        // restlength (prim) <- volume
        setprimattrib(outgeo, "restlength", cprim, volume);
        // restmatrix (prim) <- restmatrix
        setprimattrib(outgeo, "restmatrix", cprim, restmatrix);
        // restvector (prim) <- vector4({0, 0, 0, 1}
        setprimattrib(outgeo, "restvector", cprim, vector4({0, 0, 0, 1}));
        // type (prim) <- type
        setprimattrib(outgeo, "type", cprim, type);
        // outgrp (prim) <- 1
        setprimgroup(outgeo, outgrp, cprim, 1);
    }
}

orientedRestDifference

ポイント間におけるオリエンテーションの差を計算

引数名説明
geoint入力ジオメトリのインデックス
pts[]int arrayポイントインデックスの配列
typestring拘束タイプ("pinorient"または"bendtwist")
restvectorvector4rest状態におけるベクター
aadiffvector関数内で計算されたオリエンテーション差分の角軸(angle-axis)表現(参照渡しパラメータ)
int
orientedRestDifference(const int geo, pts[]; const string type;
                      const vector4 restvector; vector aadiff)
{
    int isorient = 0;
    vector4 curorient; // current orientation
    if (type == "pinorient")
    {
        curorient = point(geo, "orient", pts[0]);
        isorient = 1;
    }
    else if (type == "bendtwist")
    {
        // 2つのポイント間の曲げとねじれを計算
        curorient = computeBendTwistRestVector(geo, pts[0], pts[1]);
        isorient = 1;
    }

    if (isorient)
    {
        // restvectorの共役クォータニオン
        vector4 restconj = restvector * {-1, -1, -1, 1};
        // Angle/axis representation of orientation difference.
        // orientの差分を角度/軸のベクトルとして格納
        aadiff = qconvert(qmultiply(restconj, curorient));
    }
    return isorient;
}

logscaleStiffness

ログスケールに変換

引数名説明
kfloat対数スケール変換の係数
stiffnessfloat変換対象の剛性値
float
logscaleStiffness(const float k, stiffness)
{
    // Restrict to non-negative, finite values.
    return clamp(exp(k * log(stiffness + 1)) - 1, 0, 1e37);
}

invlogscaleStiffness

logscaleStiffness の逆変換

引数名説明
xfloat対数スケールで変換された剛性値
stiffnessfloat元の剛性値
// Returns the value that can be passed to logscaleStiffness to
// get x given the same stiffness.
float
invlogscaleStiffness(const float x, stiffness)
{
    // Restrict to non-negative, finite values.
    return clamp(log(x + 1) / log(stiffness + 1), 0, 1e37);
}

updateRestVectorOrient

角度/軸の差分ベクトルをもとに restvector を更新し、その角度を返す

引数名説明
inamountfloat更新されるオリエンテーションの量(度数または比率で指定)
isratiointamountが比率で指定されている場合は1、度数で指定されている場合は0
aadiffvectorオリエンテーションの差を表す角度/軸表現
restvectorvector4現在のオリエンテーション情報を格納した四元数
// Increment restvector by amount towards current deformation in
// axis/angle space.
// aadiff is angle/axis representation of orientation difference.
// Returns the degrees the orientation was updated by.
float
updateRestVectorOrient(const float inamount; const int isratio;
                      const vector aadiff; vector4 restvector)
{
    float amount = inamount;
    // Difference in degrees.
    // 現在の方向と目標との差
    float degdiff = degrees(length(aadiff));

    // Convert to ratio if amount already in degrees.
    // 比率に変換
    if (!isratio)
        amount /= degdiff;

    // Increment towards current deformation in axis/angle space.
    // aadiff is angle/axis representation of orientation difference.
    // 角度/軸のベクトルに変換
    vector rest = qconvert(restvector);

    // aadiff方向にamountの数だけ動かす
    rest += clamp(amount, 0, 1) * aadiff;

    // クォータニオンに変換
    restvector = quaternion(rest);

    // 角度の更新
    return amount * degdiff;
}

squaredNorm2

2x2 行列における Frobenius ノルムの二乗を返す

引数名説明
amatrix22x2の行列
float
squaredNorm2(const matrix2 a)
{
    // Below conversion doesn't exist for some reason.
    // vector2 rows[] = set(a);
    vector2 rows[];
    resize(rows, 2);
    rows[0] = set(a.xx, a.xy);
    rows[1] = set(a.yx, a.yy);
    return dot(rows[0], rows[0]) + dot(rows[1], rows[1]);
}

squaredNorm3

3x3 行列における Frobenius ノルムの二乗を返す

引数名説明
amatrix33x3の行列
float
squaredNorm3(const matrix3 a)
{
    vector rows[] = set(a);
    return dot(rows[0], rows[0]) + dot(rows[1], rows[1]) + dot(rows[2], rows[2]);
}

updateRestMatrix2

差分ベクトルをもとにrestvectorrestlengthを更新しノルムの差を返す

引数名説明
inamountfloat更新量(長さ単位または比率)
isratioint更新量が比率であるかどうかを示すフラグ(0: 長さ単位、1: 比率)
vecdiffvector4差分ベクトル
restlengthfloat更新するrestlength
restvectorvector42x2のrestmatrixを格納するベクトル
// Update the 2x2 restmatrix stored in restvector by amount,
// given the difference vector4 supplied.
float
updateRestMatrix2(const float inamount; const int isratio; const vector4 vecdiff;
                  float restlength; vector4 restvector)
{
    // 2X2
    matrix2 D_m_inv = set(restvector.x, restvector.y, restvector.z, restvector.w);
    // 逆行列
    matrix2 D_m = invert(D_m_inv);

    float amount = inamount;
    float sqrnorm = squaredNorm2(D_m);  // ノルム

    // Convert to ratio if in length units.
    // Use squared norm for "length"
    // 比率に変換
    if (!isratio)
        amount /= sqrnorm;
    amount = clamp(amount, 0, 1);

    // restvector holds the inverse of the material space matrix, so we have to invert before
    // and after updating.
    matrix2 matdiff = set(vecdiff.x, vecdiff.y, vecdiff.z, vecdiff.w);
    D_m += amount * matdiff; // 更新

    // restvectorの形式に合わせるために逆行列へ変換
    D_m_inv = invert(D_m);

    // Store inverse of D_m in restvector and area in restlength.
    restvector = set(D_m_inv.xx, D_m_inv.xy, D_m_inv.yx, D_m_inv.yy);
    restlength = abs(determinant(D_m) / 2); // areaの計算

    // Return change in squared norm
    // 二乗ノルムの差分
    return abs(squaredNorm2(D_m) - sqrnorm);
}

updateRestMatrix

差分ベクトルをもとにrestmatrixrestlengthを更新しノルムの差を返す

引数名説明
inamountconst float更新量(長さ単位または比率)
isratioconst int更新量が比率であるかどうかを示すフラグ(0: 長さ単位、1: 比率)
matdiffconst matrix3マトリックスの差
restlengthfloatrest状態における長さを格納する変数
restmatrixmatrix3rest状態におけるマトリックスを格納する変数
// Update the restmatrix by amount given the difference matrix
// supplied.
float
updateRestMatrix(const float inamount; const int isratio; const matrix3 matdiff;
                float restlength; matrix3 restmatrix)
{
    float amount = inamount;
    
    // 3X3
    matrix3 D_m = invert(restmatrix);
    float sqrnorm = squaredNorm3(D_m);  // ノルムの二乗

    // Convert to ratio if in length units.
    // Use squared norm for "length"
    // 比率に変換
    if (!isratio)
        amount /= sqrnorm;
    amount = clamp(amount, 0, 1);

    // restmatrix holds the inverse of the material space matrix, so we have to invert before
    // and after updating.
    D_m += amount * matdiff;  // 更新

    // Store inverse of D_m in restmatrix and volume in restlength.
    // restmatrixの形式に合わせるために逆行列へ変換
    restmatrix = invert(D_m);
    restlength = determinant(D_m) / 6;  // volumeの計算

    // Return change in squared norm
    // 二乗ノルムの差分
    return abs(squaredNorm3(D_m) - sqrnorm);
}

computeRestVectorDifference

四面体または三角形の current-rest 間におけるベクトル差分を計算

引数名説明
geoconst intジオメトリのインデックス
pts[]int array頂ポイントのインデックスの配列
typeconst stringシミュレーションタイプ(tetfiber, tetfibernorm, triarap, triarapnl, triarapnorm)
restvectorconst vector4rest状態におけるベクトル
vecdiffvector4rest状態におけるベクトルと現在のベクトルの差を格納する変数
int
computeRestVectorDifference(const int geo, pts[];  const string type; const vector4 restvector;
                            vector4 vecdiff)
{
    // tetfiber or tetfibernorm
    // triarap or triarapnl or triarapnorm
    if (!isTetFiber(type) && !isTriARAP(type))
        return 0;

    vecdiff = 0;

    // tetfiber or tetfibernorm
    if (isTetFiber(type))
    {
        float volume;
        vector curvector, rv = vector(restvector);

        // volume と curvector <- materialW の計算
        if (computeTetFiberRestLength(geo, pts[0], pts[1], pts[2], pts[3], volume, curvector))
        {
            // ベクトルの差分
            vecdiff = vector4(curvector - rv);
            vecdiff.w = 0;
        }
    }
    else if (isTriARAP(type)) // triarap or triarapnl or triarapnorm
    {
        // We need to compute the difference in material coordinates, so we get the polar decomposition
        // of the deformation gradient and transform the new coordinates into material space.
        
        matrix2 D_s_inv, D_m_inv = set(restvector.x, restvector.y, restvector.z, restvector.w);
        
        float area;
        // Compute the current (inverse) spatial matrix.  Bail out if degenerate.
        // 2X2 current matrix と area の計算
        if (!computeTriRestMatrix(geo, pts[0], pts[1], pts[2], 1, D_s_inv, area))
            return 1;
        
        // 逆行列に変換
        matrix2 D_s = invert(D_s_inv);

        // Deformation gradient.
        matrix2 F = D_s * D_m_inv; // 変形勾配
        matrix2 R = polardecomp2d(F);  // 回転
        D_s = transpose(R) * D_s;  // 更新

        // Difference in material coordinates.
        // 差分計算
        matrix2 mdiff = D_s - invert(D_m_inv);
        vecdiff = set(mdiff.xx, mdiff.xy, mdiff.yx, mdiff.yy);
    }
    return 1;
}

computeRestMatrixDifference

四面体の current-rest 間における matrix 差分を計算

引数名説明
geointジオメトリのインデックス
pts[]int[]四面体を形成する4つのポイントのインデックス配列
typestring拘束タイプ
restmatrixmatrix3rest行列です
matdiffmatrix3rest行列と現在の変形に対する差分行列
int
computeRestMatrixDifference(const int geo, pts[];  const string type; const matrix3 restmatrix;
                            matrix3 matdiff)
{
    // tetarap or tetarapnl or tetarapnorm
    // tetarapvol or tetaarapnnlvol or tetarapnormvol
    if (!isTetARAP(type))
        return 0;

    matdiff = 0;

    // We need to compute the difference in material coordinates, so we get the polar decomposition
    // of the deformation gradient and transform the new coordinates into material space.
    matrix3 D_s_inv;
    float volume;

    // Compute the current (inverse) spatial matrix.  Bail out if degenerate.
    // 四面体における matrix と volume を計算 
    if (!computeTetRestMatrix(geo, pts[0], pts[1], pts[2], pts[3], 1, D_s_inv, volume))
        return 1;

    // 逆行列に変換
    matrix3 D_s = invert(D_s_inv);

    // Deformation gradient.
    matrix3 F = D_s * restmatrix;  // 変形勾配
    matrix3 R = polardecomp(F);  // 回転

    D_s = transpose(R) * D_s;  // 転置し、matrixを更新

    // Difference in material coordinates.
    // 差分計算
    matdiff = D_s - invert(restmatrix);

    return 1;
}

plasticDeformation

塑性変形における塑性流動量を計算し、拘束の剛性値を更新

引数名説明
geointジオメトリのインデックス
pts[]int[]四面体を形成する4つのポイントのインデックス配列
intypestring拘束タイプ
difffloat現在の長さからrest長での符号付き距離
plasticratefloat塑性流動速度
plasticthresholdfloat塑性変形が発生する閾値
plastichardeningfloat塑性変形による硬化係数
dtfloat時間ステップ
restlengthfloatrest状態における長さ
restvectorvector4rest状態におけるベクトル
restmatrixmatrix3rest状態における行列
stiffnessfloat剛性値
// Diff should be (signed) distance from curlength to restlength.
// Returns amount of plastic flow, for angular constraints in degrees.
float
plasticDeformation(const int geo, pts[];  const string intype; const float diff;
                  const float plasticrate, plasticthreshold, plastichardening, dt;
                  float restlength; vector4 restvector; matrix3 restmatrix;
                  float stiffness)
{
    float threshold = plasticthreshold;

    // Use aliased constraint type.
    string type = constraintAlias(intype);

    // Negative stretch value indicates ratio of current restlength;
    // thresholdの値が負の場合、restlengthに対する比率とする
    if (threshold < 0)
        threshold = -threshold * restlength;

    // Nothing to do if not past threshold.
    // 閾値以下であれば何もしない
    if (abs(diff) <= threshold)
        return 0;

    vector aadiff;
    vector4 vecdiff;
    matrix3 matdiff;

    // This plasticity model roughly matches the wire solver.
    float u = exp(-plasticrate * dt);  // 0-1
    float v = 1 - u;
    float flow = 0;

    // Need to recompute expensive difference for some constraint types,
    // but only once we already know we're past the plastic threshold.
    // 各Constraintタイプに対して差分を計算し restvector や restmatrix を更新
    if (orientedRestDifference(geo, pts, type, restvector, aadiff))
    {
        // 塑性流動量の更新
        flow = updateRestVectorOrient(v, 1, aadiff, restvector);
    }
    else if (computeRestVectorDifference(geo, pts, type, restvector, vecdiff))
    {
        // 塑性流動量の更新
        flow = updateRestMatrix2(v, 1, vecdiff, restlength, restvector);
    }
    else if (computeRestMatrixDifference(geo, pts, type, restmatrix, matdiff))
    {
        // We don't want to update restlength (volume) under plastic deformation
        // for tetarap constraints, so they can still preserve their original volume
        // stored in restlength.
        // 塑性変形において、四面体の体積が更新されることは望ましくないので、
        // 一時的にtemprlとして格納しておく
        float temprl = restlength;

        // 塑性流動量の更新
        flow = updateRestMatrix(v, 1, matdiff, temprl, restmatrix);
    }
    else
    {
        // 塑性流動量の更新
        flow = v * diff;
        // 累算
        restlength += flow;
    }

    // Update stiffness from hardening.
    // 剛性値の更新
    float k = u + v * plastichardening;
    float s = logscaleStiffness(k, stiffness);

    // Ensure we stay finite for stiffness.
    // 有限値に制限
    stiffness = select(isfinite(s), s, stiffness);

    // 塑性流動量
    return flow;
}

getSourcePoints

拘束タイプがdistance / stretchshear / weld / ptprimであったときに、最初の配列要素を返す

引数名説明
intypestring拘束タイプ
pts[]int[]拘束に関連するポイントのインデックス配列
int []
getSourcePoints(const string intype; const int pts[])
{
    string type = constraintAlias(intype);

    // distance or stretchshear or weld or ptprim
    if (type == "distance" || type == "stretchshear" || type == "weld" || type == "ptprim")
    {
        return pts[:1]; // 最初の要素
    }
    return pts;
}

getTargetPoints

拘束タイプがdistance / stretchshear / weld / ptprimであったときに、最初以外の配列要素を返す

引数名説明
intypestring拘束タイプ
pts[]int[]拘束に関連するポイントのインデックス配列
int []
getTargetPoints(const string intype; const int pts[])
{
    string type = constraintAlias(intype);

    // distance or stretchshear or weld or ptprim
    if (type == "distance" || type == "stretchshear" || type == "weld" || type == "ptprim")
    {
        return pts[1:]; // 最初以外の要素
    }
    return {};  // 空
}

accumScaleValues

アトリビュートを指定されたモード(最小・最大・平均・乗算)で累積させる

引数名説明
typestring拘束タイプ
ptgeoint入力ジオメトリのインデックス
inpts[]int[]拘束に関連するポイントのインデックス配列
primgeostringプリミティブジオメトリを識別する文字列
targetprimintターゲットプリミティブのインデックス
uvvectorプリミティブのUV座標
attrstringスケールに影響する属性名
valscalefloatスカラー乗数
scalemodestringスケーリングを計算するためのモードを示す文字列で、"value"、"attribvalue"、または "attrib"のいずれか
promotionstringプロモーションモードを示す文字列で、"source"、"target"、"min"、"mult"、または "mean"のいずれか
// Return a scaling from accumulating attribute values and/or
// scalar multiplier, depending on mode and promotion.

// scalemode: value, attribvalue, attrib
// promotion: source, target, min, mult, mean

float
accumScaleValues(const string type;
                const int ptgeo; const int inpts[];
                const string primgeo; const int targetprim; const vector uv;
                const string attr;
                const float valscale; const string scalemode, promotion)
{
    float attrscale = 0;
    int div = 0;

    if (scalemode == "attrib" || scalemode == "attribvalue")
    {
        int pts[] = inpts;

        if (promotion == "source")
            pts = getSourcePoints(type, inpts); // 最初の配列要素

        if (promotion == "target")
            pts = getTargetPoints(type, inpts); // 最初以外の配列要素

        if (promotion == "min")
            attrscale = 1e23;

        if (promotion == "mult")
            attrscale = 1;

        // Accumulate point parts.
        // ポイント
        if (haspointattrib(ptgeo, attr))
        {
            foreach(int pt; pts)
            {
                // アトリビュート取得
                float ptval = point(ptgeo, attr, pt);
        
                // 平均値 or ソース or ターゲット
                if (promotion == "mean" || promotion == "source" || promotion == "target")
                {
                    // 加算
                    attrscale += ptval;
                    // インクリメント
                    div++;
                }
                else if (promotion == "max") // 最大値
                {
                    attrscale = max(attrscale, ptval);
                    div = 1;
                }
                else if (promotion == "min")  // 最小値
                {
                    attrscale = min(attrscale, ptval);
                    div = 1;
                }
                else if (promotion == "mult")  // 乗算値
                {
                    attrscale *= ptval;
                    div = 1;
                }
            }
        }

        // Accumulate primitive part.  The primuv function will use prim, vertex, or point attribs.
        // prim can never be a source.
        // プリミティブ
        if (primgeo != "" && targetprim >= 0 && promotion != "source" &&
            (hasprimattrib(primgeo, attr) || hasvertexattrib(primgeo, attr) || haspointattrib(primgeo, attr)))
        {
            // アトリビュート取得
            float primval = primuv(primgeo, attr, targetprim, uv);

            // 平均値 or ターゲット
            if (promotion == "mean" || promotion == "target")
            {
                // 加算
                attrscale += primval;
                // インクリメント
                div++;
            }
            else if (promotion == "max") // 最大値
            {
                attrscale = max(attrscale, primval);
                div = 1;
            }
            else if (promotion == "min") // 最小値
            {
                attrscale = min(attrscale, primval);
                div = 1;
            }
            else if (promotion == "mult") // 乗算値
            {
                attrscale *= primval;
                div = 1;
            }
        }
    }

    float scale = 1;

    // mean or source or targetの場合は、平均値が出る
    if (div > 0)
        scale *= attrscale / div;

    // scalemode が value の場合は、scale = valscale
    if (scalemode == "value" || scalemode == "attribvalue")
        scale *= valscale;

    return scale;
}

falseColor

入力値を指定した範囲に基づいて false を示すための RGB 値へ変換

引数名説明
valfloatカラーマッピングを計算するための入力値
minvalfloat値の範囲の最小値
maxvalfloat値の範囲の最大値
vector
falseColor(const float val, minval, maxval)
{
    return hsvtorgb(0.7 * (1 - fit(val, minval, maxval, 0, 1)), 1, 1);
}

weldTarget

接合の目標となるポイント番号の取得

引数名説明
geointジオメトリのインデックス
ptnumintジオメトリ内のポイント番号
int
weldTarget(const int geo, ptnum)
{
    // ポイントがweldを持っている
    if (haspointattrib(geo, "weld"))
    {
        int weld = point(geo, "weld", ptnum);
      
        // weldするターゲットポイントの取得
        if (weld >= 0)
            return idtopoint(geo, weld);  
    }

    // weldを持っていない or weld == -1
    return ptnum;
}

computeStress

物体の変形や歪みによって生じる拘束に対するstress(応力)を計算

引数名説明
typestring拘束タイプ
Linvector力を表すベクトル
dtfloat時間ステップ
normalizeint正規化を行うかどうかを指定するフラグ(0または1)

compute_stress(Vellum Solver DOP)

// run over: primitives

#include <pbd_constraints.h>

f@stress = computeStress(s@type, v@L, @TimeInc, chi("normalize"));
float computeStress(const string type; const vector Lin;
                    const float dt; const int normalize)
{
    // ラグランジュ
    vector L = Lin;

    // We want to ignore the volume component for tetARAP/volume constraints.
    // tetarapvol, tetaarapnnlvol, tetarapnormvolの場合は、
    // 体積変化に対する影響を無視
    L.z = select(isTetARAPVol(type), 0, Lin.z);

    // 正規化しない場合
    if (!normalize)
        return length(L);

    // nonlinear ARAP divides by just dt. Although it doesn't work that well,
    // it's still better than dt^2
    // 正規化
    // 非線形ARAP(triarapnl、tetarapnl、tetarapnlvol)の場合は、dtを用いる
    float scale = 1.0 / select(isNonLinearARAP(type), dt, dt * dt);

    return length(L) * scale;
}

maxConstraintStress

拘束ジオメトリに含まれるstress(応力)の最大値を返す

引数名説明
ptgeointジオメトリのインデックス
congeoint拘束ジオメトリのインデックス
ptnumintストレスを計算するポイント番号
typesstring[]計算に使用する拘束タイプの配列
float
maxConstraintStress(const int ptgeo, congeo, ptnum; const string types[])
{
    // Use the weld target if any.
    // weldが存在していた場合、ターゲットのポイント番号を返す
    int pt = weldTarget(ptgeo, ptnum);

    // Iterate over all constraint primitives connected
    // to each point and find the max "stress".
    int prims[] = pointprims(congeo, pt);
    float stress = 0;

    foreach(int prim; prims)
    {
        // 拘束タイプ
        string type = prim(congeo, "type", prim);

        // types配列に含まれていない場合は、continue
        if (find(types, type) < 0)
            continue;

        // 応力の最大値
        stress = max(stress, prim(congeo, "stress", prim));
    }

    return stress;
}

computeRestLengthDifference

与えられた拘束タイプに基づいて、current-rest 間における長さや角度の差分またはノルムを計算

引数名説明
geoint入力ジオメトリのインデックス
ptsint[]関連するポイントのインデックスを含む配列
intypestring拘束タイプ
restlengthfloat拘束のrest状態における長さ
restvectorvector4拘束のrest状態における4次元ベクトル
restdirvector拘束のrest状態におけるベクトル方向
targetpathstringターゲットジオメトリへのパス
targetprimintターゲットプリミティブのインデックス
restmatrixmatrix3rest状態における変換行列
float
computeRestLengthDifference(const int geo, pts[];  const string intype;
                            const float restlength; const vector4 restvector;
                            const vector restdir; const string targetpath; const int targetprim;
                            const matrix3 restmatrix)
{
    float curlength;  // current length
    vector4 curorient;  // current orient

    // Use aliased constraint type.
    string type = constraintAlias(intype);

    // 各拘束タイプごとに関数を用いて長さを計算
    if (type == "pin")
    {
        curlength = distance(point(geo, "P", pts[0]), vector(restvector));
    }
    else if (type == "distance" || type == "stretchshear")
    {
        curlength = computeDistanceRestLength(geo, pts[0], pts[1]);
    }
    else if (type == "distanceline")
    {
        curlength = computeDistanceLineRestLength(geo, pts[0], vector(restvector), restdir, targetpath, targetprim);
    }
    else if (type == "pressure")
    {
        curlength = computePressureRestLength(geo, pts, "volume");
    }
    else if (type == "tetvolume")
    {
        curlength = computeTetVolumeRestLength(geo, pts[0], pts[1], pts[2], pts[3]);
    }
    else if (type == "bend")
    {
        if (!computeDihedralRestLength(geo, pts[0], pts[1], pts[2], pts[3], curlength))
            return 0;
    }
    else if (type == "angle")
    {
        curlength = computeAngleRestLength(geo, pts[0], pts[1], pts[2]);
    }
    else if (type == "trianglebend")
    {
        curlength = computeTriangleBendRestLength(geo, pts[0], pts[1], pts[2]);
    }
    else if (type == "ptprim")
    {
        curlength = computePointPrimRestLength(geo, pts[0], pts[1:], restvector);
    }

    // Use axis/angle orientation difference if exists.
    // 回転角度の差分
    vector aadiff;
    if (orientedRestDifference(geo, pts, type, restvector, aadiff))
        return degrees(length(aadiff));

    // ベクトル差分の2乗ノルム
    vector4 vecdiff;
    if (computeRestVectorDifference(geo, pts, type, restvector, vecdiff))
        return squaredNorm2(set(vecdiff.x, vecdiff.y, vecdiff.z, vecdiff.w));

    // 3x3行列の2乗ノルム
    matrix3 matdiff;
    if (computeRestMatrixDifference(geo, pts, type, restmatrix, matdiff))
        return squaredNorm3(matdiff);

    // 差分
    float diff = curlength - restlength;

    return diff;
}

updateFromRest

与えられた拘束タイプに基づいて、restlengthrestvectorなどの値を更新

引数名説明
geoint入力ジオメトリのインデックス
ptsint[]関連するポイントのインデックスを含む配列
typestring拘束タイプ
restlengthfloat拘束のrest状態における長さ
restvectorvector4拘束のrest状態における4次元ベクトル
restdirvector拘束のrest状態におけるベクトル方向
targetpathstringターゲットジオメトリへのパス
targetprimintターゲットプリミティブのインデックス
restmatrixmatrix3拘束のrest状態における変換行列
indropofffloat剛性の減衰を制御するドロップオフ値
stiffnessorigfloatオリジナルの剛性値
stiffnessminfloat剛性の最小値この値は、剛性が減少する際の下限として使用される

// Update restlength or restvector from the current rest state
// as depicted in the point positions in geo.
// Amount can be a 0-1 ratio or a unit amount.
void
updateFromRest(const int geo, pts[]; const string intype;
              const float inamount; const int isratio;
              float restlength; vector4 restvector; matrix3 restmatrix;
                const vector restdir; const string targetpath; const int targetprim)
{
    float amount = inamount;

    // Check if nothing to do.
    if (isratio && amount <= 0)
        return;

    // Use aliased constraint type.
    string type = constraintAlias(intype);

    float diff = 0;
    // Use axis/angle orientation difference if exists.
    vector aadiff = 0;
    vector4 vecdiff = 0;
    matrix3 matdiff = 0;

    // それぞれの拘束タイプごとに関数を用いて計算し、
    // restvectorやrestlengthを更新

    // pinorient / bendtwist
    if (orientedRestDifference(geo, pts, type, restvector, aadiff))
    {
        // 角度/軸の方向ベクトル
        updateRestVectorOrient(inamount, isratio, aadiff, restvector);
    }
    // tetfiber / tetfibernorm / triarap / triarapnl / triarapnorm
    else if (computeRestVectorDifference(geo, pts, type, restvector, vecdiff))
    {
        // triarap / triarapnl / triarapnorm
        if (isTriARAP(type))
        {
            // クォータニオン
            updateRestMatrix2(inamount, isratio, vecdiff, restlength, restvector);
        }
        else
        {
            // Convert to ratio if in length units.
            // 比率に変換
            if (!isratio)
                amount /= length(vecdiff);

            // 0-1
            amount = clamp(amount, 0, 1);
            
            // restvectorとrestlengthをamountだけ乗算し加算
            restvector += amount * vecdiff;
            restlength += amount * diff;
        }
    }
    // tetarap*
    else if (computeRestMatrixDifference(geo, pts, type, restmatrix, matdiff))
    {
        updateRestMatrix(inamount, isratio, matdiff, restlength, restmatrix);
    }
    else
    {
        // 長さの差分
        diff = computeRestLengthDifference(geo, pts, type, restlength, restvector,
                                          restdir, targetpath, targetprim, restmatrix);
        // Convert to ratio if in length units.
        // 比率に変換
        if (!isratio)
            amount /= abs(diff);

        // amountだけ乗算し加算
        restlength += clamp(amount, 0, 1) * diff;
    }
}

computeStiffnessDropoff

Stiffness Dropoff を考慮した場合の剛性値を計算

引数名説明
geointジオメトリのインデックス
ptsint[]関連するポイントのインデックスを含む配列
typestring拘束タイプ
restlengthfloat拘束のrest状態における長さ
restvectorvector4拘束のrest状態における次元ベクトル
restdirvector拘束のrest状態におけるベクトル方向
targetpathstringターゲットジオメトリへのパス
targetprimintターゲットプリミティブのインデックス
restmatrixmatrix3拘束のrest状態における変換行列
indropofffloat剛性の減衰を制御するドロップオフ値
stiffnessorigfloatオリジナルの剛性値
stiffnessminfloat剛性の最小値この値は、剛性が減少する際の下限として使用される
float
computeStiffnessDropoff(const int geo, pts[]; const string type;
                        const float restlength; const vector4 restvector;
                        const vector restdir; const string targetpath; const int targetprim;
                        const matrix3 restmatrix;
                        const float indropoff; const float stiffnessorig; const float stiffnessmin)
{
    // Nothing to do for no dropoff.
    // indropoffが0の場合は、stiffnessorigを返す
    float dropoff = abs(indropoff);
    if (dropoff == 0)
        return stiffnessorig;

    // 差分計算
    float diff = computeRestLengthDifference(geo, pts, type, restlength, restvector,
                                            restdir, targetpath, targetprim, restmatrix);
    diff = abs(diff);

    float k = 0;

    // If we have a minimum desired stiffness, use its inverse as the lower bound.
    // stiffnessminが設定されている場合は、下限値として使用する
    if (stiffnessmin > 0)
        k = invlogscaleStiffness(stiffnessmin, stiffnessorig);

    float scale;
    
    // If dropoff is negative, decrease stiffness towards dropoff, else increase.
    // indropoffが負の場合は、stiffnessを減少させる
    if (indropoff < 0)
        scale = fit(diff, 0, dropoff, 1, k);
    else
        scale = fit(diff, 0, dropoff, k, 1);

    // ログスケールに変換
    return logscaleStiffness(scale, stiffnessorig);
}

restMetric

塑性変形などの可視化に用いるための rest 状態におけるメトリックを計算

引数名説明
typestring拘束タイプ
restlengthfloat拘束のrest状態における長さ
restvectorvector4拘束のrest状態における4次元ベクトル
restmatrixmatrix3拘束のrest状態における変換行列
// Scalar rest metric used as the divisor for ratio-based visualizations and plastic deformation.
float
restMetric(const string type; const float restlength; const vector4 restvector;
          const matrix3 restmatrix)
{
    // 2d and 3d restmatrices store inverse of material space coordinates.
    // rest状態におけるノルムを計算したいので逆行列に変換しておく

    // triarap, triarapnl, triarapnorm
    if (isTriARAP(type))
        return squaredNorm2(invert(set(restvector.x, restvector.y, restvector.z, restvector.w)));
    
    // tetarap*
    if (isTetARAP(type))
        return squaredNorm3(invert(restmatrix));

    // 対象以外は、restlengthを返す
    return restlength;
}

constraintMetric

指定タイプにおける拘束ジオメトリの変化量を計算

引数名説明
ptgeointポイントジオメトリのインデックス
congeoint拘束ジオメトリのインデックス
primint拘束プリミティブのインデックス
typestring拘束タイプ
metricstring計算するメトリック
float
constraintMetric(const int ptgeo, congeo, prim; const string type, metric)
{
    // stretchstress/bendstressが指定された場合は、
    // stressアトリビュートを返す
    if (metric == "stretchstress" || metric == "bendstress")
        return prim(congeo, "stress", prim);

    // プリミティブアトリビュートの取得
    float restlength = prim(congeo, "restlength", prim);
    vector4 restvector = prim(congeo, "restvector", prim);
    vector restdir = prim(congeo, "restdir", prim);
    string targetpath = prim(congeo, "target_path", prim);
    int targetprim = prim(congeo, "target_prim", prim);
    matrix3 restmatrix = prim(congeo, "restmatrix", prim);

    // 差分計算
    float val = computeRestLengthDifference(ptgeo, primpoints(congeo, prim), type,
                                            restlength, restvector,
                                            restdir, targetpath, targetprim, restmatrix);
    val = abs(val);

    // stretchratioが指定された場合は、比率に変換する
    if (metric == "stretchratio")
        val /= restMetric(type, restlength, restvector, restmatrix);

    return val;
}

maxConstraintMetric

指定タイプにおける拘束ジオメトリの最大変化量を計算

引数名説明
ptgeointポイントジオメトリのインデックス
congeoint拘束ジオメトリのインデックス
ptnumintポイント番号
types[]string[]評価する拘束タイプのリスト
metricstring計算するメトリック
float
maxConstraintMetric(const int ptgeo, congeo, ptnum; const string types[], metric)
{
    // Use the weld target if any.
    // weldが存在していた場合、ターゲットのポイント番号を返す
    int pt = weldTarget(ptgeo, ptnum);

    // Iterate over all constraint primitives of specified types connected
    // to input point and evaluate the max metric.
    // プリミティブ取得
    int prims[] = pointprims(congeo, pt);
    float maxval = 0;

    foreach(int prim; prims)
    {
        // constraint typeの取得
        string type = prim(congeo, "type", prim);

        // typesに含まれていない場合
        if (find(types, type) < 0)
            continue;

        // 最大値
        maxval = max(maxval, constraintMetric(ptgeo, congeo, prim, type, metric));
    }

    return maxval;
}

warpWeftScale

マテリアル UV 座標に基づいて、織り方向のスケーリング値を計算

引数名説明
geointジオメトリのインデックス
pts[]int[]ポイント番号の配列
warpfloat縦方向のスケール値
weftfloat横方向のスケール値
shearfloat斜め方向のスケール値
materialuvstringUVの名前
float
warpWeftScale(const int geo, pts[]; const float warp, weft, shear; const string materialuv)
{
    // uv値
    vector p0 = point(geo, materialuv, pts[0]);
    vector p1 = point(geo, materialuv, pts[1]);
    
    // 方向ベクトル
    p1 -= p0;

    // 角度
    float angle = degrees(atan2(p1.x, p1.y)) % 180;

    // 0-90
    if (angle > 90)
    {
        angle = 180 - angle;
    }

    float scale;

    // 0-1
    angle /= 90;

    // 45度未満
    if (angle < 0.5)
    {
        scale = lerp(warp, shear, angle*2);
    }
    else // 45度以上
    {
        scale = lerp(shear, weft, (angle-0.5)*2);
    }

    return scale;
}

findwelds

Weld に使用されているポイント配列を返す

引数名説明
geostringジオメトリの名前
pts[]int[]ポイント番号の配列
weldattribstringweldの名前デフォルト値は-1
// Return an array of pts welded to or from the points in pts array.
// NOTE: The geometry should have weldattrib with default value -1
// for this function work correctly.
// weldアトリビュート必須
// デフォルト値は、-1
int[]
findwelds(const string geo; const int pts[]; const string weldattrib)
{
    string weldgrp;
    string weldstr[];
    int welds[];

    // ptsが存在しない場合
    if (len(pts) == 0)
        return welds;

    foreach(int pt; pts)
    {
        // weldアトリビュート
        int weld = point(geo, weldattrib, pt);

        // "weld @weld=weld"を配列に格納
        if (weld >=0)
        {
            // Include any points this point is welded to.
            // weld目標ポイント
            append(weldstr, itoa(weld));

            // And any points also welded to those points.
            // weld目標ポイントを目標とする他のポイント
            append(weldstr, sprintf("\@weld=%d", weld));
        }

        // Include any points welded to this point.
        // 現在ポイントをweld目標とする他のポイント
        append(weldstr, sprintf("\@weld=%d", pt));
    }

    // Expand point group ensures we don't get duplicates.
    // weldstrに含まれるポイント番号を取得
    welds = expandpointgroup(geo, join(weldstr, " "));

    return welds;
}

walkdist

目標ポイントから指定プリミティブまでの最短距離やそのプリミティブにおける UV 座標を計算

引数名説明
geostring指定ジオメトリ
grpstringプリミティブグループの名前
goalposvector目標位置
typeintプリミティブのタイプID-1の場合は、すべてのプリミティブタイプが該当
weldattribstringweldの名前
curprimint現在のプリミティブ番号
curuvvector現在のUV座標
float
walkdist(const string geo; const string grp; const vector goalpos;
        const int type; const string weldattrib;
        int curprim; vector curuv)
{
    int prims[], pts[];
    string primstr[];
    int visited[];
    float dist = 0;
    int hasgrp = strlen(grp) > 0;
    int haswelds = haspointattrib(geo, weldattrib);

    // 探索済みでない場合
    while(find(visited, curprim) < 0)
    {
        // 探索済みとして配列へ格納
        append(visited, curprim);
        
        // 現在プリミティブから配列を作成
        primstr = array(itoa(curprim));

        // ポイント取得
        pts = primpoints(geo, curprim);
        int npts = len(pts);

        // Include welded points if needed.
        // weldポイントのチェック
        if (haswelds)
            append(pts, findwelds(geo, pts, weldattrib));

        foreach(int pt; pts)
        {
            // プリミティブ取得
            prims = pointprims(geo, pt);

            foreach(int prim; prims)
            {
                // skip current prim
                // skip not in group
                // only matching type
                // 現在のプリミティブとは異なり、
                // 指定されたグループに属し、
                // 指定されたタイプと一致するもの
                if (prim != curprim &&
                    (!hasgrp || inprimgroup(geo, grp, prim)) &&
                    (type < 0 || primintrinsic(geo, "typeid", prim) == type))
                    
                    // 配列へ格納 
                    append(primstr, itoa(prim));
            }
        }

        // goalposからprimstrグループ内の一番近い位置までの距離を調べて、
        // その一番近い位置におけるプリミティブ番号とUV座標を出力
        dist = xyzdist(geo, join(primstr, " "), goalpos, curprim, curuv);
    }

    return dist;
}

closestpttriangle

指定したポイントpから三角形までの最も近いポイント座標を計算し、頂ポイントまたは辺の番号とバリセントリック座標を計算

second_order_1

Real-Time Collision Detection" by Ericson

second_order_2

Real-Time Collision Detection" by Ericson

引数名説明
pvector対象となるポイントp
avector三角形の頂ポイントAの座標
bvector三角形の頂ポイントBの座標
cvector三角形の頂ポイントCの座標
vertint最も近い頂ポイントのインデックス
edgeint最も近い辺のインデックス
uvvector最も近いポイントのバリセントリック座標
// From "Real-Time Collision Detection" by Ericson.
// with modifications to return closest vertex or edge
// barycentric coords.
// バリセントリック座標
vector
closestpttriangle(const vector p, a, b, c;
                  int vert, edge; vector uv)
{
    // 初期化
    vert = edge = -1;

    // Check if P in vertex region outside A
    // ポイントPが頂ポイントAの外側の領域にあるかどうかをチェック
    vector ab = b - a;
    vector ac = c - a;
    vector ap = p - a;
    float d1 = dot(ab, ap);
    float d2 = dot(ac, ap);
    if (d1 <= 0.0f && d2 <= 0.0f)
    {
        vert = 0;
        uv = set(1, 0, 0);
        return a; // barycentric coordinates (1,0,0)
    }

    // Check if P in vertex region outside B
    // ポイントPが頂ポイントBの外側の領域にあるかどうかをチェック
    vector bp = p - b;
    float d3 = dot(ab, bp);
    float d4 = dot(ac, bp);
    if (d3 >= 0.0f && d4 <= d3)
    {
        vert = 1;
        uv = set(0, 1, 0);
        return b; // barycentric coordinates (0,1,0)
    }

    // Check if P in edge region of AB, if so return projection of P onto AB
    // ポイントPが辺ABの領域にあるかどうかをチェック
    // もしそうであれば、辺AB上に投影
    float vc = d1*d4 - d3*d2;
    if (vc <= 0.0f && d1 >= 0.0f && d3 <= 0.0f)
    {
        edge = 0;
        float v = d1 / (d1 - d3);
        uv = set(1-v, v, 0);
        return a + v * ab; // barycentric coordinates (1-v,v,0)
    }

    // Check if P in vertex region outside C
    // ポイントPが頂ポイントCの外側の領域にあるかどうかをチェック
    vector cp = p - c;
    float d5 = dot(ab, cp);
    float d6 = dot(ac, cp);
    if (d6 >= 0.0f && d5 <= d6)
    {
        vert = 2;
        uv = set(0, 0, 1);
        return c; // barycentric coordinates (0,0,1)
    }

    // Check if P in edge region of AC, if so return projection of P onto AC
    // ポイントPが辺ACの領域にあるかどうかをチェック
    // もしそうであれば、辺AC上に投影
    float vb = d5*d2 - d1*d6;
    if (vb <= 0.0f && d2 >= 0.0f && d6 <= 0.0f)
    {
        edge = 2;
        float w = d2 / (d2 - d6);
        uv = set(1-w, 0, w);
        return a + w * ac; // barycentric coordinates (1-w,0,w)
    }

    // Check if P in edge region of BC, if so return projection of P onto BC
    // ポイントPが辺BCの領域にあるかどうかをチェック
    // もしそうであれば、辺BC上に投影
    float va = d3*d6 - d5*d4;
    if (va <= 0.0f && (d4 - d3) >= 0.0f && (d5 - d6) >= 0.0f)
    {
        edge = 1;
        float w = (d4 - d3) / ((d4 - d3) + (d5 - d6));
        uv = set(0, 1-w, w);
        return b + w * (c - b); // barycentric coordinates (0,1-w,w)
    }

    // P inside face region. Compute Q through its barycentric coordinates (u,v,w)
    // ポイントPが三角形の内部にある場合は、そのバリセントリック座標を計算する
    float denom = 1.0f / (va + vb + vc);
    float v = vb * denom;
    float w = vc * denom;
    uv = set(1-w, v, w);
    return a + ab * v + ac * w; // = u*a + v*b + w*c, u = va * denom = 1.0f-v-w
}

closestpttriangle

closestpttriangleのラッパー関数であり、対応するポイント番号やハーフエッジを求める機能が追加されている

引数名説明
geostring指定ジオメトリ
primint三角形プリミティブのインデックス
ptsint[]三角形プリミティブの頂ポイントインデックス配列
pvector対象のポイント座標
ptnumint最も近い頂ポイントのインデックス
hedgeint最も近いハーフエッジのインデックス
uvvector最も近いポイントのバリセントリック座標
// Wrapper that translates vertex or edge ordinals to point numbers
// or half-edges, respectively, as well as translating barycentric coords.
vector
closestpttriangle(const string geo; const int prim, pts[]; const vector p;
                  int ptnum, hedge; vector uv)
{
    // 初期化
    ptnum = hedge = -1;

    // ポイント座標
    vector p0 = point(geo, "P", pts[0]);
    vector p1 = point(geo, "P", pts[1]);
    vector p2 = point(geo, "P", pts[2]);

    // ポイントPに最も近い三角形内のポイントを計算し、最も近い頂ポイントまたは辺の番号を取得
    int vert, edge;
    vector closepos = closestpttriangle(p, p0, p1, p2, vert, edge, uv);

    // 最も近い頂ポイントがある場合、対応するポイント番号を格納
    if (vert >= 0)
        ptnum = pts[vert];
    else if (edge >= 0) // 最も近いエッジがある場合、対応するハーフエッジを格納
        hedge = vertexhedge(geo, primvertex(geo, prim, edge));

    // Translate from barycentric as returned by inner closestpttriangle.
    // バリセントリック座標
    uv = set(uv.y, uv.z, 0);

    return closepos;
}

ispolytri

三角ポリゴンであるかどうか判別

引数名説明
geostring指定ジオメトリ
primintプリミティブのインデックス
ptsint[]プリミティブの頂ポイントインデックスの配列
int
ispolytri(const string geo; const int prim, pts[])
{
    // 3ポイントを持ち、typeidが1であり、閉じているか
    return len(pts) == 3 &&
            primintrinsic(geo, "typeid", prim) == 1 &&
            primintrinsic(geo, "closed", prim) == 1;
}

triwalkdist

三角プリミティブを対象として、与えられたジオメトリ内で目標位置に最も近いポイントを取得

引数名説明
geostring指定ジオメトリ
grpstring対象とするプリミティブグループ
goalposvector目標位置
weldattribstringweldの名前
curprimint現在のプリミティブのインデックス
curuvvector現在のプリミティブにおけるUV座標
// Similar to walkdist but uses closest point to triangle tests for speed.
// At the moment only supports triangles, but *might* be expanded
// to quads at some point.
float
triwalkdist(const string geo; const string grp; const vector goalpos;
            const string weldattrib;
            int curprim; vector curuv)
{
    int visited[];
    int hasgrp = strlen(grp) > 0; // グループが存在するか
    int haswelds = haspointattrib(geo, weldattrib); // weldを持っているか

    // ポイント取得
    int pts[] = primpoints(geo, curprim);

    // Nothing much we can do if not a triangle
    // 三角形ではない場合は、現在のプリミティブと目標位置までの距離を計算
    if (!ispolytri(geo, curprim, pts))
    {
        vector curpos = primuv(geo, "P", curprim, curuv);
        return xyzdist(geo, itoa(curprim), curpos, curprim, curuv);
    }
    
    // 初期化
    int curpt = -1, curhedge = -1;

    // 現在プリミティブ(三角形)における目標位置に最も近いポイントを計算し
    // ポイントが頂ポイント上またはエッジ上にある場合は、
    // curpt、curhedgeが更新
    vector curpos;
    curpos = closestpttriangle(geo, curprim, pts, goalpos,
                              curpt, curhedge, curuv);
    // 距離
    float dist = distance(curpos, goalpos);

    // 未探索プリミティブが存在
    while(find(visited, curprim) < 0)
    {
        // 探索済み
        append(visited, curprim);
        pts = primpoints(geo, curprim);

        // If still in current triangle, we're done.
        // ポイントが三角形の内側にあれば、break
        if (curpt < 0 && curhedge < 0)
            break;

        int prims[], nextpts[];

        // エッジ上のポイントが存在
        if (curhedge >= 0)
        {
            // On triangle edge, find edge of next primitive.
            // 次のハーフエッジ
            int nexthedge = hedge_nextequiv(geo, curhedge);

            // 現在のプリミティブから次のプリミティブを取得
            do
            {
                // Get prim from that edge.
                // nexthedgeを含んだ次のプリミティブを取得
                int nextprim = hedge_prim(geo, nexthedge);

                // Ensure it meets group and type criteria and add to prims.
                // 次のプリミティブが現在と同じでなく
                // グループが指定されていて、
                // 三角形である場合、配列に追加
                if (nextprim != curprim &&
                    (!hasgrp || inprimgroup(geo, grp, nextprim)) &&
                    ispolytri(geo, nextprim, primpoints(geo, nextprim)))
                    append(prims, nextprim);

                // Find any welds from the end points of the edge.
                // ポイントがweldを持っている場合
                // エッジの両端ポイントからweldポイントを探索し、
                // 得られたリストを配列に追加
                if (haswelds)
                    nextpts = findwelds(geo,
                                        array(hedge_srcpoint(geo, nexthedge), hedge_dstpoint(geo, nexthedge)),
                                        weldattrib);

                // 次のハーフエッジへ
                nexthedge = hedge_nextequiv(geo, nexthedge);

            } while (nexthedge != curhedge);

        }
        else // 頂ポイント上にポイントが存在
        {
            // On vertex, add to list of next points to check.
            // 現在のポイントをチェック対象へ
            nextpts = array(curpt);

            // And welded points.
            // weldを持っている場合
            if (haswelds)
            {
                // weldポイントを探索
                int weldpts[] = findwelds(geo, nextpts, weldattrib);

                // Avoid duplicates.
                // 重複回避し、weldポイントを配列に追加
                removevalue(weldpts, curpt);
                append(nextpts, weldpts);
            }
        }

        // Add any triangles from next set of points.
        // 各ポイントに関連するプリミティブを取得
        foreach(int pt; nextpts)
        {
            foreach(int prim; pointprims(geo, pt))
                
                // 現在プリミティブと異なっており、
                // グループを持っていた場合は、プリミティブに属していて、
                // 三角形の場合は、配列に追加
                if (prim != curprim &&
                    (!hasgrp || inprimgroup(geo, grp, prim)) &&
                    ispolytri(geo, prim, primpoints(geo, prim)))
                append(prims, prim);

        }

        // Check each candidate triangle for closer.
        // 目標位置に最も近い三角形を取得
        foreach(int prim; prims)
        {
            // ポイント取得
            pts = primpoints(geo, prim);
            vector nextuv;
            int nextpt = -1;
            int nexthedge = -1;
            
            // 現在プリミティブ(三角形)における目標位置に最も近いポイントを計算
            // ポイントが頂ポイント上またはエッジ上にある場合は、
            // nextpt、nexthedgeが更新
            vector nextpos = closestpttriangle(geo, prim, pts, goalpos,
                                              nextpt, nexthedge, nextuv);
            // 距離計算
            float d = distance(nextpos, goalpos);
            
            // 最初に求めた最短距離distよりも短い場合は更新する
            if (d < dist)
            {
                dist = d;
                curprim = prim;
                curuv = nextuv;
                curpt = nextpt;
                curhedge = nexthedge;
            }
        }
    }

    return dist;
}

extractRotation

以下の論文に基づいて、入力行列から回転成分を抽出

A Robust Method to Extract the Rotational Part of Deformations YouTube

引数名説明
Amatrix3回転を抽出するための入力行列
qinvector4以前のタイムステップや拘束解決からの回転を表すクォータニオン
maxiterintアルゴリズムが収束するまでの最大繰り返し回数
// Extract the rotation from the provided matrix using the algorithm from
// "A robust method to extract the rotational part of deformations."
// The input q is hopefully the rotation from a previous timestep or constraint
// solve for faster convergence.
vector4
extractRotation(const matrix3 A; const vector4 qin; const int maxiter)
{
    vector4 q = qin; // クォータニオン
    vector Arow[] = set(A);  // 行成分ごとに配列へ

    // 回転行列が入力行列に反復回数だけ近づける
    for(int i = 0; i < maxiter; i++)
    {
        vector Rrow[] = set(qconvert(q));  // 回転行列に変換

        // 角速度ベクトルを計算
        // 回転行列が入力行列にどれだけ一致しているか
        vector omega = cross(Rrow[0], Arow[0]) + cross(Rrow[1], Arow[1]) + cross(Rrow[2], Arow[2]);
        omega /= abs(dot(Rrow[0], Arow[0]) + dot(Rrow[1], Arow[1]) + dot(Rrow[2], Arow[2])) + 1e-5f;

        // 長さを計算
        float w = length(omega);
        // 収束
        if (w < 1e-5f)
            break;

        // 新しいクォータニオンを計算し、正規化
        // quaternion(angle, axis)
        q = qmultiply(quaternion(w, omega / w), q);
        q = normalize(q);
    }

    return q;
}

accumVec

カハンの加算アルゴリズムを利用してベクトルの和を計算

引数名説明
vvector累積和に加えるベクトル
sumvector現在の累積和を格納するベクトル
cvector誤差補正項を格納するベクトル
// Kahan sum vector and matrix accumulators.
void
accumVec(const vector v; vector sum, c)
{
    vector y = v - c; 
    vector t = sum + y;
    c = (t - sum) - y;
    sum = t;
}

accumMat3

カハンの加算アルゴリズムを利用して 3x3 行列の和を計算

引数名説明
vmatrix3累積和に加える3x3行列
summatrix3現在の累積和を格納する3x3行列
cmatrix3誤差補正項を格納する3x3行列
void
accumMat3(const matrix3 v; matrix3 sum, c)
{
    matrix3 y = v - c; 
    matrix3 t = sum + y;
    c = (t - sum) - y;
    sum = t;
}

computeCmAndRot

与えられたポイント集合に対して、rest と current における重心を計算し、その最適な回転を求める

引数名説明
geoconst int現在のジオメトリのインデックス
congeoconst intresst状態におけるジオメトリのインデックス
pts[]int array頂ポイントのインデックス配列
restcmvectorresst状態における重心を格納する変数
cmvector現在の重心
Rvector4最適な回転を格納するクォータニオン

// Compute the rest and current centers of mass, and
// best-fit rotation from rest space to current space.
// The R quateronion should the last best known rotation
// or the unit quaternion if unknown.
void computeCmAndRot(const int geo, congeo, pts[];
                    vector restcm, cm; vector4 R)
{
    // Rest and current centers-of-mass using Kahan sum for accuracy.
    int npts = len(pts);
    restcm = cm = 0;
    vector restcmerr = 0, cmerr = 0;

    // restとcurrentにおける重心を計算する
    foreach(int pt; pts)
    {
        // 累算
        accumVec(point(congeo, "rest", pt), restcm, restcmerr);
        accumVec(point(geo, "P", pt), cm, cmerr);
    }
    restcm /= npts;
    cm /= npts;

    // Covariance matrix using Kahan sum for accuracy.
    matrix3 A = 0, Aerr = 0;

    // restとcurrentにおける共分散行列を計算する
    foreach(int pt; pts)
    {
        vector rest = point(congeo, "rest", pt); // rest
        vector pos = point(geo, "P", pt); // current
        vector q = rest - restcm;
        vector p = pos - cm;
        
        // 累算
        accumMat3(outerproduct(q, p), A, Aerr);
    }

    // Rotation from rest space to current.
    // restからcurrentへの最適な回転を求める
    R = extractRotation(A, R, 20);
}


updateFromRestShapeMatch

rest-current間における形状マッチングを行い、rest状態におけるポイントを更新

引数名説明
geoconst int現在のジオメトリのインデックス
congeoconst int休息状態のジオメトリのインデックス
pts[]int array頂点のインデックスの配列
inamountconst float更新量(長さ単位または比率)
isratioconst int更新量が比率であるかどうかを示すフラグ(0: 長さ単位、1: 比率)
outgeoconst int更新された休息状態のジオメトリのインデックス
int
updateFromRestShapeMatch(const int geo, congeo, pts[];
                        const float inamount; const int isratio;
                        const int outgeo)
{
    // Check if nothing to do.
    // inamountが0以下で、isratioが指定されている場合は、0を返す
    if (isratio && inamount <= 0)
        return 0;

    vector restcm, cm;
    vector4 R = {0, 0, 0, 1};

    // Find centers of mass and rotation from rest to current.
    // 重心とrestからcurrentへの回転を求める
    computeCmAndRot(geo, congeo, pts, restcm, cm, R);

    // Current rotation back to rest.
    // 逆クォータニオン
    vector4 Rinv = qinvert(R);

    foreach(int pt; pts)
    {
        // Diff from current point to rest in rest space.
        // currentからrestの位置までの差分ベクトルを計算
        vector pos = point(geo, "P", pt);  // current
        vector rest = point(congeo, "rest", pt); // rest
        vector diff = (qrotate(Rinv, pos - cm) + restcm) - rest;

        // Convert to ratio if in length units.
        // inamountが長さで与えられている場合は、比率に変換
        float amount = inamount;
        if (!isratio)
            amount = inamount / length(diff);

        // 0-1
        amount = clamp(amount, 0, 1);

        // restを更新
        rest += diff * amount;

        // Update rest point attribute.
        // rest (pt) <- rest
        setpointattrib(outgeo, "rest", pt, rest);
    }

    return 1;
}

plasticDeformationShapeMatch

Shape Match拘束を対象として塑性変形における塑性流動量を計算し、拘束の剛性値を更新

引数名説明
geoconst int現在のジオメトリのインデックス
congeoconst intrest状態におけるジオメトリのインデックス
pts[]int array頂点のインデックスの配列
plasticrateconst float塑性変形のレート
plasticthresholdconst float塑性変形の閾値
plastichardeningconst float塑性硬化係数
dtconst float時間ステップ
Rinconst vector4初期回転を表すクォータニオン
stiffnessfloat剛性を格納する変数
outgeoconst int更新された休息状態のジオメトリのインデックス
float
plasticDeformationShapeMatch(const int geo, congeo, pts[];
                            const float plasticrate, plasticthreshold,
                            plastichardening, dt;
                            const vector4 Rin;
                            float stiffness;
                            const int outgeo)
{
    // This plasticity model roughly matches the wire solver.
    float u = exp(-plasticrate * dt); // 0-1
    float v = 1 - u;
    float flow = 0;

    vector restcm, cm;
    vector4 R = Rin;

    // Find centers of mass and rotation from rest to current.
    // 重心とrestからcurrentへの回転を求める
    computeCmAndRot(geo, congeo, pts, restcm, cm, R);

    // Current rotation back to rest.
    // 逆クォータニオン
    vector4 Rinv = qinvert(R);

    // Check every point in the constraint for plastic flow.
    // ポイントごとに塑性流動量を計算する
    foreach(int pt; pts)
    {
        // Current point transformed to rest space.
        // 現在ポイントをrest空間に戻す
        vector rest = point(congeo, "rest", pt);
        vector pos = point(geo, "P", pt);
        vector currest = qrotate(Rinv, pos - cm) + restcm;
        
        // 差分計算
        float diff = distance(currest, rest);

        // 計算した差分が閾値より大きい場合
        if (diff > plasticthreshold)
        {
            // plasticrateを元にrestを更新する
            vector newrest = lerp(rest, currest, v);

            // ポイントにおける塑性流動量
            float localflow = v * diff;
          
            // rest (pt) <- newrest
            setpointattrib(outgeo, "rest", pt, newrest);
            // plasticflow (pt) += localflow
            setpointattrib(outgeo, "plasticflow", pt, localflow, "add");

            // 累算し全体の塑性流動量とする
            flow += localflow;
        }
    }

    // Update stiffness from hardening.
    // 剛性値の更新
    float k = u + v * plastichardening;
    float s = logscaleStiffness(k, stiffness); // ログスケール

    // Ensure we stay finite for stiffness.
    // 有限値
    stiffness = select(isfinite(s), s, stiffness);

    // Return total flow for constraint.
    // 全体の塑性流動量
    return flow;
}

hasSmoothing

与えられた拘束タイプが拘束解決時にスムージングが行えるか判別

引数名説明
typestringスムージングを調べる対象のタイプの文字列
// Returns whether the type supports smoothing in the constraint solve.
// We use this during graph-coloring to clear out the worksets for the
// smoothing sizes and offsets if no smoothing is possible, rather
// than call a bunch of empty constraint passes.
int
hasSmoothing(const string type)
{
    string nosmoothtypes[] = { "bend", "trianglebend", "angle", "tetfiber", "tetfibernorm", "stretchshear",
                              "bendtwist", "pinorient", "pressure", "shapematch" };
    
    // typeがリスト内にある場合は、0を返す
    return (find(nosmoothtypes, type) < 0);
}