I have created a 3D cube in iphone using CALayer's. Now I wanted to rotate that cube(CALayer) at 90˚ when user double taps on it.
I was able to rotate that cube(CALayer) to 90˚ once but when I double tap the cube(CALayer) is not rotating.
Here is the code that I used to rotate the cube(CALayer)
CATransform3D x = CATransform3DRotate(currentLayer.sublayerTransform, M_PI / 2, 0, 0, 1);
currentLayer.transform = x;
Can anyone help in this. What I'm doing wrong.
PS. For the people who are wondering how I got the degree sign then here is the trick
Option + K
its because you are not changing the angle of rotation .... to understand this lets say you are passing M_PI/2 each time to that method .... so CATransform3DRotate do not rotate it to next 90˚ rather it rotate the layer to the specified angle in this case its 90... so you are not getting any chage because it already at 90˚ ..... so to get correct result do this
static float angle = M_PI / 2;//dont make it static rather make it a global variable
angle += M_PI / 2;
CATransform3D x = CATransform3DRotate(currentLayer.sublayerTransform,angle, 0, 0, 1);
currentLayer.transform = x;
Related
I have written a script in Unity which takes a SkinnedMeshRenderer and AnimationClip and rotates the vertices in each by a specified number of degrees. It looks mostly correct except that rotations seem to be incorrect. Here is an example bone rotation (in euler angles) in the skeleton along with the correct values that would be needed for the animation to look correct.
With no rotation: (0, 0, -10)
Rotated 90 degrees: (-10, 0, 0)
Rotate 180 degrees: (0, 0, 10)
I have been trying to find a way to rotate these bones to make this conversion make sense with the data I have here, but have come up short. I know I want to rotate these values around the Y axis, but don't actually want the Y value in the euler angle to change. I am aware I could just reorient the root bone around the Y axis and the problem would be solved, but I want to have no rotation in the Y axis. I am "fixing" some older animations that have unnecessary rotation values in them.
var localBoneRotation = new Quaternion(keysX[j].value, keysY[j].value, keysZ[j].value, keysW[j].value).eulerAngles;
var reorientedForward = Quaternion.AngleAxis(rotation, Vector3.up) * Vector3.forward;
localBoneRotation.x *= reorientedForward.x;
localBoneRotation.y *= reorientedForward.y;
localBoneRotation.z *= reorientedForward.z;
var finalRotation = Quaternion.Euler(localBoneRotation);
keysX[j].value = finalRotation.x;
keysY[j].value = finalRotation.y;
keysZ[j].value = finalRotation.z;
keysW[j].value = finalRotation.w;
I have also tried using a matrix and Vector3 but most of the time I end up with values in the Y. Perhaps I am going about this incorrectly. I just need to be able to specify an angle rotation and then have the input data match the final euler angles with each of these data points.
I am trying to figure out how to use transform.rotation to simply rotate a character 180 degrees, as if the character is sitting in front of a mirror.
Initially, I used the following to set the character model to the game object it is attached to, which works fine:
target = gameObject.transform;
origPos = target;
target.transform.rotation = transform.rotation;
Now, I would like to turn it around and mirror its movements. How do I do this?
As a first silly attempt, I tried putting a minus sign before rotation, thinking that it would negate all 4 values of w, x, y, z but of course that was just stupid, as I could not use such an operand here.
What is the simplest way of doing this?
transform.scale should be able to sort this, just multiply by -1 on the axis you require so
transform.scale = new Vector3(1.0f, -1.0f, 1.0f);
would mirror in the y axis
http://docs.unity3d.com/ScriptReference/Transform-localScale.html
to rotate something using euler angle values use Quaternion.Euler
target.transform.rotation = Quaternion.Euler(x, y, z);
target.transform.rotation = Quaternion.AngleAxis(180, transform.up);
Using Sprite Kit I am trying to set an SKPhysicsBody moving according to a given angle, so for example if you wanted the sprite to travel to the right you would specify 1.571 radians. To turn the specified angle into a velocity I am using the method below to convert radians to a CGVector. The ORIGINAL version that I implemented from memory has the strange effect of offsetting all the angles by 90degrees. (i.e. if 0 degrees is used the sprite moves right (just like it would if you specified 90degrees)
Question:
I have fixed this in the NEW version by swapping the dx and dy assignments. My question is why does this happen, do I have it wrong in the original (there do seem to be others doing it that way on the web) or is there some reason based on the particular coordinate system being used.
// ORIGINAL
- (CGVector)convertAngleToVector:(CGFloat)radians {
CGVector vector;
vector.dx = cos(radians) * 10;
vector.dy = sin(radians) * 10;
NSLog(#"DX: %0.2f DY: %0.2f", vector.dx, vector.dy);
return vector;
}
// NEW, SWAPPED DX & DY
- (CGVector)convertAngleToVector:(CGFloat)radians {
CGVector vector;
vector.dy = cos(radians) * 10;
vector.dx = sin(radians) * 10;
NSLog(#"DX: %0.2f DY: %0.2f", vector.dx, vector.dy);
return vector;
}
NOTE: also in Sprite Kit clockwise rotations are negative, so far convertAngleToVector is doing positive clockwise rotations (i.e. 1.571 radians is right, where it should be left) I could just do cos(radians*-1) and sin(radians*-1) but there might be some underlying reason for this based on me swapping dx and dy.
Sprite Kit (SKView Coordinates):
Yeah, SpriteKit defaults to the right. The Physics Collision sample project solves this by implementing this method:
- (CGFloat)shipOrientation
{
// The ship art is oriented so that it faces the top of the scene, but Sprite Kit's rotation default is to the right.
// This method calculates the ship orientation for use in other calculations.
return self.zRotation + M_PI_2;
}
You can then just get the existing orientation by calling something like:
CGFloat shipDirection = [self shipOrientation];
And then adjust the zRotation property from there.
From the Sprite Kit Programming Guide (emphasis added):
Sprite Kit also has a standard rotation convention. Figure 4-2 shows the polar coordinate convention. An angle of 0 radians specifies the positive x axis. A positive angle is in the counterclockwise direction.
In this coordinate system, an angle of zero radians pointing to the right is correct. If you want to use a system in which a zero angle is straight up (along positive y axis) and increase clockwise, you'll want to transform your angles before converting them to vectors.
I have a UIImageView that I applied a:
CGAffineTransformConcat(scaleTransform, rotateTransform);
Now I need to get the actual scale value and rotation degrees. I can get the rotation degrees, but the problem comes when getting the scale value. The scale value I get is not the right one, unless I rotate the view to 0.0;
I think this is happening because the matrix is now multiplied (scale * rotation).
Any ideas on how to get the right scale value?
I solved me problem.
To get the Angle:
float angle = atan2(imageView.transform.b, imageView.transform.a);
The scale transform applied to the imageView was uniform, so to get the Scale Value:
CATransform3D localScaleTransform = [(CALayer *)[imageView.layer presentationLayer] transform];
float scale = sqrt(pow(localScaleTransform.m11, 2) + pow(localScaleTransform.m12, 2));
If you applied different scale values follow this:
scaleInX = sqrt(M11^2 + M12^2)
scaleInY = sqrt(M21^2 + M22^2)
I'm trying figure out how to get an OpenGL specified object to be displayed correctly according to the device orientation (ie. according to the gravity vector from the accelerometer, and heading from compass).
The GLGravity sample project has an example which is almost like this (despite ignoring heading), but it has some glitches. For example, the teapot jumps 180deg as the device viewing angle crosses the horizon, and it also rotates spuriously if you tilt the device from portrait into landscape. This is fine for the context of this app, as it just shows off an object and it doesn't matter that it does these things. But it means that the code just doesn't work when you attempt to emulate real life viewing of an OpenGL object according to the device's orientation. What happens is that it almost works, but the heading rotation you apply from the compass gets "corrupted" by the spurious additional rotations seen in the GLGravity example project.
Can anyone provide sample code that shows how to adjust correctly for the device orientation (ie. gravity vector), or to fix the GLGravity example so that it doesn't include spurious heading changes?
//Clear matrix to be used to rotate from the current referential to one based on the gravity vector
bzero(matrix, sizeof(matrix));
matrix[3][3] = 1.0;
//Setup first matrix column as gravity vector
matrix[0][0] = accel[0] / length;
matrix[0][1] = accel[1] / length;
matrix[0][2] = accel[2] / length;
//Setup second matrix column as an arbitrary vector in the plane perpendicular to the gravity vector {Gx, Gy, Gz} defined by by the equation "Gx * x + Gy * y + Gz * z = 0" in which we arbitrarily set x=0 and y=1
matrix[1][0] = 0.0;
matrix[1][1] = 1.0;
matrix[1][2] = -accel[1] / accel[2];
length = sqrtf(matrix[1][0] * matrix[1][0] + matrix[1][1] * matrix[1][1] + matrix[1][2] * matrix[1][2]);
matrix[1][0] /= length;
matrix[1][1] /= length;
matrix[1][2] /= length;
//Setup third matrix column as the cross product of the first two
matrix[2][0] = matrix[0][1] * matrix[1][2] - matrix[0][2] * matrix[1][1];
matrix[2][1] = matrix[1][0] * matrix[0][2] - matrix[1][2] * matrix[0][0];
matrix[2][2] = matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0];
//Finally load matrix
glMultMatrixf((GLfloat*)matrix);
Here's a clarification showing how to get the elevation and tilt that are needed for gluLookAt solution as shown in my last answer:
// elevation comes from z component (0 = facing horizon)
elevationRadians = asin(gravityVector.z / Vector3DMagnitude(gravityVector));
// tilt is how far screen is from vertical, looking along z axis
tiltRadians = atan2(-gravityVector.y, -gravityVector.x) - M_PI_2;
Following up on Chris's suggestion: I'm not sure if I've got this all correct due to differing conventions of row/column order and heading cw or ccw. However the following code is what I came up with:
Vector3D forward = Vector3DMake(0.0f, 0.0f, -1.0f);
// Multiply it by current rotation matrix to get teapot direction
Vector3D direction;
direction.x = matrix[0][0] * forward.x + matrix[1][0] * forward.y + matrix[2][0] * forward.z;
direction.y = matrix[0][1] * forward.x + matrix[1][1] * forward.y + matrix[2][1] * forward.z;
direction.z = matrix[0][2] * forward.x + matrix[1][2] * forward.y + matrix[2][2] * forward.z;
heading = atan2(direction.z, direction.x) * 180 / M_PI;
// Use this heading to adjust the teapot direction back to keep it fixed
// Rotate about vertical axis (Y), as it is a heading adjustment
glRotatef(heading, 0.0, 1.0, 0.0);
When I run this code, the teapot behaviour has apparently "improved" eg. heading no longer flips 180deg when device screen (in portrait view) is pitched forward/back through upright. However, it still makes major jumps in heading when device (in landscape view) is pitched forward/back. So something's not right. It suggests that the above calculation of the actual heading is incorrect...
I finally found a solution that works. :-)
I dropped the rotation matrix approach, and instead adopted gluLookAt. To make this work you need to know the device "elevation" (viewing angle relative to horizon ie. 0 on horizon, +90 overhead), and the camera's "tilt" (how far the device is from vertical its x/y plane ie. 0 when vertical/portrait, +/-90 when horizontal/landscape), both of which are obtained from the device gravity vector components.
Vector3D eye, scene, up;
CGFloat distanceFromScene = 0.8;
// Adjust eye position for elevation (y/z)
eye.x = 0;
eye.y = distanceFromScene * -sin(elevationRadians); // eye position goes down as elevation angle goes up
eye.z = distanceFromScene * cos(elevationRadians); // z position is maximum when elevation is zero
// Lookat point is origin
scene = Vector3DMake(0, 0, 0); // Scene is at origin
// Camera tilt - involves x/y plane only - arbitrary vector length
up.x = sin(tiltRadians);
up.y = cos(tiltRadians);
up.z = 0;
Then you just apply the gluLookAt transformation, and also rotate the scene according to the device heading.
// Adjust view for device orientation
gluLookAt(eye.x, eye.y, eye.z, scene.x, scene.y, scene.z, up.x, up.y, up.z);
// Apply device heading to scene
glRotatef(currentHeadingDegrees, 0.0, 1.0, 0.0);
Try rotating the object depending upon iphone acceleration values.
float angle = -atan2(accelX, accelY);
glPushMatrix();
glTranslatef(centerPoint.x, centerPoint.y, 0);
glRotatef(angle, 0, 0, 1);
glTranslatef(-centerPoint.x, -centerPoint.y, 0);
glPopMatrix();
Where centerPoint is the middle point the object.
oo, nice.
GLGravity seems to get everything right except for the yaw. Here's what I would try. Do everything GLGravity does, and then this:
Project a vector in the direction you want the teapot to face, using the compass or whatever you so choose. Then multiply a "forward" vector by the teapot's current rotation matrix, which will give you the direction the teapot is facing. Flatten the two vectors to the horizontal plane and take the angle between them.
This angle is your corrective yaw. Then just glRotatef by it.
Whether or not the 3GS's compass is reliable and robust enough for this to work is another thing. Normal compasses don't work when the north vector is perpendicular to their face. But I just tried the Maps app on my workmate's 3GS and it seems to cope, so maybe they have got a mechanical solution in there. Knowing what the device is actually doing will help interpret the results it gives.
Make sure to test your app at the north and south poles once you're done. :-)
Getting a much more stable gravity-based reference, can now be done using CMMotionManager.
When starting motion updates with startDeviceMotionUpdates(), you can specify a reference frame.
This fuses the accelerometer, gyroscope and optionally (depending on chose reference frame) magnetometer data. Accelerometer data is pretty noisy and bouncy (any sideways motion of the device temporarily tilts the gravity vector by any device acceleration) and alone doesn't make a good reference.
I've been low-pass filtering the accelerometer data, which helps a bit but makes the system slow.