Reputation: 16804
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 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: UPDATE #1
Ok, i thought i found the solution, which was rotating only the camera around the Z axis, And perform X and Y rotations on the model itself. This seemed to be good, But of course it led to a new problem described in this VIDEO (it's in the 23'd second, the rest is to show how it is being done).
The reason this is happening is the axis system of the object is being rotated and when i am doing a Z axis rotation followed by a X or Y axis rotations, The results are wrong.
I just don't know how to rotate the object alone from the axis system, so that the rotations will be done correctly.
Now, for the code part:
The rendering function:
- (void)render:(CADisplayLink*)displayLink {
...
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];
glUniformMatrix4fv(_projectionUniform, 1, 0, projection.glMatrix);
[modelView populateFromTranslation:_currentPan];
[modelView rotateBy:_currentRotation];
[modelView rotateByZ:zRotationEnd];
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);
}
And the relevant calling part:
if(sender.numberOfTouches == 1)
{
BOOL started = false;
CGPoint rotation = [sender translationInView:sender.view];
float x = rotation.x;
float y = rotation.y;
if (sender.state == UIGestureRecognizerStateBegan)
{
started = true;
}
[self.glView rotateAroundX:x andY:y newRotate:started];
}
The Z rotation function:
- (void) rotateAroundZ:(float) z newRotate:(BOOL) isNewRotate
{
if (isNewRotate) {
zRotationStart = 0;
}
zRotationEnd = zRotationEnd - (z - zRotationStart);
zRotationStart = z;
}
And the relevant calling part:
- (IBAction)rotation:(UIRotationGestureRecognizer *)sender {
BOOL started = false;
float rotation = RadiansToDegrees([sender rotation]);
if (sender.state == UIGestureRecognizerStateBegan)
{
started = true;
}
[self.glView rotateAroundZ:rotation newRotate:started];
NSLog(@"Rotation %f", rotation);
}
The 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;
}
Would really appreciate any help.
Cheers!
Upvotes: 3
Views: 1002
Reputation: 62333
Your mistake is coming because you are rotating around x,y and z at the same time. The problem is that your z-axis rotation is around the z axis as defined by the object when its model matrix is identity.
The easiest way to solve this is with a compound matrix multiply. Essentially by multiplying matrices together you are specifying the order of the operations performed.
In your case you want to apply the "x-y" animation as you already do. You THEN want to perform your z-axis rotation.
So something like the following: (I've never written an cocos3d code so this is based on a quick search through the docs, there may be typos).
CC3GLMatrix* rotationXY = [CC3GLMatrix identity];
[rotationXY rotateBy: _currentRotation];
CC3GLMatrix* rotationZ = [CC3GLMatrix rotateByZ: zRotationEnd];
[rotationXY multiplyByMatrix: rotationZ];
This should give you your correct model matrix. Finally you need to multiply your view (camera) matrix in:
[rotationXY multiplyByMatrix: view];
[CC3GLMatrix copyMatrix: rotationXY into: modelView];
You now should be seeing the behaviour you expect.
Upvotes: 1
Reputation: 455
Simple rotations.
This is the easiest way to rotate an object based on touch movement. Here is example
pseudocode:
Matrix.setIdentity(modelMatrix);
... do other translations here ...
Matrix.rotateX(totalYMovement);
Matrix.rotateY(totalXMovement);
This is done every frame.
To rotate an object up or down, we rotate it around the X-axis, and to rotate an object left or right, we rotate it around the Y axis. We could also rotate an object around the Z axis if we wanted it to spin around.
Upvotes: 3
Reputation: 2374
It looks like you are trying to implement a gimbal.
Although you seem to be only using Cocos3D for the basic data math structures, have a look at this post, which describes creating a gimbal in Cocos3D, and which might help point you in the right direction.
Creating a gimbal is easier to implement using nested structural objects (CC3Node
in Cocos3D) that match the structure of a gimbal, instead of trying to apply consecutive rotations to a single matrix. But, with a little algorithmic analysis and experimentation, you may be able to extract the resulting matrix math and implement it on a single matrix.
Remember that a successful gimbal requires that the rotations be performed in the correct order.
Upvotes: 1