6
\$\begingroup\$

I have an object on my screen which is presented rotated and panned, But i have 2 problems regarding the z axis rotations. It's a bit tricky to explain so i uploaded 2 videos to describe each problem.

1) Reverse rotation : After rotating the object around the x axis, the z rotations are being reversed and not as it should be.

2) Wrong Z axis rotation : Again, After rotating the object around the x axis, i'm trying to rotate the object around the z axis and the rotation results in a different axis rotations.

I do believe the video's describe the problems well.

EDIT: Second attempt

As kindly explained by the user @Fault, i understood the problems i was facing with. So i tried to solve those by just rotating the projection matrix around the z axis, which seemed to be working, but it doesn't.

Since i am rotating the model's axis, I get this problem (video). the issue appears in the 23'd seconds, while i'm demonstrating how it works. As can been seen, when the z rotation causes a wrong x and y rotations.

I do understand that i must likely have to move these rotations to world view and not model view, the thing is i'm not really sure how to do that.

Here is the relevant code:

Render function:

{
...

    CC3GLMatrix *projection = [CC3GLMatrix matrix];
    float h = 4.0f * self.frame.size.height / self.frame.size.width;
    [projection populateFromFrustumLeft:-2 andRight:2 andBottom:-h/2 andTop:h/2 andNear:4 andFar:100];
    [projection rotateByZ:zRotationEnd];
    glUniformMatrix4fv(_projectionUniform, 1, 0, projection.glMatrix);

    [modelView populateFromTranslation:_currentPan];
    [modelView rotateBy:_currentRotation];


    glUniformMatrix4fv(_modelViewUniform, 1, 0, modelView.glMatrix);
...
}

X and Y rotations:

- (void) rotateAroundX:(float) x andY:(float) y newRotate:(BOOL) isNewRotate
{
    if (isNewRotate) {
        rotationStart = CC3VectorMake(0.0, 0.0, 0.0);
    }

    int rotationDirection = ceil(zRotationEnd/90);
    if (rotationDirection % 4 == 2 || rotationDirection % 4 == 3) {
        rotationEnd.x = rotationEnd.x - (x-rotationStart.x);
        rotationEnd.y = rotationEnd.y - (y-rotationStart.y);
    } else {
        rotationEnd.x = rotationEnd.x + (x-rotationStart.x);
        rotationEnd.y = rotationEnd.y + (y-rotationStart.y);
    }



    rotationStart.x = x;
    rotationStart.y = y;
    _currentRotation = CC3VectorMake(rotationEnd.y, rotationEnd.x, 0);
    NSLog(@"Current x is: %f y is: %f z is: %f",_currentRotation.x,_currentRotation.y,zRotationEnd);

}

Z rotations:

- (void) rotateAroundZ:(float) z newRotate:(BOOL) isNewRotate
{
    if (isNewRotate) {
        zRotationStart = 0;
    }
    zRotationEnd = zRotationEnd - (z - zRotationStart);
    zRotationStart = z;
}

And the vertex shader:

attribute vec4 Position;
attribute vec4 SourceColor;

varying vec4 DestinationColor;

uniform mat4 Projection;
uniform mat4 Modelview;

attribute vec2 TexCoordIn;
varying vec2 TexCoordOut;

void main(void) {
    DestinationColor = SourceColor;
    gl_Position = Projection * Modelview * Position;
    TexCoordOut = TexCoordIn;
}

I would really like to get this right, so any help will be appreciated.

Cheers!

