Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Set CALayer as SCNMaterial's diffuse contents

I've been searching all over the internet over the past couple of days to no avail. Unfortunately, the apple documentation about this specific issue is vague and no sample code is available (at least thats what I found out). What seems to be the issue you may ask...

I'm trying to set a uiview's layer as the contents of the material that is used to render an iPhone model's screen (Yep, trippy :P ). The iPhone's screen's UV mapping is set from 0 to 1 so that no issue persists in mapping the texture/layer onto the texels.

So, instead of getting this layer to appear rendered on the iPhone, same as left image, Instead, I get this rendered onto the iPhone like right image

Correct Render                                        Incorrect Render

enter image description here

Also note, that when I set a breakpoint and debug the actual iPhone node and view it in Xcode, a completely different render is shown and the layer gets half-fixed when I continue execution:

Weird bug

Now then... HOW do I fix this issue??? I've tried playing with the diffuse's contents transform matrix but nothing gets fixed. I've also tried resizing the UIView to 256x256 (since the UV seems to be 256x256 as shown in blender - the 3d modelling package), but that doesn't fix anything.

Here is the code for the layer:

UIView *screen = [[UIView alloc] initWithFrame:self.view.bounds];
screen.backgroundColor = [UIColor redColor];

UIView *temp = [[UIView alloc] initWithFrame:CGRectMake(0, 0, screen.bounds.size.width, 60)];
temp.backgroundColor = [UIColor colorWithRed:0 green:(112.f/255.f) blue:(235.f/255.f) alpha:1];

UILabel *label = [[UILabel alloc] initWithFrame:CGRectInset(temp.bounds, 40, 0)];
label.frame = CGRectOffset(label.frame, 40, 0);
label.textColor = [UIColor colorWithRed:0 green:(48.f/255.f) blue:(84.f/255.f) alpha:1];
label.text = @"Select Track";
label.font = [UIFont fontWithName:@"HelveticaNeue-Light" size:30];
label.minimumScaleFactor = 0.001;
label.adjustsFontSizeToFitWidth = YES;
label.lineBreakMode = NSLineBreakByClipping;
[temp addSubview:label];

UIView *separator = [[UIView alloc] initWithFrame:CGRectMake(0, temp.bounds.size.height - 2, temp.bounds.size.width, 2)];
separator.backgroundColor = [UIColor colorWithRed:0 green:(48.f/255.f) blue:(84.f/255.f) alpha:1];
[temp addSubview:separator];
[screen addSubview:temp];
screen.layer.contentsGravity = kCAGravityCenter;

Edit
What's even weirder is that if I capture a UIImage of the view using:

- (UIImage *) imageWithView:(UIView *)view
{
    UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 0.0);
    [view.layer renderInContext:UIGraphicsGetCurrentContext()];

    UIImage * img = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return img;
}

and use that as the diffuse's content... everything works out perfectly fine?! It's really weird and frustrating since the image's size is exactly the same as the uiview's...


Edit 2

I ended up just using an image of the view as the texture, which makes things much more static than I needed. I won't set this as the answer because I'll still be waiting for a correct fix to this issue even if it in a long time. So, if you have an answer and this topic has been opened for a long time, please bump it if you can. The documentation on this section is just so poor.

like image 240
Brave Heart Avatar asked Mar 23 '16 23:03

Brave Heart


2 Answers

New post on an old thread, but this day-in-age, it's possible to set the UIView itself as SCNMaterialProperty (diffuse) contents. Intention to support this feature is communicated directly from SceneKit engineering at Apple, though the documentation has not yet been updated to reflect it.

To tied back to the original post, do not set a UIView.layer as material property contents; instead set contents to the UIView itself.

[Update: according to Lance's comment below, support for views may be getting worse rather than getting better.]

like image 122
Bobjt Avatar answered Nov 03 '22 17:11

Bobjt


The SceneKit docs pretty strongly suggest that, while there are cases where you can use animated CALayers as material content, that doesn't include UIView layers:

SceneKit cannot use a layer that is already being displayed elsewhere (for example, the backing layer of a UIView object).

That suggests that if you want to make animated content for your material, you're better off with either Core Animation used entirely on its own or SpriteKit.

like image 30
rickster Avatar answered Nov 03 '22 18:11

rickster