- compareIntArrays
2つの整数配列が等しいかどうかを比較 - sortRemoveDuplicates
整数配列から重複する要素を削除し、要素をソートした新しい配列を返す - calcConstraintTopology
拘束トポロジーに関するデータIDを取得 - constraintAlias
入力された拘束タイプの文字列に対応するエイリアスを返す - constraintHash
拘束タイプのエイリアスに基づいてハッシュ値を生成する - isTriARAP
拘束タイプがTriARAP(三角形の角度による最小二乗法)であるかどうかを判別 - isTetARAPVol
TetARAPにおける体積維持に使用する拘束の種類を判別 - isTetARAP
拘束タイプがTetARAP(四面体における剛体補間)であるかどうかを判別 - isNonLinearARAP
拘束タイプが非線形ARAPであるかどうかを判別 - isTetFiber
拘束タイプがTetFiber(特定方向に沿って圧縮することができる四面体拘束)であるかどうかを判別 - computeDistanceRestLength
2ポイント間の距離を計算 - createDistanceConstraint
入力ポイントから最も近いプリミティブ上の位置を計算し、restvector
、restlength
などを作成 - createAttachConstraint
入力ポイントから最も近いプリミティブ上の位置を計算し、restvector
、restlength
などを作成 - projectToLine
与えられた位置ベクトルを指定方向の直線上に射影 - fromTriangleSpaceXform
三角形からワールド空間への変換行列を返す - fromTriangleSpace
3ポイントで構成される平面からワールド空間への回転ベクトルを返す - computeDistanceLineRestLength
与えられたポイントと、指定された直線間の距離に基づいてrestlength
を計算 - createAttachNormalConstraint
対象プリミティブの法線情報を考慮したAttach拘束を作成 - pointPrimTargetPos
UV座標と対象プリミティブのポイント位置からターゲット位置を計算 - pointPrimTargetPos
pointPrimTargetPos関数のpattrib
をP
としてオーバーロードしたもの - 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
差分ベクトルをもとにrestvector
とrestlength
を更新しノルムの差を返す - updateRestMatrix
差分ベクトルをもとにrestmatrix
とrestlength
を更新しノルムの差を返す - 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
与えられた拘束タイプに基づいて、restlength
やrestvector
などの値を更新 - 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 を返す
引数名 | 型 | 説明 |
a | int[] | 比較する最初の整数配列 |
b | int[] | 比較する 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
整数配列から重複する要素を削除し、要素をソートした新しい配列を返す
引数名 | 型 | 説明 |
a | int[] | ソートおよび重複削除を行う整数配列 |
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を取得
引数名 | 型 | 説明 |
constraintgeo | int | 拘束ジオメトリのデータID |
pointgeo | int | ポイントジオメトリのデータ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
入力された拘束タイプの文字列に対応するエイリアスを返す
引数名 | 型 | 説明 |
type | string | 拘束タイプの文字列 |
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
拘束タイプのエイリアスに基づいてハッシュ値を生成する
引数名 | 型 | 説明 |
type | string | 拘束タイプの文字列 |
int constraintHash(const string type)
{
return random_shash(constraintAlias(type));
}
isTriARAP
拘束タイプがTriARAP(三角形の角度による最小二乗法)であるかどうかを判別
triarap
: 三角形に対するARAPアルゴリズムtriarapnl
: 非線形変形を考慮した三角形に対するARAPアルゴリズムtriarapnorm
: 法線情報を維持しながら変形を行う三角形に対するARAPアルゴリズム
引数名 | 型 | 説明 |
type | string | 拘束タイプの文字列 |
int isTriARAP(const string type)
{
return type == "triarap" || type == "triarapnl" || type == "triarapnorm";
}
isTetARAPVol
TetARAPにおける体積維持に使用する拘束の種類を判別
tetarapvol
: 体積維持を考慮した四面体に対するARAPアルゴリズムtetarapnlvol
: 非線形変形と体積維持を考慮した四面体に対するARAPアルゴリズムtetarapnormvol
: 体積と法線を維持しながら変形を行う四面体に対するARAPアルゴリズム
引数 | 型 | 説明 |
type | string | 判定対象の拘束タイプを表す文字列 |
isTetARAP
拘束タイプがTetARAP(四面体における剛体補間)であるかどうかを判別
tetarap
: 四面体に対するARAPアルゴリズムtetarapnl
: 非線形変形を考慮した四面体に対するARAPアルゴリズムtetarapnorm
: 法線情報を維持しながら変形を行う四面体に対するARAPアルゴリズム
引数名 | 型 | 説明 |
type | string | 拘束タイプの文字列 |
int isTetARAP(const string type)
{
return type == "tetarap" || type == "tetarapnl" || type == "tetarapnorm" || isTetARAPVol(type);
}
isNonLinearARAP
拘束タイプが非線形ARAPであるかどうかを判別
引数名 | 型 | 説明 |
type | string | 拘束タイプの文字列 |
int isNonLinearARAP(const string type)
{
return type == "triarapnl" || type == "tetarapnl" || type == "tetarapnlvol";
}
isTetFiber
拘束タイプがTetFiber(特定方向に沿って圧縮することができる四面体拘束)であるかどうかを判別
tetfiber
: 圧縮を考慮した四面体拘束tetfibernorm
: 圧縮と法線情報を考慮しながら変形を行う四面体拘束
引数名 | 型 | 説明 |
type | string | 拘束タイプの文字列 |
int isTetFiber(const string type)
{
return type == "tetfiber" || type == "tetfibernorm";
}
computeDistanceRestLength
2ポイント間の距離を計算
引数名 | 型 | 説明 |
geo | int | 距離を計算するジオメトリのデータID |
p0 | int | ジオメトリ内の1つ目のポイントのインデックス |
p1 | int | ジオメトリ内の2つ目のポイントのインデックス |
float
computeDistanceRestLength(const int geo; const int p0, p1)
{
return distance(vector(point(geo, "P", p0)), vector(point(geo, "P", p1)));
}
createDistanceConstraint
隣接ポイントを結合し、polylineを作成
引数名 | 型 | 説明 |
geo | int | 距離拘束を生成する元のジオメトリ |
ptnum | int | ジオメトリ内のポイントのインデックス |
srcgrp | string | 入力ジオメトリ内のポイントグループ名 |
outgeo | int | 距離拘束を追加する出力ジオメトリ |
outgrp | string | 出力ジオメトリ内の生成されたプリミティブのグループ名 |
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拘束を作成
引数名 | 型 | 説明 |
geo | int | アタッチ拘束を生成する元のジオメトリ |
attachgeo | int | アタッチ先のジオメトリ |
ptnum | int | ジオメトリ内のポイントのインデックス |
srcidx | int | ソースインデックス |
attachgrp | string | アタッチ先ジオメトリ内のポイントまたはプリミティブグループ名 |
useclosestpt | int | 最も近いポイントを使用するかどうか(1:真、0:偽) |
useclosestprim | int | 最も近いプリミティブを使用するかどうか(1:真、0:偽) |
maxdistcheck | int | 最大距離チェックを行うかどうか(1:真、0:偽) |
maxdist | float | 最大距離制限 |
outgeo | int | アタッチ拘束を追加する出力ジオメトリ |
outgrp | string | 出力ジオメトリ内の生成されたプリミティブのグループ名 |
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
与えられた位置ベクトルを指定方向の直線上に射影
引数名 | 型 | 説明 |
pos | vector | 射影する位置ベクトル |
orig | vector | 直線上の任意のポイントを表すベクトル |
dir | vector | 正規化された方向ベクトル(直線の方向を示す) |
// 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と一致させる必要がある
引数名 | 型 | 説明 |
p0 | vector | 三角形の頂ポイント1の座標 |
p1 | vector | 三角形の頂ポイント2の座標 |
p2 | vector | 三角形の頂ポイント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ポイントで構成される平面からワールド空間への回転ベクトルを返す
引数名 | 型 | 説明 |
path | string | ジオメトリのパス |
prim | int | ポリゴンを指定するプリミティブのインデックス |
dir | vector | 三角形空間からワールド空間へ回転させるベクトル |
invert | int | 逆変換を行うかどうか(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を計算
引数名 | 型 | 説明 |
geo | int | 距離を計算する元のジオメトリ |
pt0 | int | ジオメトリ内のポイントのインデックス |
orig | vector | 直線上の任意のポイントを表すベクトル |
indir | vector | 直線の方向を示すベクトル |
path | string | ジオメトリのパス(三角形空間の変換が必要な場合) |
prim | int | ポリゴンを指定するプリミティブのインデックス |
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拘束を作成
引数名 | 型 | 説明 |
geo | int | 入力ジオメトリ |
ptnum | int | ジオメトリ内のポイントのインデックス |
targetpath | string | ターゲットジオメトリのパス |
targetprim | int | ターゲットジオメトリのプリミティブインデックス |
targetuv | vector | ターゲットジオメトリのプリミティブ上のUV座標 |
outgeo | int | 出力ジオメトリ |
outgrp | string | 出力ジオメトリのプリミティブグループ名 |
// 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座標と対象プリミティブのポイント位置からターゲット位置を計算
引数名 | 型 | 説明 |
geo | int | ジオメトリ |
pts | int[] | プリミティブのポイントインデックスの配列 |
u | float | UV座標のU値 |
v | float | UV座標のV値 |
pattrib | string | 対象のポイント属性名 |
// 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" としてオーバーロードしたもの
引数名 | 型 | 説明 |
geo | int | ジオメトリ |
pts | int[] | プリミティブのポイントインデックスの配列 |
u | float | UV座標のU値 |
v | float | UV座標のV値 |
// オーバーロード
vector pointPrimTargetPos(const int geo; const int pts[]; const float u, v)
{
return pointPrimTargetPos(geo, pts, u, v, "P");
}
computePointPrimRestLength
与えられたポイントとターゲットプリミティブ間の距離を計算
引数名 | 型 | 説明 |
geo | int | ジオメトリ |
pt | int | 計算する距離の基準となるポイントのインデックス |
tgtpts | int[] | ターゲットプリミティブのポイントインデックスの配列 |
restvector | vector4 | ターゲットプリミティブの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座標を、対象となる線分内のパラメトリック値に変換
引数名 | 型 | 説明 |
geo | string | ジオメトリのパス |
targetprim | int | 対象のプリミティブインデックス |
targetpts | int[] | ターゲットプリミティブのポイントインデックスの配列 |
targetuv | vector | ターゲットプリミティブの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(縫合)拘束を作成
引数名 | 型 | 説明 |
geo | int | ソースジオメトリのインデックス |
ptnum | int | ソースポイントのインデックス |
srcidx | int | ソースインデックス |
targetgrp | string | ターゲットポイントグループの名前 |
useclosestpt | int | 最も近いポイントまたはプリミティブを使用するかどうかを示すフラグ |
useclosestprim | int | 最も近いプリミティブを使用するかどうかを示すフラグ |
maxdistcheck | int | 最大距離チェックを使用するかどうかを示すフラグ |
maxdist | float | 最大距離 |
outgeo | int | 出力ジオメトリのインデックス |
outgrp | string | 出力プリムグループの名前 |
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
与えられたハーフエッジに対して、反対側にあるポリゴンのポイントを返す
引数名 | 型 | 説明 |
geo | int | ジオメトリを参照する整数 |
hedge | int | ハーフエッジを参照する整数 |
int oppositepoint(const int geo; const int hedge)
{
// hedgeの後に続くハーフエッジを取得し、ゴールポイント番号を取得
return hedge_dstpoint(geo, hedge_next(geo, hedge));
}
computeDihedralRestLength
隣接する三角形の法線ベクトルから二面角を計算
引数名 | 型 | 説明 |
geo | int | ジオメトリのID |
pt0, pt1, pt2, pt3 | int | 2つの隣接三角形を構成する4つのポイントのインデックス |
restlength | float | 計算された二面角の初期値(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(二面角)拘束を作成
引数名 | 型 | 説明 |
geo | int | 入力ジオメトリのID |
ptnum | int | 拘束を作成するポイントのインデックス |
srcgrp | string | 入力ジオメトリ内で拘束を作成するポイントを含むグループ名 |
outgeo | int | 出力ジオメトリのID |
outgrp | string | 作成された拘束プリミティブを含む出力ジオメトリのグループ名 |
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(二面角)拘束を作成
引数名 | 型 | 説明 |
geo | int | 入力ジオメトリのID |
oldgeo | int | 元のジオメトリのID |
prim | int | 処理対象のプリミティブインデックス |
outgeo | int | 出力ジオメトリのID |
outgrp | string | 作成された拘束プリミティブを含む出力ジオメトリのグループ名 |
// この関数の目的は、ソフトボディシミュレーションに使用できる、
// 新しく溶接されたプリミティブの間の二面体拘束を作成することです
// この拘束は、複雑なオブジェクトが外力を受けて変形する際に、その形状を保持するのに役立ちます
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つのポイント間の各セグメントの回転と長さを計算
引数名 | 型 | 説明 |
geo | int | 入力ジオメトリのID |
primnum | int | 処理対象のプリミティブインデックス |
srcgrp | string | 入力ジオメトリで対象とするポイントグループの名前 |
outgeo | int | 出力ジオメトリの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ポイントのオリエンテーションを取得し、それらの間における最も近い回転を計算
引数名 | 型 | 説明 |
geo | int | 入力ジオメトリのインデックス |
pt0 | int | 最初のポイントのインデックス |
pt1 | int | 2番目のポイントのインデックス |
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(曲げ)拘束を作成
引数名 | 型 | 説明 |
geo | int | 入力ジオメトリのインデックス |
ptnum | int | ポイントのインデックス |
srcgrp | string | 入力ジオメトリのソースグループ名 |
type | string | 拘束タイプ("stretchshear"またはその他) |
outgeo | int | 出力ジオメトリのインデックス |
outgrp | string | 出力ジオメトリの出力グループ名 |
// 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拘束を作成
引数名 | 型 | 説明 |
geo | int | 入力ジオメトリのインデックス |
ptnum | int | ポイントのインデックス |
srcgrp | string | 入力ジオメトリのソースグループ名 |
outgeo | int | 出力ジオメトリのインデックス |
outgrp | string | 出力ジオメトリの出力グループ名 |
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(曲げ・捻じれ)拘束を作成
引数名 | 型 | 説明 |
geo | int | 入力ジオメトリのインデックス |
ptnum | int | ポイントのインデックス |
srcgrp | string | 入力ジオメトリのソースグループ名 |
outgeo | int | 出力ジオメトリのインデックス |
outgrp | string | 出力ジオメトリの出力グループ名 |
// 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ポイントを見つける
引数名 | 型 | 説明 |
geo | int | 入力ジオメトリのインデックス |
ptnum | int | ポイントのインデックス |
weld | int | 溶接ポイントのインデックス |
pt0 | int | 拘束を作成するための最初のポイントのインデックス(出力) |
pt1 | int | 拘束を作成するための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)拘束を作成
引数名 | 型 | 説明 |
geo | int | 入力ジオメトリのインデックス |
ptnum | int | ポイントのインデックス |
srcgrp | string | 入力ポイントのグループ名 |
maxbranchangle | float | 最大ブランチ角度(度) |
outgeo | int | 出力ジオメトリのインデックス |
outbendgrp | string | 出力プリミティブのベンドグループ名 |
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)拘束を削除
引数名 | 型 | 説明 |
congeo | int | 拘束ジオメトリのインデックス |
ptgeo | int | ポイントジオメトリのインデックス |
primnum | int | プリミティブのインデックス |
outgeo | int | 出力ジオメトリのインデックス |
// 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
三角形上のポイントを体積と勾配を求めるのに適した順番にする
引数名 | 型 | 説明 |
geo | int | ジオメトリのインデックス |
ptnum | int | 対象となるポイントのインデックス |
// 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
三角形の体積を計算
引数名 | 型 | 説明 |
geo | int | ジオメトリのインデックス |
ptnum | int | 対象となるポイントのインデックス |
volumepts | int[] | 体積計算に使用される三角形のポイントを表す配列 |
// 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(圧力)拘束に必要な体積を計算
引数名 | 型 | 説明 |
geo | int | ジオメトリのインデックス |
inpts | int[] | 静止状態の体積を計算するためのポイントのインデックスの配列 |
mode | string | 計算モード("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としてオーバーロードしたもの
引数名 | 型 | 説明 |
geo | int | ジオメトリのインデックス |
inpts | int[] | 静止状態の体積を計算するためのポイントのインデックスの配列 |
float
computePressureRestLength(const int geo; const int inpts[])
{
// modeをvolumeとし体積計算
return computePressureRestLength(geo, inpts, "volume");
}
createPressureConstraint
体積を維持するPressure(圧力)拘束を作成
引数名 | 型 | 説明 |
geo | int | 入力ジオメトリのインデックス |
srcgrp | string | 対象となるポイントのグループ名 |
outgeo | int | 出力ジオメトリのインデックス |
outgrp | string | 作成された圧力拘束のプリミティブを含むグループ名 |
// 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拘束を作成
引数名 | 型 | 説明 |
geo | int | 入力ジオメトリのインデックス |
srcgrp | string | 対象となるポイントのグループ名 |
outgeo | int | 出力ジオメトリのインデックス |
outgrp | string | 作成された形状マッチ拘束のプリミティブを含むグループ名 |
// 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
四面体の体積を計算
引数名 | 型 | 説明 |
geo | int | 入力ジオメトリのインデックス |
pt0 | int | テトラヘドロンの頂ポイント1のインデックス |
pt1 | int | テトラヘドロンの頂ポイント2のインデックス |
pt2 | int | テトラヘドロンの頂ポイント3のインデックス |
pt3 | int | テトラヘドロンの頂ポイント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拘束を作成
引数名 | 型 | 説明 |
geo | int | 入力ジオメトリのインデックス |
ptnum | int | 対象のポイントのインデックス |
srcgrp | string | ソースポイントグループ名 |
outgeo | int | 出力ジオメトリのインデックス |
outgrp | string | 出力プリミティブグループ名 |
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つの連続するポイントを受け取り、その間の角度を計算
引数名 | 型 | 説明 |
geo | int | ジオメトリのインデックス |
pt0 | int | 1つ目のポイントのインデックス |
pt1 | int | 2つ目のポイントのインデックス(中心ポイント) |
pt2 | int | 3つ目のポイントのインデックス |
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
三角形の座標を受け取り、その座標から重心までの距離を計算
引数名 | 型 | 説明 |
p0 | vector | 1つ目のポイントの座標 |
p1 | vector | 2つ目のポイントの座標(対象の頂ポイント) |
p2 | vector | 3つ目のポイントの座標 |
// 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
三角形のインデックスを受け取り、その座標から重心までの距離を計算
引数名 | 型 | 説明 |
geo | int | ジオメトリのインデックス |
pt0 | int | 1つ目のポイントのインデックス |
pt1 | int | 2つ目のポイントのインデックス(対象の頂ポイント) |
pt2 | int | 3つ目のポイントのインデックス |
// 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
を計算
引数名 | 型 | 説明 |
geo | int | ジオメトリのインデックス |
pt0 | int | 1つ目のポイントのインデックス |
pt1 | int | 2つ目のポイントのインデックス(対象の頂ポイント) |
pt2 | int | 3つ目のポイントのインデックス |
angle | float | 与えられた角度(度数法) |
// 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(曲げ)拘束を作成
引数名 | 型 | 説明 |
geo | int | 入力ジオメトリのインデックス |
ptnum | int | 中心となるポイントのインデックス |
type | string | 拘束のタイプ |
srcgrp | string | 対象となるポイントグループ名 |
maxbranchangle | float | 最大枝分かれ角度(度数法) |
outgeo | int | 出力ジオメトリのインデックス |
outgrp | string | 作成された拘束を格納するプリミティブグループ名 |
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(接着)拘束を作成
引数名 | 型 | 説明 |
geo | int | 入力ジオメトリのインデックス |
congeo | int | 接続をチェックするジオメトリのインデックス |
pt | int | 拘束を作成するポイントのインデックス |
srcgrp | string | 入力ジオメトリのポイントグループ名 |
dstgrp | string | 接続先ポイントグループ名 |
primgrp | string | 既存の拘束をチェックするためのプリミティブグループ名 |
classname | string | クラス名を格納するポイントアトリビュート名 |
usecluster | int | クラスタリングを使用するかどうか(0:使用しない、1:使用する) |
clusterattrib | string | クラスタ名を格納するポイントアトリビュート名 |
numconstraint | int | 作成する拘束の最大数 |
minrad | float | 最小距離制限 |
maxrad | float | 最大距離制限 |
maxpt | int | 近傍ポイントの最大数 |
pref | int | 順序設定(1:最も遠いポイントから) |
seed | float | 乱数シード |
threshold | float | 拘束を作成するためのしきい値 |
ptthreshold | float | しきい値をポイント接続に適用するためのパラメータ |
outgeo | int | 出力ジオメトリのインデックス |
outgrp | string | 作成された拘束を格納するプリミティブグループ名 |
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(支柱)拘束を作成
引数名 | 型 | 説明 |
geo | int | 入力ジオメトリのインデックス |
ptnum | int | Strut拘束を作成するポイントのインデックス |
srcgrp | string | 入力ジオメトリのポイントグループ名 |
classname | string | クラス名を格納するポイントアトリビュート名 |
dirattrib | string | 方向ベクトルを格納するポイントアトリビュート名 |
revnml | int | 法線を反転するかどうか(0:反転しない、1:反転する) |
checknml | int | 法線チェックを行うかどうか(0:行わない、1:行う) |
numconstraint | int | 作成する拘束の最大数 |
maxlen | float | 最大距離制限 |
jitter | float | 方向ベクトルのジッター(ランダムノイズ) |
rayoff | float | レイのオフセット距離 |
seed | float | 乱数シード |
ptthreshold | float | しきい値をポイント接続に適用するためのパラメータ |
outgeo | int | 出力ジオメトリのインデックス |
outgrp | string | 作成された拘束を格納するプリミティブグループ名 |
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形状情報と体積を計算
引数名 | 型 | 説明 |
geo | int | 入力ジオメトリのインデックス |
pt0 | int | テトラヘドロンの頂ポイント0のインデックス |
pt1 | int | テトラヘドロンの頂ポイント1のインデックス |
pt2 | int | テトラヘドロンの頂ポイント2のインデックス |
pt3 | int | テトラヘドロンの頂ポイント3のインデックス |
scale | float | スケーリング係数 |
restmatrix | matrix3 | 計算された逆材料行列(出力パラメータ) |
volume | float | 計算されたテトラヘドロンの体積(出力パラメータ) |
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を計算
引数名 | 型 | 説明 |
geo | int | ジオメトリオブジェクトのID |
pt0, pt1, pt2, pt3 | int | 四面体を構成するポイントのインデックス |
volume | float | 四面体の体積 |
materialW | vector | 材料の方向ベクトル |
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拘束を作成
引数名 | 型 | 説明 |
geo | int | 入力ジオメトリのインデックス |
ptnum | int | 処理対象のポイント番号 |
srcgrp | string | 入力ジオメトリのポイントグループ名 |
outgeo | int | 出力ジオメトリのインデックス |
outgrp | string | 出力ジオメトリのプリミティブグループ名 |
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
(形状情報)と面積を計算
引数名 | 型 | 説明 |
geo | int | 入力ジオメトリのインデックス |
pt0, pt1, pt2 | int | 三角形の頂ポイントのポイント番号 |
scale | float | スケーリング係数 |
restmatrix | matrix2 | 計算されたrest状態における行列(出力) |
area | float | 計算された三角形の面積(出力) |
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次元行列の極分解を計算
引数名 | 型 | 説明 |
A | matrix2 | 入力となる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
指定されたスケーリング係数に基いて三角形の面積を計算
引数名 | 型 | 説明 |
geo | int | 入力ジオメトリのインデックス |
pt0, pt1, pt2 | int | 三角形の頂ポイントのポイント番号 |
scale | float | 三角形のスケーリング係数 |
// 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拘束を作成
引数名 | 型 | 説明 |
geo | int | 入力ジオメトリのインデックス |
ptnum | int | 処理対象のポイント番号 |
srcgrp | string | 入力ジオメトリのポイントグループ名 |
type | string | 拘束タイプ(ストレッチ) |
restscale | float | rest状態におけるスケーリング係数 |
outgeo | int | 出力ジオメトリのインデックス |
outgrp | string | 出力ジオメトリのプリミティブグループ名 |
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拘束を作成
引数名 | 型 | 説明 |
geo | int | 入力ジオメトリのインデックス |
ptnum | int | 処理対象のポイント番号 |
srcgrp | string | 入力ジオメトリのポイントグループ名 |
type | string | 拘束タイプ(ストレッチ) |
restscale | float | rest状態におけるスケーリング係数 |
outgeo | int | 出力ジオメトリのインデックス |
outgrp | string | 出力ジオメトリのプリミティブグループ名 |
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
ポイント間におけるオリエンテーションの差を計算
引数名 | 型 | 説明 |
geo | int | 入力ジオメトリのインデックス |
pts[] | int array | ポイントインデックスの配列 |
type | string | 拘束タイプ("pinorient"または"bendtwist") |
restvector | vector4 | rest状態におけるベクター |
aadiff | vector | 関数内で計算されたオリエンテーション差分の角軸(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
ログスケールに変換
引数名 | 型 | 説明 |
k | float | 対数スケール変換の係数 |
stiffness | float | 変換対象の剛性値 |
float
logscaleStiffness(const float k, stiffness)
{
// Restrict to non-negative, finite values.
return clamp(exp(k * log(stiffness + 1)) - 1, 0, 1e37);
}
invlogscaleStiffness
logscaleStiffness の逆変換
引数名 | 型 | 説明 |
x | float | 対数スケールで変換された剛性値 |
stiffness | float | 元の剛性値 |
// 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 を更新し、その角度を返す
引数名 | 型 | 説明 |
inamount | float | 更新されるオリエンテーションの量(度数または比率で指定) |
isratio | int | amountが比率で指定されている場合は1、度数で指定されている場合は0 |
aadiff | vector | オリエンテーションの差を表す角度/軸表現 |
restvector | vector4 | 現在のオリエンテーション情報を格納した四元数 |
// 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 ノルムの二乗を返す
引数名 | 型 | 説明 |
a | matrix2 | 2x2の行列 |
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 ノルムの二乗を返す
引数名 | 型 | 説明 |
a | matrix3 | 3x3の行列 |
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
差分ベクトルをもとにrestvector
とrestlength
を更新しノルムの差を返す
引数名 | 型 | 説明 |
inamount | float | 更新量(長さ単位または比率) |
isratio | int | 更新量が比率であるかどうかを示すフラグ(0: 長さ単位、1: 比率) |
vecdiff | vector4 | 差分ベクトル |
restlength | float | 更新するrestlength |
restvector | vector4 | 2x2の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
差分ベクトルをもとにrestmatrix
とrestlength
を更新しノルムの差を返す
引数名 | 型 | 説明 |
inamount | const float | 更新量(長さ単位または比率) |
isratio | const int | 更新量が比率であるかどうかを示すフラグ(0: 長さ単位、1: 比率) |
matdiff | const matrix3 | マトリックスの差 |
restlength | float | rest状態における長さを格納する変数 |
restmatrix | matrix3 | rest状態におけるマトリックスを格納する変数 |
// 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 間におけるベクトル差分を計算
引数名 | 型 | 説明 |
geo | const int | ジオメトリのインデックス |
pts[] | int array | 頂ポイントのインデックスの配列 |
type | const string | シミュレーションタイプ(tetfiber, tetfibernorm, triarap, triarapnl, triarapnorm) |
restvector | const vector4 | rest状態におけるベクトル |
vecdiff | vector4 | rest状態におけるベクトルと現在のベクトルの差を格納する変数 |
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 差分を計算
引数名 | 型 | 説明 |
geo | int | ジオメトリのインデックス |
pts[] | int[] | 四面体を形成する4つのポイントのインデックス配列 |
type | string | 拘束タイプ |
restmatrix | matrix3 | rest行列です |
matdiff | matrix3 | rest行列と現在の変形に対する差分行列 |
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
塑性変形における塑性流動量を計算し、拘束の剛性値を更新
引数名 | 型 | 説明 |
geo | int | ジオメトリのインデックス |
pts[] | int[] | 四面体を形成する4つのポイントのインデックス配列 |
intype | string | 拘束タイプ |
diff | float | 現在の長さからrest長での符号付き距離 |
plasticrate | float | 塑性流動速度 |
plasticthreshold | float | 塑性変形が発生する閾値 |
plastichardening | float | 塑性変形による硬化係数 |
dt | float | 時間ステップ |
restlength | float | rest状態における長さ |
restvector | vector4 | rest状態におけるベクトル |
restmatrix | matrix3 | rest状態における行列 |
stiffness | float | 剛性値 |
// 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
であったときに、最初の配列要素を返す
引数名 | 型 | 説明 |
intype | string | 拘束タイプ |
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
であったときに、最初以外の配列要素を返す
引数名 | 型 | 説明 |
intype | string | 拘束タイプ |
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
アトリビュートを指定されたモード(最小・最大・平均・乗算)で累積させる
引数名 | 型 | 説明 |
type | string | 拘束タイプ |
ptgeo | int | 入力ジオメトリのインデックス |
inpts[] | int[] | 拘束に関連するポイントのインデックス配列 |
primgeo | string | プリミティブジオメトリを識別する文字列 |
targetprim | int | ターゲットプリミティブのインデックス |
uv | vector | プリミティブのUV座標 |
attr | string | スケールに影響する属性名 |
valscale | float | スカラー乗数 |
scalemode | string | スケーリングを計算するためのモードを示す文字列で、"value"、"attribvalue"、または "attrib"のいずれか |
promotion | string | プロモーションモードを示す文字列で、"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 値へ変換
引数名 | 型 | 説明 |
val | float | カラーマッピングを計算するための入力値 |
minval | float | 値の範囲の最小値 |
maxval | float | 値の範囲の最大値 |
vector
falseColor(const float val, minval, maxval)
{
return hsvtorgb(0.7 * (1 - fit(val, minval, maxval, 0, 1)), 1, 1);
}
weldTarget
接合の目標となるポイント番号の取得
引数名 | 型 | 説明 |
geo | int | ジオメトリのインデックス |
ptnum | int | ジオメトリ内のポイント番号 |
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
(応力)を計算
引数名 | 型 | 説明 |
type | string | 拘束タイプ |
Lin | vector | 力を表すベクトル |
dt | float | 時間ステップ |
normalize | int | 正規化を行うかどうかを指定するフラグ(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
(応力)の最大値を返す
引数名 | 型 | 説明 |
ptgeo | int | ジオメトリのインデックス |
congeo | int | 拘束ジオメトリのインデックス |
ptnum | int | ストレスを計算するポイント番号 |
types | string[] | 計算に使用する拘束タイプの配列 |
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 間における長さや角度の差分またはノルムを計算
引数名 | 型 | 説明 |
geo | int | 入力ジオメトリのインデックス |
pts | int[] | 関連するポイントのインデックスを含む配列 |
intype | string | 拘束タイプ |
restlength | float | 拘束のrest状態における長さ |
restvector | vector4 | 拘束のrest状態における4次元ベクトル |
restdir | vector | 拘束のrest状態におけるベクトル方向 |
targetpath | string | ターゲットジオメトリへのパス |
targetprim | int | ターゲットプリミティブのインデックス |
restmatrix | matrix3 | rest状態における変換行列 |
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
与えられた拘束タイプに基づいて、restlength
やrestvector
などの値を更新
引数名 | 型 | 説明 |
geo | int | 入力ジオメトリのインデックス |
pts | int[] | 関連するポイントのインデックスを含む配列 |
type | string | 拘束タイプ |
restlength | float | 拘束のrest状態における長さ |
restvector | vector4 | 拘束のrest状態における4次元ベクトル |
restdir | vector | 拘束のrest状態におけるベクトル方向 |
targetpath | string | ターゲットジオメトリへのパス |
targetprim | int | ターゲットプリミティブのインデックス |
restmatrix | matrix3 | 拘束のrest状態における変換行列 |
indropoff | float | 剛性の減衰を制御するドロップオフ値 |
stiffnessorig | float | オリジナルの剛性値 |
stiffnessmin | float | 剛性の最小値この値は、剛性が減少する際の下限として使用される |
// 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 を考慮した場合の剛性値を計算
引数名 | 型 | 説明 |
geo | int | ジオメトリのインデックス |
pts | int[] | 関連するポイントのインデックスを含む配列 |
type | string | 拘束タイプ |
restlength | float | 拘束のrest状態における長さ |
restvector | vector4 | 拘束のrest状態における次元ベクトル |
restdir | vector | 拘束のrest状態におけるベクトル方向 |
targetpath | string | ターゲットジオメトリへのパス |
targetprim | int | ターゲットプリミティブのインデックス |
restmatrix | matrix3 | 拘束のrest状態における変換行列 |
indropoff | float | 剛性の減衰を制御するドロップオフ値 |
stiffnessorig | float | オリジナルの剛性値 |
stiffnessmin | float | 剛性の最小値この値は、剛性が減少する際の下限として使用される |
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 状態におけるメトリックを計算
引数名 | 型 | 説明 |
type | string | 拘束タイプ |
restlength | float | 拘束のrest状態における長さ |
restvector | vector4 | 拘束のrest状態における4次元ベクトル |
restmatrix | matrix3 | 拘束の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
指定タイプにおける拘束ジオメトリの変化量を計算
引数名 | 型 | 説明 |
ptgeo | int | ポイントジオメトリのインデックス |
congeo | int | 拘束ジオメトリのインデックス |
prim | int | 拘束プリミティブのインデックス |
type | string | 拘束タイプ |
metric | string | 計算するメトリック |
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
指定タイプにおける拘束ジオメトリの最大変化量を計算
引数名 | 型 | 説明 |
ptgeo | int | ポイントジオメトリのインデックス |
congeo | int | 拘束ジオメトリのインデックス |
ptnum | int | ポイント番号 |
types[] | string[] | 評価する拘束タイプのリスト |
metric | string | 計算するメトリック |
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 座標に基づいて、織り方向のスケーリング値を計算
引数名 | 型 | 説明 |
geo | int | ジオメトリのインデックス |
pts[] | int[] | ポイント番号の配列 |
warp | float | 縦方向のスケール値 |
weft | float | 横方向のスケール値 |
shear | float | 斜め方向のスケール値 |
materialuv | string | UVの名前 |
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 に使用されているポイント配列を返す
引数名 | 型 | 説明 |
geo | string | ジオメトリの名前 |
pts[] | int[] | ポイント番号の配列 |
weldattrib | string | weldの名前デフォルト値は-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 座標を計算
引数名 | 型 | 説明 |
geo | string | 指定ジオメトリ |
grp | string | プリミティブグループの名前 |
goalpos | vector | 目標位置 |
type | int | プリミティブのタイプID-1の場合は、すべてのプリミティブタイプが該当 |
weldattrib | string | weldの名前 |
curprim | int | 現在のプリミティブ番号 |
curuv | vector | 現在の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
から三角形までの最も近いポイント座標を計算し、頂ポイントまたは辺の番号とバリセントリック座標を計算
Real-Time Collision Detection" by Ericson
Real-Time Collision Detection" by Ericson
引数名 | 型 | 説明 |
p | vector | 対象となるポイントp |
a | vector | 三角形の頂ポイントAの座標 |
b | vector | 三角形の頂ポイントBの座標 |
c | vector | 三角形の頂ポイントCの座標 |
vert | int | 最も近い頂ポイントのインデックス |
edge | int | 最も近い辺のインデックス |
uv | vector | 最も近いポイントのバリセントリック座標 |
// 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
のラッパー関数であり、対応するポイント番号やハーフエッジを求める機能が追加されている
引数名 | 型 | 説明 |
geo | string | 指定ジオメトリ |
prim | int | 三角形プリミティブのインデックス |
pts | int[] | 三角形プリミティブの頂ポイントインデックス配列 |
p | vector | 対象のポイント座標 |
ptnum | int | 最も近い頂ポイントのインデックス |
hedge | int | 最も近いハーフエッジのインデックス |
uv | vector | 最も近いポイントのバリセントリック座標 |
// 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
三角ポリゴンであるかどうか判別
引数名 | 型 | 説明 |
geo | string | 指定ジオメトリ |
prim | int | プリミティブのインデックス |
pts | int[] | プリミティブの頂ポイントインデックスの配列 |
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
三角プリミティブを対象として、与えられたジオメトリ内で目標位置に最も近いポイントを取得
引数名 | 型 | 説明 |
geo | string | 指定ジオメトリ |
grp | string | 対象とするプリミティブグループ |
goalpos | vector | 目標位置 |
weldattrib | string | weldの名前 |
curprim | int | 現在のプリミティブのインデックス |
curuv | vector | 現在のプリミティブにおける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
引数名 | 型 | 説明 |
A | matrix3 | 回転を抽出するための入力行列 |
qin | vector4 | 以前のタイムステップや拘束解決からの回転を表すクォータニオン |
maxiter | int | アルゴリズムが収束するまでの最大繰り返し回数 |
// 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
カハンの加算アルゴリズムを利用してベクトルの和を計算
引数名 | 型 | 説明 |
v | vector | 累積和に加えるベクトル |
sum | vector | 現在の累積和を格納するベクトル |
c | vector | 誤差補正項を格納するベクトル |
// 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 行列の和を計算
引数名 | 型 | 説明 |
v | matrix3 | 累積和に加える3x3行列 |
sum | matrix3 | 現在の累積和を格納する3x3行列 |
c | matrix3 | 誤差補正項を格納する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 における重心を計算し、その最適な回転を求める
引数名 | 型 | 説明 |
geo | const int | 現在のジオメトリのインデックス |
congeo | const int | resst状態におけるジオメトリのインデックス |
pts[] | int array | 頂ポイントのインデックス配列 |
restcm | vector | resst状態における重心を格納する変数 |
cm | vector | 現在の重心 |
R | vector4 | 最適な回転を格納するクォータニオン |
// 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状態におけるポイントを更新
引数名 | 型 | 説明 |
geo | const int | 現在のジオメトリのインデックス |
congeo | const int | 休息状態のジオメトリのインデックス |
pts[] | int array | 頂点のインデックスの配列 |
inamount | const float | 更新量(長さ単位または比率) |
isratio | const int | 更新量が比率であるかどうかを示すフラグ(0: 長さ単位、1: 比率) |
outgeo | const 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拘束を対象として塑性変形における塑性流動量を計算し、拘束の剛性値を更新
引数名 | 型 | 説明 |
geo | const int | 現在のジオメトリのインデックス |
congeo | const int | rest状態におけるジオメトリのインデックス |
pts[] | int array | 頂点のインデックスの配列 |
plasticrate | const float | 塑性変形のレート |
plasticthreshold | const float | 塑性変形の閾値 |
plastichardening | const float | 塑性硬化係数 |
dt | const float | 時間ステップ |
Rin | const vector4 | 初期回転を表すクォータニオン |
stiffness | float | 剛性を格納する変数 |
outgeo | const 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
与えられた拘束タイプが拘束解決時にスムージングが行えるか判別
引数名 | 型 | 説明 |
---|---|---|
type | string | スムージングを調べる対象のタイプの文字列 |
// 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);
}