PDA

View Full Version : Cube squeezed while rotating, using GLKit

fredikk
10-01-2013, 01:29 AM
So I am trying to draw and rotate a cube using GLKit on an iPad. My problem is that as the cube rotates it seems as the aspect ratio changes with it, squeezing it as it rotates. To be more precise, the face of the cube on the starting position has a ratio of 1/2 (width/height). Lets say A is the base of the cube and B is the height(we do not care about the depth right now, although the effect I am explaining occurs there as well). So at the starting position A/B=1/2. As it turns clockwise it gets squeezed, side A decreases and side B increases, so after a 90 degrees clockwise rotation(anticlockwise has the same effect) the ratio A/B is 2/1.
Some code...

The cube vertices:

+ (void)initialize {
if (!initialized) {
vertices[0] = GLKVector3Make(-0.5, -0.5, 0.5); // Left bottom front
vertices[1] = GLKVector3Make( 0.5, -0.5, 0.5); // Right bottom front
vertices[2] = GLKVector3Make( 0.5, 0.5, 0.5); // Right top front
vertices[3] = GLKVector3Make(-0.5, 0.5, 0.5); // Left top front
vertices[4] = GLKVector3Make(-0.5, -0.5, -0.5); // Left bottom back
vertices[5] = GLKVector3Make( 0.5, -0.5, -0.5); // Right bottom back
vertices[6] = GLKVector3Make( 0.5, 0.5, -0.5); // Right top back
vertices[7] = GLKVector3Make(-0.5, 0.5, -0.5); // Left top back

colors[0] = GLKVector4Make(1.0, 0.0, 0.0, 1.0); // Red
colors[1] = GLKVector4Make(0.0, 1.0, 0.0, 1.0); // Green
colors[2] = GLKVector4Make(0.0, 0.0, 1.0, 1.0); // Blue
colors[3] = GLKVector4Make(0.0, 0.0, 0.0, 1.0); // Black
colors[4] = GLKVector4Make(0.0, 0.0, 1.0, 1.0); // Blue
colors[5] = GLKVector4Make(0.0, 0.0, 0.0, 1.0); // Black
colors[6] = GLKVector4Make(1.0, 0.0, 0.0, 1.0); // Red
colors[7] = GLKVector4Make(0.0, 1.0, 0.0, 1.0); // Green

int vertexIndices[36] = {
// Front
0, 1, 2,
0, 2, 3,
// Right
1, 5, 6,
1, 6, 2,
// Back
5, 4, 7,
5, 7, 6,
// Left
4, 0, 3,
4, 3, 7,
// Top
3, 2, 6,
3, 6, 7,
// Bottom
4, 5, 1,
4, 1, 0,
};

for (int i = 0; i < 36; i++) {
triangleVertices[i] = vertices[vertexIndices[i]];
triangleColors[i] = colors[vertexIndices[i]];
}

effect = [[GLKBaseEffect alloc] init];
}
}

and the method that draws the cube in every frame:

- (void)draw
{
GLKQuaternion glkq=GLKQuaternionMake(-_quat.y,_quat.x,_quat.z,_quat.w);
GLKMatrix4 rotationMatrix=GLKMatrix4MakeWithQuaternion (glkq);

GLKMatrix4 scaleMatrix = GLKMatrix4MakeScale(0.5, 1. ,0.3);
GLKMatrix4 translateMatrix = GLKMatrix4MakeTranslation(0., 0., 0.);

GLKMatrix4 modelMatrix =GLKMatrix4Multiply(translateMatrix,GLKMatrix4Mult iply(scaleMatrix,rotationMatrix));

GLKMatrix4 viewMatrix = GLKMatrix4MakeLookAt(0, 0, 5, 0, 0, 0, 0, 1 , 0);
effect.transform.modelviewMatrix = GLKMatrix4Multiply(viewMatrix, modelMatrix);

effect.transform.projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians( 45.0f), 3./4., 3, -5);

[effect prepareToDraw];

glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);

glEnableVertexAttribArray(GLKVertexAttribPosition) ;
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 0, triangleVertices);

glEnableVertexAttribArray(GLKVertexAttribColor);
glVertexAttribPointer(GLKVertexAttribColor, 4, GL_FLOAT, GL_FALSE, 0, triangleColors);

glDrawArrays(GL_TRIANGLES, 0, 36);

glDisableVertexAttribArray(GLKVertexAttribPosition );
glDisableVertexAttribArray(GLKVertexAttribColor);
}

I cannot figure out what I am doing wrong here though I am under the impression that it is the call to

effect.transform.projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians( 45.0f), 3./4., 3, -5);

that creates a wrong perspective. Anyhow if you could point me out what might be going wrong I would be grateful.

sandbucket
10-01-2013, 07:34 AM
i have this problem too. i believe its because the view port isnt square and it causes the normalized coordinates to distort to reach their new positions. its nothing you did wrong :) just gotta find a fix for it...

fredikk
10-01-2013, 08:28 AM
Well, I thought that defining the aspect ratio in

effect.transform.projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians( 45.0f), 3./4., 3, -5);

to 3/4 should set the view port accordingly... I cannot understand what is happening and unfortunately I do not have the time to dive into opengl right now. This code is a tweaked example I found online since what I want to do is(well... should be) fairly simple. I believe that there is something conceptually wrong with my code. Meaning that one of these calls that produce all this matrices that, multiplied, transform to the final object is not doing what I think it is doing... Anyhow if someone with more experience could point us towards somewhere it would be nice...

Roaoul
10-01-2013, 11:04 AM
I don't know GLKit, but for regular OpenGL on a PC: If you want to distort/scale your object by .5(x), 1(y), .3(z) in object coordinates, then you should switch the order of your rotate and scale matrices. The one farthest on the right happens in the undisturbed object coordinates, the next one happens in disturbed object coordinates. So when you rotate and then distort, the distortion will be different at the object for different rotations. Hopefully your screen aspect is taken care of by your viewport transform, that comes after projection.

Basic principle: matrices multiplying from the right (where your vertices are) translate or rotate or distort from the object's perspective. Matrices on the left are from your eye's perspective. Stuff in the middle has to be thought of from the perspective of a transformed eye, by matrices left of the perspective, or the perspective of a transformed object (by the matrices on the right).

fredikk
10-01-2013, 01:42 PM
Roaoul, thanks very much man! The problem was exactly what you mentioned. The cube was first rotated and then scaled (in every frame). So the call that works is

effect.transform.modelviewMatrix = GLKMatrix4Multiply(viewMatrix,GLKMatrix4Multiply(t ranslateMatrix,GLKMatrix4Multiply(rotationMatrix,s caleMatrix)));
I feel actually a bit embarrassed not seeing this... Thanks again.

Roaoul
10-01-2013, 08:13 PM
What you've pulled off is awesome. Don't feel embarrassed. OpenGL does that to me all the time: see my post on "Lost Hello Triangle". :P Welcome to the club!