Scene Kit Animation - macos

Anyone have any idea why I can't get this simple animation to work? It just doesn't play.
self.scene = [SCNScene scene];
SCNNode *sun = [SCNNode nodeWithGeometry:[SCNSphere sphereWithRadius:5.0]];
SCNNode *moon = [SCNNode nodeWithGeometry:[SCNSphere sphereWithRadius:2.0]];
moon.position = SCNVector3Make(7.0, 7.0, 7.0);
moon.pivot = CATransform3DMakeTranslation(-7.0, -7.0, -7.0);
CABasicAnimation *startAnim = [CABasicAnimation animationWithKeyPath:#"rotation"];
startAnim.duration = 5;
startAnim.repeatCount = MAXFLOAT;
startAnim.toValue =[NSValue valueWithSCNVector4:SCNVector4Make(0.0, 0.0, 0.0,1.0)];
startAnim.timingFunction =[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[moon addAnimation:startAnim forKey:#"rotate"];
[sun addChildNode:moon];
[[self.scene rootNode] addChildNode:sun];
I think the problem is...
startAnim.toValue =[NSValue valueWithSCNVector4:SCNVector4Make(0.0, 0.0, 0.0,1.0)];
Cheers

Indeed SCNVector4Make(0.0, 0.0, 0.0,1.0) is not a valid rotation.
"rotation" is an axis angle made with 4 floats {x y z w}.
the 3 first floats x y z represents the axis, w is the rotation in radian.
So (0.0, 0.0, 0.0) is not a valid axis (or in the best case it represents a null rotation)

I couldn't get your example working with the "rotation" keypath either, but I could using "transform". For example:
CABasicAnimation *startAnim = [CABasicAnimation animationWithKeyPath:#"transform"];
startAnim.duration = 5;
startAnim.repeatCount = MAXFLOAT;
startAnim.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(3.14, 0.0, 1.0, 0.0)];
startAnim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[moon addAnimation:startAnim forKey:#"transform"];

Related

rotate a sublayer in xcode

It's been a while, as I was hospitalized for 3 months after a motorcycle accident.
So I just got to renew my apple programming subscription :-)
I have another question that has been on my mind for quite some time.
In my iPad application I draw a triangle in the center of an iPad like this:
- (void)initTriangle
{
CGRect screenBound = [[UIScreen mainScreen] bounds];
CGSize screenSize = screenBound.size;
CGFloat screenWidth = screenSize.width;
CGFloat screenHeight = screenSize.height;
// draw triangle (TRIANGLE)
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path,NULL, 0.5*screenWidth, 0.5*screenHeight-25);
CGPathAddLineToPoint(path, NULL, 0.5*screenWidth-25, 0.5*screenHeight+25);
CGPathAddLineToPoint(path, NULL, 0.5*screenWidth+25, 0.5*screenHeight+25);
CGPathAddLineToPoint(path, NULL, 0.5*screenWidth, 0.5*screenHeight-25);
CAShapeLayer *triangle = [CAShapeLayer layer];
[triangle setPath:path];
[triangle setFillColor:[[UIColor blackColor] CGColor]];
[[[self view] layer] addSublayer:triangle];
CGPathRelease(path);
}
And I call this from my viewDidLoad like this:
[self initTriangle];
Now I'm trying to rotate this triangle with the rotation of my iPad around Z-Axis while laying flat on the table. I have a function that gives me the yaw readings in float and I'm calling my
-(void)updateTriangleWithYaw:(float)yaw
method, but I don't know what to exactly put in there to make it rotate.
here is what my method looks like so far:
-(void)updateTriangleWithYaw:(float)yaw
{
CGRect screenBound = [[UIScreen mainScreen] bounds];
CGSize screenSize = screenBound.size;
CGFloat screenWidth = screenSize.width;
CGFloat screenHeight = screenSize.height;
NSLog(#"YAW: %f", yaw);
Z += 2 * yaw;
Z *= 0.8;
CGFloat newR = R + 10 * yaw;
self.triangle.frame = CGRectMake(0.5*screenWidth, 0.5*screenHeight, newR, newR);
}
Any help will be greatly appreciated!
Thanks and be safe guys!!
You should set the layer's affineTransform. You can apply a rotation transform like:
[self.triangle setAffineTransform:CGAffineTransformMakeRotation(yaw)];
This method, setAffineTransform is a convenience to set the transform property of the layer, which is a more general type of transform CATransform3D. You can also set the transform of the layer directly, and if you want to do that you can make a rotation about the z-axis like:
self.triangle.transform = CATransform3DMakeRotation(yaw, 0, 0, 1);
In this case the first argument is the angle (in radians) and the last three arguments specify the axis of rotation.
Note that you should not assign or depend on the value of the frame property of a layer whose transform is not the identity (CGAffineTransformIdentity). When you use the transform property you should set the size and position of your layer by assigning the layer's center and bounds properties, and similarly you should read the center and bounds when you want to find out information about the layer's position and size.

How do I scale a NSView from the center using Facebook Pop animation?

Please note, this is a Mac OS X (NSView) related question.
I'm trying to use Facebook's POP animation to scale a NSView from the center (to 75% its size) and then back to 100%, however I can't get it to work. Given kPOPLayerScaleXY doesn't seem to work, I did the following but this gives me incorrect results (as it seems to scale down from the top left, and when zoomIn is false, it goes too large:
CGRect baseRect = CGRectMake(0, 0, 30, 24);
CGFloat scale = (zoomIn) ? 0.75 : 1.0;
CGFloat x = baseRect.origin.x;
CGFloat y = baseRect.origin.y;
CGFloat width = baseRect.size.width;
CGFloat height = baseRect.size.height;
if (zoomIn) {
width -= floorf((1.0 - scale) * width);
height -= floorf((1.0 - scale) * height);
x += floorf((width * (1.0f - scale)) / 2);
y += floorf((height * (1.0f - scale)) / 2);
}
CGRect scaleRect = CGRectMake(x, y, width, height);
[myView.layer pop_removeAllAnimations];
POPSpringAnimation *animation = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerBounds];
animation.springBounciness = 8;
animation.toValue = [NSValue valueWithCGRect: scaleRect];
[myView.layer pop_addAnimation:animation forKey:#"zoom"];
I got it working finally by using two animations instead:
CGRect baseRect = CGRectMake(0, 0, 30, 24);
CGFloat scale = (zoomIn) ? 0.80 : 1.0;
CGFloat x = baseRect.origin.x;
CGFloat y = baseRect.origin.y;
if (zoomIn) {
x = floorf((baseRect.size.width * (1.0 - scale)) / 2);
y = floorf((baseRect.size.height * (1.0 - scale)) / 2);
}
[myView.layer pop_removeAllAnimations];
POPSpringAnimation *animation = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerScaleXY];
animation.springBounciness = 8;
animation.toValue = [NSValue valueWithCGSize:CGSizeMake(scale, scale)];
[myView.layer pop_addAnimation:animation forKey:#"zoom"];
animation = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerTranslationXY];
animation.springBounciness = 8;
animation.toValue = [NSValue valueWithCGPoint:CGPointMake(x, y)];
[myView.layer pop_addAnimation:animation forKey:#"translate"];

Rotating CALayer of NSImageView 90 degrees

I am trying to rotate the CALayer of an NSImageView. My problem is that the anchorPoint appears to be (0.0, 0.0) by default but I want it to be the center of the image (Apple's documentation indicates the default should be the center (0.5, 0.5), but it's not on my system OS X 10.7), When I modify the anchor point the origin of the center of the image shifts to the lower left corner.
Here's the code I am using to rotate the layer:
CALayer *myLayer = [imageView layer];
CGFloat myRotationAngle = -M_PI_2;
NSNumber *rotationAtStart = [myLayer valueForKeyPath:#"transform.rotation"];
CATransform3D myRotationTransform = CATransform3DRotate(myLayer.transform, myRotationAngle, 0.0, 0.0, 1.0);
myLayer.transform = myRotationTransform;
CABasicAnimation *myAnimation = [CABasicAnimation animationWithKeyPath:#"transform.rotation"];
myAnimation.duration = 1.0;
myAnimation.fromValue = rotationAtStart;
myAnimation.toValue = [NSNumber numberWithFloat:([rotationAtStart floatValue] + myRotationAngle)];
[myLayer addAnimation:myAnimation forKey:#"transform.rotation"];
myLayer.anchorPoint = CGPointMake(0.5, 0.5);
[myLayer addAnimation:myAnimation forKey:#"transform.rotation"];
It appears that changing the anchor point of something also changes it's position. The following snippet fixes the problem:
CGPoint anchorPoint = CGPointMake(0.5, 0.5);
CGPoint newPoint = CGPointMake(disclosureTriangle.bounds.size.width * anchorPoint.x,
disclosureTriangle.bounds.size.height * anchorPoint.y);
CGPoint oldPoint = CGPointMake(disclosureTriangle.bounds.size.width * disclosureTriangle.layer.anchorPoint.x,
disclosureTriangle.bounds.size.height * disclosureTriangle.layer.anchorPoint.y);
newPoint = CGPointApplyAffineTransform(newPoint,
[disclosureTriangle.layer affineTransform]);
oldPoint = CGPointApplyAffineTransform(oldPoint,
[disclosureTriangle.layer affineTransform]);
CGPoint position = disclosureTriangle.layer.position;
position.x -= oldPoint.x;
position.x += newPoint.x;
position.y -= oldPoint.y;
position.y += newPoint.y;
disclosureTriangle.layer.position = position;
disclosureTriangle.layer.anchorPoint = anchorPoint;

question about CGAffineTransformTranslate

CGRect rect1 = backgroundImageView.frame;
NSLog(#"%f,%f,%f,%f",rect1.origin.x,rect1.origin.y,
rect1.size.width,rect1.size.height);
angle = -90.0;
moveX = 0;
moveY = 0.0;
CGFloat degreesToRadians = M_PI * angle / 180.0;
CGAffineTransform landscapeTransform =
CGAffineTransformMakeRotation(degreesToRadians);
landscapeTransform =
CGAffineTransformTranslate(landscapeTransform, moveX, moveY);
[backgroundImageView setTransform:landscapeTransform];
rect1 = backgroundImageView.frame;
NSLog(#"%f,%f,%f,%f",rect1.origin.x,rect1.origin.y,
rect1.size.width,rect1.size.height);
the debug message output:
0.000000,0.000000,320.000000,480.000000
-80.000000,80.000000,480.000000,320.000000
why does the (x,y) changes to (-80,80)?
When you set the transform, the backgroundImageView.center does not change. If the parent view has already rotated, yout can do something like this after applying the transform.
backgroundImageView.center = backgroundImageView.superview.center;
Either way, for your purposes you should adjust the center and not translate the transform.

OpenGL ES glRotatef performing shear instead of rotate?

I am able to draw a sprite on the screen of an iPhone, but when I try to rotate it I am getting some weird results. It seems to be stretching the sprite in the y direction more the closer the sprite gets to pointing down the y-axis (90 and 270 degrees). It displays correctly when pointing down the x and -x axes (0 and 180 degrees). It is basically like it is shearing instead of rotating. Here are the essentials of the code (projection matrix is ortho):
glPushMatrix();
glLoadIdentity();
glTranslatef( position.x, position.y, -1.0f );
glRotatef( rotation, 0.0f, 0.0f, 1.0f );
glScalef( halfSize.x, halfSize.y, 1.0f );
vertices[0] = 1.0f;
vertices[1] = 1.0f;
vertices[2] = 0.0f;
vertices[3] = 1.0f;
vertices[4] = -1.0f;
vertices[5] = 0.0f;
vertices[6] = -1.0f;
vertices[7] = 1.0f;
vertices[8] = 0.0f;
vertices[9] = -1.0f;
vertices[10] = -1.0f;
vertices[11] = 0.0f;
glVertexPointer( 3, GL_FLOAT, 0, vertices );
glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
glPopMatrix();
Can anybody explain to me how to fix this please?
halfsize is just half the x and y extent of the sprite; removing the glScalef call does not make any difference.
Here is my matrix setup:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrthof(0, 320, 480, 0, 0.01, 5);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
OK, hopefully this screenshot will demonstrate what's happening:
If you are scaling by the same amount in the x and y directions, then your projection is causing the distortion.
Just a hunch, but maybe try swapping the 320 and 480 in your Ortho projection. (In case the X and Y on the iPhone is swapped)

Resources