Como girar um objeto em Java 3D?
Pergunta
Eu tenho um Cone eu desenhei em Java 3D com o seguinte código:
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);
Suponha que eu tenho o cone sentado no ponto (1,1,1) e eu quero a ponta do cone para apontar para baixo uma linha imaginária que atravessa (0,0,0) e (1,1,1). .. como eu posso fazer isso?
Aqui está um exemplo do que eu tenho tentado:
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);
Agradecemos antecipadamente por toda a ajuda!
Solução 3
Eu finalmente descobri o que eu queria fazer usando Quaternions, o que eu aprendi sobre aqui: http://www.cs.uic.edu/~jbell/Courses/Eng591_F1999/outline_2.html Aqui está a minha solução.
Criando o cone:
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);
}
Agora, quando eu quero rodar o cone de ponto em uma determinada direção especificada como o vetor do ponto (0,0,0) a (direction.x, direction.y, direction.z), eu uso:
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);
}
Outras dicas
Eu estou aprendendo Java 3D mim no momento, e do meu conhecimento atual, os métodos de rotação definir a transformar a uma rotação em torno deste eixo somente.
Portanto, se você deseja realizar rotações em torno de vários eixos, então você vai precisar usar um segundo Transform3D.
ou seja:
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.
Quanto à razão para Math.PI, isso é porque ele utiliza radianos em vez de graus, onde Math.PI é equivalente a 180 graus.
Encontrar o ângulo entre sua orientação atual e sua orientação pretendida não é muito difícil - você poderia usar Vector3fs, com o método do ângulo (). Um vector seria criado com a orientação inicial, e uma outra no que se destina. No entanto, isso não lhe diz em que os eixos das mentiras ângulo. Isso exigiria análise dos vetores para ver quais segmentos estão definidos. [É claro, pode haver algo que eu estou atualmente desconhece na API]
Esta não é uma resposta específica JAVA3D.
De um modo geral uma matriz pode ser construída de tal modo que existem 4 vectores que o descrevem.
1) Um lado (ou lateral) vector
2) Um vetor
3) Um vector de direcção
4) A posição de um
Cada linha de uma matriz 4x4.
Assim, para uma matriz de identidade simples, temos a seguinte matriz (vou definir uma grande matriz de coluna, para uma grande matriz de linha tudo o que você precisa fazer é trocar os índices de matriz em torno de tal forma que a linha 2 col 3 torna-se linha 3 col 2 em toda a matriz).
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1
nesta primeira coluna é o vector de lado. A segunda coluna o vector acima. A terceira direcção e a quarta posição.
Logicamente, podemos ver que o vector de (1, 0, 0, 0) pontos ao longo do eixo x (e, portanto, é o vector de lado). O vector de (0, 1, 0, 0) pontos ao longo do eixo y (e, portanto, é o vector acima). O terceiro (0, 0, 1, 0) pontos ao longo do eixo Z (e, portanto, é o vector de direcção). A quarta (0, 0, 0, 1) indica que os objectos não se move de todo.
Agora, vamos dizer que queríamos rosto ao longo do eixo-X.
Obviamente, isso significaria que temos um vector de (1, 0, 0, 0) para o nosso vetor de direção. -Se ainda seria (0, 1, 0, 0) e posição ainda 0, 0, 0 1. Então, o que seria o nosso vector lado ser? Bem, logicamente seria apontar ao longo do eixo z. Mas de que maneira? Bem segurar os dedos de tal forma que um dedo aponta para a frente, um para o lado e uma para cima. Agora gire de modo que o dedo para a frente está virada na mesma direcção que o dedo lado apontador. Que maneira é o lado Apontando o dedo Apontando agora? A direção oposta ao dedo originais direção apontador. Assim, a matriz é
0 0 1 0
0 1 0 0
-1 0 0 0
0 0 0 1
Neste ponto coisas aparentemente se um pouco mais complicado. É bastante simples de tomar uma posição arbitrária e um ponto arbitrário olhada (vou chamá-los vPos e vFocus). É bastante fácil para formar um vector de vPos para vFocus subtraindo vPos de vFocus (vFocus.x - vPos.x, vFocus.y - vPos.y, vFocus.z - vPos.z, vFocus.w - vPos.w) . Tenha em mente todas as posições devem ser definidos com um '1' na posição w, onde todas as direções deve ter um '0'. Esta é tirada automaticamente cuidado de quando você faz a subtração acima como 1 em ambos os ws vai anular e deixar 0. De qualquer forma, agora temos um vetor apontando a partir da posição em direção vFocus vamos chamá-lo VDIR. Infelizmente, tem o comprimento da diferença entre vPos e vFocus. No entanto, se dividirmos o vetor VDIR pelo seu comprimento (vDir.x / comprimento, vDir.y / comprimento, vDir.z / comprimento, vDir.w / comprimento) então nós normalize isso e temos um o sentido com um comprimento total de 1.
Neste ponit agora temos a nossa 3ª e 4ª colunas de nossa matriz. Agora, vamos assuem up ainda é (0, 1, 0, 0) ou VUP. Podemos assumir que o CrossProduct da direcção e VUP irá produzir um vector que é perpendicular (e também da unidade de comprimento) para o plano formado pela VDIR e VUP. Isso nos dá o nosso vector lado ou VLAT. Agora .. fizemos tipo de assumir o vector de modo que não é estritamente correto. Agora podemos calcular exatamente tomando o produto cruzado de VLAT e VDIR e temos todos os 4 vetores.
A matriz final é, assim, definida como se segue
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
Isto não é estritamente a resposta completa como você vai ter problemas como você olhar para um ponto perto de sua (0, 1, 0, 0) vector mas que deve trabalhar para a maioria casos.
Eu acho que isso deve fazê-lo:
coneTransform.rotX(Math.PI / 4);
coneTransform.rotY(Math.PI / 4);
Você pode dar o seu Transform3D uma matriz de rotação. você pode obter uma matriz de rotação usando a calculadora matriz de rotação on-line: http://toolserver.org/~dschwen /tools/rotationmatrix.html aqui está o meu exemplo:
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);