3

次のコードを使用して Java 3D で描いた円錐があります。

Cone cone = new Cone(2f, 3f);

Transform3D t3d = new Transform3D();
TransformGroup coneTransform = new TransformGroup(t3d);
coneTransform.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);

t3d.setTranslation(new Vector3f(0f,0f,0f);
coneTransform.setTransform(t3d);
coneTransform.addChild(cone);

this.addChild(coneTransform);

円錐が点 (1,1,1) にあり、円錐の先端が (0,0,0) と (1,1,1) を通る仮想線を下に向けるようにしたいとします...どのように私はこれを行うことができますか?

これが私が試してきたことの例です:

Transform3D t3d = new Transform3D();  

Vector3f direction = new Vector3f(1,2,1);    

final double angleX = direction.angle(new Vector3f(1,0,0));
final double angleY = direction.angle(new Vector3f(0,1,0));
final double angleZ = direction.angle(new Vector3f(0,0,1));

t3d.rotX(angleX);
t3d.rotY(angleY);
t3d.rotZ(angleZ);

t3d.setTranslation(direction);

coneTransform.setTransform(t3d);

すべての助けを前もってありがとう!

4

5 に答える 5

3

私はちょうど今、Java 3D を自分で学んでいます。私の現在の知識から、回転メソッドは変換をその軸のみを中心とした回転に設定します。したがって、複数の軸を中心に回転させたい場合は、2 つ目の Transform3D を使用する必要があります。
すなわち:

Transform3D rotation = new Transform3D();
Transform3D temp = new Transform3D();

rotation.rotX(Math.PI/2);
temp.rotZ(Math.PI/2);
rotation.mul(temp); // multiply the 2 transformation matrices together.

Math.PI の理由については、度の代わりにラジアンを使用するためです。Math.PI は 180 度に相当します。

現在の向きと意図した向きの間の角度を見つけるのはそれほど難しくありません。angle() メソッドで Vector3fs を使用できます。ベクターは最初の向きで設定され、別の向きで設定されます。ただし、これは角度がどの軸にあるかはわかりません。これを行うには、ベクトルを調べて、どのセグメントが設定されているかを確認する必要があります。【もちろん、現在のAPIで気づいていないこともあるかもしれません】

于 2009-08-25T21:27:57.630 に答える
2

これは java3D 固有の回答ではありません。

一般に、マトリックスは、それを表す 4 つのベクトルが存在するように作成できます。

1) サイド (またはラテラル) ベクトル
2) アップ ベクトル
3) 方向ベクトル
4) 位置

4x4 マトリックスの各行。

したがって、単純な単位行列の場合、次の行列があります (列優先行列を定義します。行優先行列の場合は、行 2 列 3 が行 3 列 2 になるように行列インデックスを交換するだけです。マトリックス)。

1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1

この最初の列はサイド ベクトルです。2 番目の列はアップ ベクトルです。3 番目は方向、4 番目は位置です。

論理的には、ベクトル (1, 0, 0, 0) が x 軸に沿っていることがわかります (つまり、サイド ベクトルです)。ベクトル (0, 1, 0, 0) は y 軸に沿ってポイントします (つまり、アップ ベクトルです)。3 番目の (0, 0, 1, 0) は、Z 軸に沿ったポイントです (つまり、方向ベクトルです)。4 番目 (0, 0, 0, 1) は、オブジェクトがまったく動かないことを示します。

ここで、X 軸に沿って面したいとしましょう。

明らかに、これは方向ベクトルに (1, 0, 0, 0 ) のベクトルがあることを意味します。Up は (0, 1, 0, 0) のままで、position は 0, 0, 0 1 のままです。論理的には、それは z 軸に沿って指します。しかし、どの方法ですか?1 本の指が前方、もう 1 本が横、もう 1 本が上を向くように指を持ちます。次に、前方の指が側面の人差し指と同じ方向を向くように回転させます。横の人差し指は今どちらを指していますか?本来の向きと逆向きの指さし。したがって、行列は

 0 0 1 0
 0 1 0 0
-1 0 0 0
 0 0 0 1

