Search code examples
macoscocoaappkitcatransform3d

Why does a CATransform3DMakeRotation not take (0,0,1) as rotating around the Z-axis?


If I do a transform to an NSView in Cocoa's app:

self.view.layer.transform = CATransform3DMakeRotation(30 * M_PI / 180, 0, 0, 1);

I see the square not rotated around the Z-axis, but rotated as if that vector is pointing downward and outward. I need to make it

self.view.layer.transform = CATransform3DMakeRotation(30 * M_PI / 180, 1, 1, 1);

to make it rotate around the Z-axis, as shown in the picture on this question.

However, if I set an NSTimer and then update the transform in the update method, then using

-(void) update:(id) info {
    self.view.layer.transform = 
                  CATransform3DMakeRotation(self.degree * M_PI / 180, 0, 0, 1);
    self.degree += 10;
}

(this time, using (0, 0, 1)) will work: it rotates around the Z-axis. I wonder why (1, 1, 1) is needed inside of applicationDidFinishLaunching , but (0, 0, 1) can be used in the update method?


Solution

  • It turns out the view needs to be added to window.contentView first:

    - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
    {    
        self.view = [[NSView alloc] initWithFrame:NSMakeRect(100, 100, 200, 200)];
    
        [self.window.contentView addSubview:self.view];
    
        self.view.wantsLayer = YES;
        self.view.layer = [CALayer layer];
    
        self.view.layer.backgroundColor = [[NSColor yellowColor] CGColor];
        self.view.layer.anchorPoint = CGPointMake(0.5, 0.5);
        self.view.layer.transform = CATransform3DMakeRotation(30 * M_PI / 180, 0, 0, 1); 
    }
    

    also, the line self.view.layer = [CALayer layer]; needs to be after the line self.view.wantsLayer = YES;. Why these order, I am not sure, but it works as it is supposed to. I can't find the docs that mentions the requirement for this order yet, but the code above works. I will update the answer when I find more info about why the order is needed.