将CALayer设置为SCNMaterial的漫反射贴图内容

9
我已经在过去几天里在互联网上搜索了很久,但没有任何结果。不幸的是,苹果关于这个具体问题的文档很模糊,也没有可用的示例代码(至少这是我发现的)。你可能会问出现了什么问题...

我正在尝试将一个uiview的层设置为用于渲染iPhone模型屏幕的材质的内容(没错,这很奇妙:P)。iPhone屏幕的UV映射被设置为0到1,以便在将纹理/层映射到texels时不会出现问题。

所以,我没有像左图那样在iPhone上呈现出这个层,而是像右图那样呈现出来。

正确的呈现                                        错误的呈现

enter image description here

请注意,当我设置了断点并调试实际的 iPhone 节点,并在 Xcode 中查看时,会显示完全不同的渲染,并且当我继续执行时,图层被半固定。

Weird bug

那么...我该如何解决这个问题???我尝试过修改扩散内容的转换矩阵,但是什么都没有被修复。我还尝试将UIView调整为256x256(因为在Blender中UV似乎是256x256), 但这也没有修复任何问题。
以下是该层的代码:
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;

编辑
更奇怪的是,如果我使用以下代码捕获视图的UIImage:
- (UIImage *) imageWithView:(UIView *)view
{
    UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 0.0);
    [view.layer renderInContext:UIGraphicsGetCurrentContext()];

    UIImage * img = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return img;
}

“并将其用作扩散的内容...一切都完美地解决了?这真的很奇怪和令人沮丧,因为图片的大小与uiview的大小完全相同...”
编辑2:
最终我只使用了一个视图的图像作为纹理,这使得事情比我需要的更加静态。我不会将其设置为答案,因为即使在很长时间内也会等待正确的解决方法。所以,如果你有一个答案,并且这个主题已经开放了很长时间,请尽可能地推动它。这部分的文档真的太差了。

我们能看一下你是如何设置SCNScene和SCNView的吗?当你使用纯色作为材质而不是CALayer时,它是否有效? - Hal Mueller
@HalMueller 我正在使用创建SceneKit应用程序时默认提供的代码,并仅更改场景的名称以及节点。CALayer的代码在这里中显示。它将与纯色一起工作,因为该层实际上是映射的,从而使其能够覆盖整个“iPhone屏幕”。似乎映射使得图层溢出到texels区域之外...但当我在ib中使用纹理图像时,它完美地适配并且看起来正确。 - Brave Heart
@ColdSteel。使用CALayer的原因是因为CALayer本身具有动画效果。换句话说,使用CALayer作为纹理的主要原因是它可以以许多有趣的方式进行独特的动画处理。如果依赖shouldRasterize,那么与其使用一个被光栅化的CALayer,不如直接使用位图。因为被光栅化的CALayer实际上就是一个位图。 - Confused
2
如果Core Animation每帧动画都试图重新创建位图,则会失去使用Core Animation的所有性能优势,因为这类似于在上下文中绘制Core Graphics,并将其复制到屏幕中。 - Confused
2
@ColdSteel 使用CALayers作为纹理的原因是为了拥有最高效的可动画纹理。同样,如果在SceneKit中使用SpriteKit作为纹理。CALayers具有一些SpriteKit没有的能力,因此对它们很有吸引力。 - Confused
显示剩余3条评论
2个回答

6
在旧线程上发布新帖,但在当今时代,可以将UIView本身设置为SCNMaterialProperty(漫反射) contents 。苹果的SceneKit工程直接表达了支持这个特性的意图,尽管文档尚未更新以反映它。
要回到原始帖子,请勿将UIView.layer设置为材质属性内容;而是将内容设置为UIView本身。
[更新:根据下面Lance的评论,对于视图的支持可能会变得更糟。]

1
太好了,我已经验证过它可以工作。不幸的是,它不支持透明度。 - Ortwin Gentz
哎呀!你提交了一个错误报告吗? - Bobjt
截至2020年,UIView尚未得到完全支持。我一直收到ARKit_4 [20429:4746699] [Animation] +[UIView setAnimationsEnabled:]被从后台线程调用的信息。在UIView或其子类上从后台线程执行任何操作都不受支持,可能会导致意外和隐匿的行为: https://dev59.com/o7jna4cB1Zd3GeqP6z2D - Lance Samaria
如果支持变得更糟,我会删除这篇文章。出于好奇,谁在调用setAnimationsEnabled? - Bobjt
1
@Bobjt 我正在遵循这个答案:https://dev59.com/uVYM5IYBdhLWcg3wjAkR#48712156。diffuse.contents属性是导致错误的原因。我认为你现在不应该删除答案。我正在使用我的TSI之一来查看苹果技术人员对此问题的看法。一旦我从他们那里得到答案,我会更新你。 - Lance Samaria

4
SceneKit文档中明确指出,虽然有些情况下你可以使用动画的CALayers作为材质内容,但不包括UIView层:

SceneKit无法使用已在其他地方显示的层(例如UIView对象的后备层)。

这意味着,如果您想为材料创建动画内容,则最好使用纯粹的核心动画或SpriteKit。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接