この時点で、事態は少し複雑になっているように見えます。任意の位置と任意の点を見るだけで十分簡単です (私はそれらを vPos と vFocus と呼びます)。vFocus (vFocus.x - vPos.x、vFocus.y - vPos.y、vFocus.z - vPos.z、vFocus.w - vPos.w) から vPos を減算することにより、vPos から vFocus へのベクトルを形成するのは簡単です。 . すべての位置は、すべての方向が「0」を持つ必要がある w 位置の「1」で定義される必要があることに注意してください。上記の減算を行うと、両方の ws の 1 がキャンセルされて 0 のままになるため、これは自動的に処理されます。残念ながら、vPos と vFocus の差の長さがあります。ただし、vDir ベクトルをその長さで割ると (vDir.x / 長さ、vDir.それを正規化すると、全長が 1 の方向が得られます。

この時点で、行列の 3 番目と 4 番目の列ができました。ここで、まだ (0, 1, 0, 0) または vUp であると仮定します。方向と vUp の外積は、vDir と vUp によって形成される平面に垂直な (単位長さの) ベクトルを生成すると仮定できます。これにより、サイド ベクトルまたは vLat が得られます。さて..アップベクトルを仮定したので、厳密には正しくありません。vLat と vDir の外積を取ることで正確に計算できるようになり、4 つのベクトルすべてが得られました。

したがって、最終的な行列は次のように定義されます。

vLat.x vUp.x vDir.x vPos.x
vLat.y vUp.y vDir.y vPos.y
vLat.z vUp.z vDir.z vPos.z
vLat.w vUp.w vDir.w vPos.w

(0, 1, 0, 0) ベクトルに近い点を見ると問題が発生するため、これは厳密には完全な答えではありませんが、ほとんどの場合はうまくいくはずです。

于 2009-08-25T20:47:55.543 に答える
1

ここで学んだクォータニオンを使用して、自分がやりたいことを最終的に理解しました: http://www.cs.uic.edu/~jbell/Courses/Eng591_F1999/outline_2.html

コーンの作成:

 private void attachCone(float size) {
        Cone cone = new Cone(size, size* 2);

        // The group for rotation
        arrowheadRotationGroup = new TransformGroup();
        arrowheadRotationGroup.
             setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        arrowheadRotationGroup.addChild(cone);

        // The group for positioning the cone
        arrowheadPositionGroup = new TransformGroup();
        arrowheadPositionGroup. 
              setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        arrowheadPositionGroup.addChild(arrowheadRotationGroup);

        super.addChild(arrowheadPositionGroup);
    }

ここで、点 (0,0,0) から (direction.x, direction.y, direction.z) へのベクトルとして指定された特定の方向を指すように円錐を回転させたい場合は、次のように使用します。

private final Vector3f yAxis = new Vector3f(0f, 1f, 0f);
private Vector3f direction; 

private void rotateCone() {
        // Get the normalized axis perpendicular to the direction 
        Vector3f axis = new Vector3f();
        axis.cross(yAxis, direction);
        axis.normalize();

        // When the intended direction is a point on the yAxis, rotate on x
        if (Float.isNaN(axis.x) && Float.isNaN(axis.y) && Float.isNaN(axis.z)) 
        {
            axis.x = 1f;
            axis.y = 0f;
            axis.z = 0f;
        }
        // Compute the quaternion transformations
        final float angleX = yAxis.angle(direction);
        final float a = axis.x * (float) Math.sin(angleX / 2f);
        final float b = axis.y * (float) Math.sin(angleX / 2f);
        final float c = axis.z * (float) Math.sin(angleX / 2f);
        final float d = (float) Math.cos(angleX / 2f);

        Transform3D t3d = new Transform3D();
        Quat4f quat = new Quat4f(a, b, c, d);
        t3d.set(quat);
        arrowheadRotationGroup.setTransform(t3d);

        Transform3D translateToTarget = new Transform3D();
        translateToTarget.setTranslation(this.direction);
        arrowheadPositionGroup.setTransform(translateToTarget);
    }
于 2009-08-31T14:18:59.160 に答える
0

私はこれがそれを行うべきだと思います:

coneTransform.rotX(Math.PI / 4);
coneTransform.rotY(Math.PI / 4);
于 2009-08-25T20:29:34.753 に答える
0

Transform3D に回転行列を与えることができます。オンラインで回転行列計算機を使用して回転行列を取得できます: http://toolserver.org/~dschwen/tools/rotationmatrix.htmlこれが私の例です:

    Matrix3f mat = new Matrix3f(0.492403876506104f, 0.586824088833465f,
            -0.642787609686539f, 0.413175911166535f, 0.492403876506104f,
            0.766044443118978f, 0.766044443118978f, -0.642787609686539f, 0f);

    Transform3D trans = new Transform3D();

    trans.set(mat);
于 2013-08-21T22:46:47.703 に答える