\$\endgroup\$
  • 2
    \$\begingroup\$ +1 for using videos to illustrate the problem. Regarding the first issue, it's an easy fix: when z axis is positive, rotate in one direction, when negative, rotate in the other direction. The second issue stems from the fact that axial rotations aren't commutative. A rotation about the x axis, then the z axis, isn't the same as a rotation about the z axis and then the x axis. It's often easier to actually rotate the camera about the model (with polar coordinates), than keep the camera stationary and rotate the model. (I'd give an answer, if I wasn't short on time). \$\endgroup\$ – Fault Mar 5 '14 at 1:47
  • \$\begingroup\$ Thanks a lot for the hints Fault! The first problem was solved, and yeah it was pretty easy. about the second one, i'm having some trouble figuring it out, do you have examples or tutorials about how to do that? currently i'm moving the ׳projection׳ matrix with the rotations i had before (the _currentRotation CC3 vector). But as expected, the results are not good and the x & y rotations are not 'focusing' on the object itself, its just being panned and moved the screen - quite weirdly i must say. i another video is needed, i will upload it. Thanks once again! \$\endgroup\$ – Itzik984 Mar 6 '14 at 14:26
  • \$\begingroup\$ And BTW, i would really love to hear if theres an option solving the second problem without moving the camera, because that could be an opening to a whole variety of other bugs :) \$\endgroup\$ – Itzik984 Mar 6 '14 at 14:35
  • \$\begingroup\$ Further considering your problem: when you are rotating, you're rotating not only the vertices of the model, but the axes of the model as well. So a rotation of 90 degrees about the x axis would result in the z axis pointing straight up or down. You should be using the world axes for the rotation, not the model's axes, to avoid this. Now where in your code the problem is occurring, I cannot say... \$\endgroup\$ – Fault Mar 6 '14 at 22:41
  • \$\begingroup\$ Just added some edits and bounty to this question :) just thought to update you and see if you have an answer that pops in your head... \$\endgroup\$ – Itzik984 Mar 8 '14 at 14:09
1
\$\begingroup\$

Since you have already solved the first problem, I will only address the second problem

The code you have does not really show where you generate the model, view & projection matrices, so it is difficult to exactly pin-point the problem position for you

You should maintain separate View & Projection matrices. If you use a library such as glm, which is fully compatible with iOS, you can easily calculate your view matrix

glm::vec3 cameraPosition = glm::vec3(cam_x_position, cam_y_position, cam_z_position);
glm::vec3 cameraTarget = glm::vec3(cam_x_target, cam_y_target, cam_z_target);
glm::vec3 cameraUp = glm::vec3(0,0,1);
glm::vec3 cameraDirection = glm::normalize(cameraPosition-cameraTarget);
glm::vec3 cameraRight = glm::cross(cameraDirection, cameraUp);
glm::mat4 view_matrix = glm::lookAt(cameraPosition, cameraTarget, cameraUp);

and your projection matrix

float lens_angle = 45.0f;
float aspect_ratio = 1.0 * (window_width / window_height);
float near_clipping_plane = 0.1f;
float far_clipping_plane = 100.0f;
glm::mat4 projection_matrix = glm::perspective(lens_angle, aspect_ratio, near_clipping_plane, far_clipping_plane);

PS: GLM is also Opensource, so if you want to take a look at how it is implemented and do it yourself, you can definitely do so

When you have your view & projection matrices (which are indifferent for your entire world) the thing you want to be modifying per each model is, as you'd expect, the model matrix

glm::mat4 Entity::getPositionMatrix() {
    return glm::translate(glm::mat4(1.0f), position);
}

glm::mat4 Entity::getRotationMatrix() {
  glm::mat4 rotation_x = glm::rotate(glm::mat4(1.0f), x_angle, glm::vec3(1.0f, 0.0f, 0.0f));
  glm::mat4 rotation_y = glm::rotate(glm::mat4(1.0f), y_angle, glm::vec3(0.0f, 1.0f, 0.0f));
  glm::mat4 rotation_z = glm::rotate(glm::mat4(1.0f), z_angle, glm::vec3(0.0f, 0.0f, 1.0f));
  glm::mat4 rotation = rotation_x * rotation_y * rotation_z;
  return rotation;
}

glm::mat4 Entity::getModelMatrix() {
    return getPositionMatrix() * getRotationMatrix();
}

And then simply pass in the model matrix (along with view & projection matrices) to the vertex shader, and you can do the multiplication there (bonus speed boost for multiplying on the GPU might occur)

uniform mat4 model; 
uniform mat4 view;
uniform mat4 projection;

.... 

//in shader body
mat4 mvp = projection * view * model;
gl_Position = mvp * vec4(vertex_position, 1.0);

This way, you will update your x, y & z angle rotations (around their respective axes) in as you'd expect them in the model space (If I understand correctly, feeding them in from the pan / rotation gesture values), and the matrix calculation / multiplication will handle the translation for you

Hope this helps

If you wanna take a more full look at this code in action, you can checkout a small sandbox I'm building (for other purposes really) that has this code in action

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.