これは、数学/3D ジオメトリ愛好家にとって大きな問題です。前もって感謝します。
概要
空間でねじれたスプライン曲線の周りに面を押し出して作成した図があります。スプラインと「整列」するように、曲線の特定のセグメントでスプライン パスに沿って方向付けられた「ループ」(トーラス) を配置しようとしています。つまり、トーラスの幅は、指定された押し出しセグメントのスプライン パスに平行であり、高さは選択された面に垂直です (下の図を参照)。
私が知っているデータ:
フィギュアの顔の1つが与えられます。そこから、その面の重心 (中心点)、それを構成する頂点、周囲の面、および面の法線ベクトルも収集できます。
現在の (機能していない) ソリューションの結果:
クリックした顔の重心の周りにトーラス ループを正しく作成できます。ただし、顔に「合わせる」ために適切に回転しません。以下で、それらがどのように「オフ」に見えるかを確認してください。
これは、その周りのマテリアルを含む写真です。
これがワイヤフレーム モードの写真です。押し出しセグメントがはっきりと見えます。
現在の (動作していない) 方法論:
私は2つの計算をしようとしています。まず、2 つの平面 (選択した面と原点の水平面) の間の角度を計算しています。次に、原点での面と垂直面の間の角度を計算しています。これらの 2 つの角度を使用して、2 つの回転を行います。トーラス上で X 回転と Y 回転を行い、正しい向きになるようにします。トーラスを可変量で回転させていますが、希望する場所ではありません。
数式:
上記を行う際に、次を使用して、法線ベクトルを使用して 2 つの平面間の角度を計算しています。
法線ベクトル 1 と法線ベクトル 2 の内積 = ベクトル 1 の大きさ * ベクトル 2 の大きさ * Cos (シータ)
または:
(n1)(n2) = || n1 || * || n2 || * cos (シータ)
または:
角度 = ArcCos { ( n1 * n2 ) / ( || n1 || * || n2 || ) }
ベクトルの大きさを決定する式は次のとおりです。
コンポーネントの二乗和の平方根。
または:
Sqrt { n1.x^2 + n1.y^2 + n1.z^2 }
また、「原点」平面の法線ベクトルには次のものを使用しています。
水平面の法線ベクトル: (1, 0, 0)
垂直面の法線ベクトル: (0, 1, 0)
上記の法線ベクトルについて何度か考えてみましたが、正しいと思いますか?
現在の実装:
以下は、私が現在それを実装するために使用しているコードです。どんな考えでも大歓迎です。平面間の角度を計算しようとする際に間違ったアプローチを取っていると感じています。アドバイス/アイデア/提案は大歓迎です。ご提案いただきありがとうございます。
角度を計算する関数:
this.toRadians = function (face, isX)
{
//Normal of the face
var n1 = face.normal;
//Normal of the vertical plane
if (isX)
var n2 = new THREE.Vector3(1, 0, 0); // Vector normal for vertical plane. Use for Y rotation.
else
var n2 = new THREE.Vector3(0, 1, 0); // Vector normal for horizontal plane. Use for X rotation.
//Equation to find the cosin of the angle. (n1)(n2) = ||n1|| * ||n2|| (cos theta)
//Find the dot product of n1 and n2.
var dotProduct = (n1.x * n2.x) + (n1.y * n2.y) + (n1.z * n2.z);
// Calculate the magnitude of each vector
var mag1 = Math.sqrt (Math.pow(n1.x, 2) + Math.pow(n1.y, 2) + Math.pow(n1.z, 2));
var mag2 = Math.sqrt (Math.pow(n2.x, 2) + Math.pow(n2.y, 2) + Math.pow(n2.z, 2));
//Calculate the angle of the two planes. Returns value in radians.
var a = (dotProduct)/(mag1 * mag2);
var result = Math.acos(a);
return result;
}
トーラス ループを作成および回転する関数:
this.createTorus = function (tubeMeshParams)
{
var torus = new THREE.TorusGeometry(5, 1.5, segments/10, 50);
fIndex = this.calculateFaceIndex();
//run the equation twice to calculate the angles
var xRadian = this.toRadians(geometry.faces[fIndex], false);
var yRadian = this.toRadians(geometry.faces[fIndex], true);
//Rotate the Torus
torus.applyMatrix(new THREE.Matrix4().makeRotationX(xRadian));
torus.applyMatrix(new THREE.Matrix4().makeRotationY(yRadian));
torusLoop = new THREE.Mesh(torus, this.m);
torusLoop.scale.x = torusLoop.scale.y = torusLoop.scale.z = tubeMeshParams['Scale'];
//Create the torus around the centroid
posx = geometry.faces[fIndex].centroid.x;
posy = geometry.faces[fIndex].centroid.y;
posz = geometry.faces[fIndex].centroid.z;
torusLoop.geometry.applyMatrix(new THREE.Matrix4().makeTranslation(posx, posy, posz));
torusLoop.geometry.computeCentroids();
torusLoop.geometry.computeFaceNormals();
torusLoop.geometry.computeVertexNormals();
return torusLoop;
}