Как повернуть объект в Java 3D? - PullRequest
3 голосов
/ 26 августа 2009

У меня есть конус, который я нарисовал в 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);

Заранее спасибо за помощь!

Ответы [ 5 ]

3 голосов
/ 26 августа 2009

В данный момент я просто изучаю Java 3D, и, исходя из моих текущих знаний, методы вращения устанавливают преобразование на вращение только вокруг этой оси. Поэтому, если вы хотите выполнить вращение вокруг нескольких осей, вам нужно будет использовать второй 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 градусам.

Найти угол между вашей текущей ориентацией и вашей предполагаемой ориентацией не так уж сложно - вы можете использовать Vector3fs с помощью метода angle (). Вектор будет настроен с начальной ориентацией, а другой - по назначению. Тем не менее, это не говорит вам, в каких осях лежит угол. Для этого потребуется изучить векторы, чтобы увидеть, какие сегменты установлены. [конечно, может быть что-то, чего я в данный момент не знаю в API]

2 голосов
/ 26 августа 2009

Это не специфичный для 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

в этом первом столбце указан боковой вектор. Второй столбец вверх вектор. Третье направление и четвертое положение.

Логически мы можем видеть, что вектор (1, 0, 0, 0) указывает вдоль оси x (и, следовательно, является боковым вектором). Вектор (0, 1, 0, 0) указывает вдоль оси y (и, следовательно, является вектором вверх). Третий (0, 0, 1, 0) указывает вдоль оси Z (и, следовательно, является вектором направления). Четвертый (0, 0, 0, 1) указывает, что объекты не двигаются вообще.

Теперь предположим, что мы хотели повернуться вдоль оси X.

Очевидно, это означало бы, что у нас есть вектор (1, 0, 0, 0) для нашего вектора направления. Вверх по-прежнему будет (0, 1, 0, 0) и положение по-прежнему 0, 0, 0 1. Так, каков будет наш боковой вектор? Ну, логически это будет указывать вдоль оси Z. Но в какую сторону? Хорошо держите пальцы так, чтобы один палец указывал вперед, один в сторону, а другой вверх. Теперь поверните так, чтобы передний палец был направлен в том же направлении, что и боковой указательный палец. В какую сторону указывает указательный палец? Противоположное направление к исходному направлению указывает пальцем. Таким образом, матрица

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

В этот момент все выглядит немного сложнее. Достаточно просто взять произвольную позицию и произвольную точку, чтобы взглянуть на них (я назову их vPos и ​​vFocus). Достаточно просто сформировать вектор из vPos в vFocus путем вычитания vPos из vFocus (vFocus.x - vPos.x, vFocus.y - vPos.y, vFocus.z - vPos.z, vFocus.w - vPos.w) , Имейте в виду, что все позиции должны быть определены с помощью «1» в позиции «w», где все направления должны иметь «0». Это автоматически выполняется, когда вы выполняете вычитание выше, так как 1 в обоих ws отменит и оставит 0. В любом случае, теперь у нас есть вектор, указывающий из положения в направлении vFocus, мы назовем его vDir. К сожалению, он имеет длину разницы между vPos и ​​vFocus. Однако если мы разделим вектор vDir на его длину (vDir.x / length, vDir.y / length, vDir.z / length, vDir.w / length), то мы нормализуем его и получим направление общей длиной 1.

В этом ponit у нас теперь есть 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) вектором, но это должно работать для большинства случаев.

1 голос
/ 31 августа 2009

Я, наконец, понял, что хочу сделать, используя кватернионы, о которых я узнал здесь: 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);
    }
0 голосов
/ 22 августа 2013

вы можете дать вашему 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);
0 голосов
/ 26 августа 2009

Я думаю, что это должно сделать это:

coneTransform.rotX(Math.PI / 4);
coneTransform.rotY(Math.PI / 4);
...