Rotación de Arcball con Quaternions(usando iOS GLKit)
opengl-es (2)
Parece que hay algunos problemas aquí.
Usted dice que está utilizando [x, y] para desplazarse, pero parece que los está usando para lanzar y guiñar. Para mí, al menos, la panorámica es la traducción, no la rotación.
A menos que me falta algo, también parece que reemplazas toda la rotación cada vez que intentas actualizarla. Gira un vector por el inverso de la rotación actual y luego crea un cuaternión a partir de ese vector y un cierto ángulo. Creo que esto es equivalente a crear el quaternion del vector original y luego rotarlo por la rotación actual inversa. Entonces tienes
q_e''*q_up
. Luego multiplicas eso con la rotación actual, que daq_e*q_e''*q_up = q_up
. La rotación actual se cancela. Esto no parece ser lo que quieres.Todo lo que necesitas hacer es crear un nuevo cuaternión a partir del eje y ángulo y luego multiplicarlo con el cuaternión actual. Si el nuevo cuaternión está a la izquierda, el cambio de orientación usará el marco local del ojo. Si el nuevo cuaternión está a la derecha, el cambio de orientación se realizará en el marco global. Creo que quieres:
self.rotationE = GLKQuaternionMultiply( GLKQuaternionMakeWithAngleAndVector3Axis(x*rate, up),self.rotationE);
Haga esto, sin la prerotación por inversión para los tres casos.
Nunca he usado el GLKit, pero es poco común extraer el ángulo del eje cuando se convierte de Quaternion a Matrix. Si el ángulo es cero, el eje no está definido. Cuando esté cerca de cero, tendrá inestabilidad numérica. Parece que debería usar
GLKMatrix4MakeWithQuaternion
y luego multiplicar la matriz resultante con su matriz de traducción y matriz de escala:GLKMatrix4 modelviewMatrix = GLKMatrix4Multiply( GLKMatrix4MakeTranslation(0.0f, 0.0f, -0.55f), GLKMatrix4MakeWithQuaternion( self.rotationE ) ); modelviewMatrix = GLKMatrix4Scale( modelviewMatrix, 0.5f, 0.5f, 0.5f );
Estoy buscando una implementación simple para la rotación de arcball en modelos 3D con cuaterniones, específicamente usando GLKit en iOS . Hasta ahora, he examinado las siguientes fuentes:
También he estado tratando de entender el código fuente y las matemáticas desde aquí y aquí . Puedo rotar mi objeto pero sigue saltando en ciertos ángulos, así que me temo que el bloqueo de cardán está en juego. Estoy usando reconocedores de gestos para controlar las rotaciones (los gestos de panoramización afectan al balanceo y la guiñada, los gestos de rotación afectan el tono). Adjunto mi código para el manejo del cuaternión y la transformación de la matriz de modelos.
Variables:
GLKQuaternion rotationE;
Manejo del cuaternión:
- (void)rotateWithXY:(float)x and:(float)y
{
const float rate = M_PI/360.0f;
GLKVector3 up = GLKVector3Make(0.0f, 1.0f, 0.0f);
GLKVector3 right = GLKVector3Make(1.0f, 0.0f, 0.0f);
up = GLKQuaternionRotateVector3(GLKQuaternionInvert(self.rotationE), up);
self.rotationE = GLKQuaternionMultiply(self.rotationE, GLKQuaternionMakeWithAngleAndVector3Axis(x*rate, up));
right = GLKQuaternionRotateVector3(GLKQuaternionInvert(self.rotationE), right);
self.rotationE = GLKQuaternionMultiply(self.rotationE, GLKQuaternionMakeWithAngleAndVector3Axis(y*rate, right));
}
- (void)rotateWithZ:(float)z
{
GLKVector3 front = GLKVector3Make(0.0f, 0.0f, -1.0f);
front = GLKQuaternionRotateVector3(GLKQuaternionInvert(self.rotationE), front);
self.rotationE = GLKQuaternionMultiply(self.rotationE, GLKQuaternionMakeWithAngleAndVector3Axis(z, front));
}
Modelview Matrix Transformation (Inside Draw Loop):
// Get Quaternion Rotation
GLKVector3 rAxis = GLKQuaternionAxis(self.transformations.rotationE);
float rAngle = GLKQuaternionAngle(self.transformations.rotationE);
// Set Modelview Matrix
GLKMatrix4 modelviewMatrix = GLKMatrix4Identity;
modelviewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, -0.55f);
modelviewMatrix = GLKMatrix4Rotate(modelviewMatrix, rAngle, rAxis.x, rAxis.y, rAxis.z);
modelviewMatrix = GLKMatrix4Scale(modelviewMatrix, 0.5f, 0.5f, 0.5f);
glUniformMatrix4fv(self.sunShader.uModelviewMatrix, 1, 0, modelviewMatrix.m);
Cualquier ayuda es muy apreciada, pero quiero mantenerla lo más simple posible y atenerme a GLKit.
Hace poco me preguntaron un poco más sobre la implementación resultante de este problema, ¡así que aquí está!
- (void)rotate:(GLKVector3)r
{
// Convert degrees to radians for maths calculations
r.x = GLKMathDegreesToRadians(r.x);
r.y = GLKMathDegreesToRadians(r.y);
r.z = GLKMathDegreesToRadians(r.z);
// Axis Vectors w/ Direction (x=right, y=up, z=front)
// In OpenGL, negative z values go "into" the screen. In GLKit, positive z values go "into" the screen.
GLKVector3 right = GLKVector3Make(1.0f, 0.0f, 0.0f);
GLKVector3 up = GLKVector3Make(0.0f, 1.0f, 0.0f);
GLKVector3 front = GLKVector3Make(0.0f, 0.0f, 1.0f);
// Quaternion w/ Angle and Vector
// Positive angles are counter-clockwise, so convert to negative for a clockwise rotation
GLKQuaternion q = GLKQuaternionIdentity;
q = GLKQuaternionMultiply(GLKQuaternionMakeWithAngleAndVector3Axis(-r.x, right), q);
q = GLKQuaternionMultiply(GLKQuaternionMakeWithAngleAndVector3Axis(-r.y, up), q);
q = GLKQuaternionMultiply(GLKQuaternionMakeWithAngleAndVector3Axis(-r.z, front), q);
// ModelView Matrix
GLKMatrix4 modelViewMatrix = GLKMatrix4Identity;
modelViewMatrix = GLKMatrix4Multiply(modelViewMatrix, GLKMatrix4MakeWithQuaternion(q));
}
Espero que lo aproveches bien :)