首页 文章

组合两个或更多 SCNGeometries

提问于
浏览
4

我使用这种方法来获取 UIImage 并将其转换为 3D 模型。然而,这意味着我添加了很多节点。我想也许可以通过将所有几何添加到单个节点来优化它。有办法实现吗?

这是代码

static inline SCNNode* S2NNode(const UIImage* sprite) {
  SCNNode *spriteNode = [SCNNode node];
  CFDataRef pixelData = CGDataProviderCopyData(CGImageGetDataProvider(sprite.CGImage));
  const UInt8* data = CFDataGetBytePtr(pixelData);
  for (int x = 0; x < sprite.size.width; x++)
  {
    for (int y = 0; y < sprite.size.height; y++)
    {
      int pixelInfo = ((sprite.size.width * y) + x) * 4;
      UInt8 alpha = data[pixelInfo + 3];
      if (alpha > 3)
      {
        UInt8 red   = data[pixelInfo];
        UInt8 green = data[pixelInfo + 1];
        UInt8 blue  = data[pixelInfo + 2];
        UIColor *color = [UIColor colorWithRed:red/255.0f green:green/255.0f blue:blue/255.0f alpha:alpha/255.0f];
        SCNNode *pixel = [SCNNode node];
        pixel.geometry = [SCNBox boxWithWidth:1.001 height:1.001 length:1.001 chamferRadius:0];
        pixel.geometry.firstMaterial.diffuse.contents = color;
        pixel.position = SCNVector3Make(x - sprite.size.width / 2.0,
                                        y - sprite.size.height / 2.0,
                                        0);
        [spriteNode addChildNode:pixel];
      }
    }
  }
  CFRelease(pixelData);
  //The image is upside down and I have no idea why.
  spriteNode.rotation = SCNVector4Make(1, 0, 0, M_PI);
  return spriteNode;
}

2 回答

  • 3

    这个答案解决了最初提出的问题 - 如何合并几何。但是,合并几何图形似乎并不能解决您的实际问题 - 如何获得具有一定厚度的像素化“精灵”,并具有良好的性能。请参阅我的另一个答案


    SCNNode方法flattenedClone将节点子节点的所有几何结构组合成具有单个几何的单个节点。这将减少场景处理开销并在单个 OpenGL 绘制调用中渲染......但它也会使立方体不能独立移动并且所有共享相同的材质,因此它们将不会是不同的颜色。此外,根据您希望多维数据集排列的方式,您可能会推送比 GPU 更多的顶点数据,这仍然会损害您的性能。

    取决于你想要的效果,可能有更好的解决方案。

  • 3

    发表一个单独的答案,因为你的评论已经证明你实际上正在寻找的并不是你所要求的 - 我会留下另一个答案,因为它回答了最初提出的问题,即使它没有解决你的问题。


    所以,听起来你真正需要的不是立方体的集合,每个立方体都可以独立移动,每个立方体都有自己的颜色,而是将 2D 形状挤压成 3D - 特别是由图像的 non-transparent 像素形成的形状:

    矮胖的精灵

    在这种情况下,制作一堆立方体确实会损害您的性能 - 以及您的渲染结果。查看此详细信息(来自使用 lots-of-cubes 方法的版本):

    文物

    那些小白点来自两个立方体相遇的圆角误差。这里的问题 - 无论你是否使用flattenedClone--是推送到 GPU 的几何数据描述了一大堆多边形,这些多边形要么是不可见的(因为它们位于两个立方体之间)或者不相关(因为两个共享的面)相邻的立方体也可以是单个多边形)。这是我对 lots-of-cubes 方法测试的性能指标:

    408 draws,4.9K 多边形,14.7K 顶点

    这是 408 绘制,4.9K 多边形,14.7K 顶点。在 iPad Air 上旋转该模型每秒可获得 14 帧 - 哎呀。

    您可以使用SCNShape类从 Bézier 路径创建拉伸形状。诀窍是从 non-transparent 像素的形状中制作最简单的路径。 (你想要的是形成轮廓轮廓的路径,而不是每个像素的一堆方形路径的并集 - 否则你就会回到立方体 problem.)

    这是一个非常重要的计算几何,但是那里有解决方案。并且有一些外部工具可以离线跟踪(大多数设计用于为 SpriteKit 制作 sprite-based 物理主体,之后它成为 iOS 8/OS X 中的 SpriteKit 功能 10.10):这是一个

    一旦你有了这条路径,就可以从它做出SCNShape,将你的图像 texture-map 放在形状的前面(如果你愿意,也可以做背面),并对边做一个平面颜色:

    UIImage *image = [UIImage imageNamed:@"sprite"];
    UIBezierPath *path = PathFromImage(image); // Make or load your path here
    SCNNode *node = [SCNNode nodeWithGeometry:[SCNShape shapeWithPath:path extrusionDepth:1]];
    SCNMaterial *face = [SCNMaterial material];
    face.diffuse.contents = image;
    face.diffuse.magnificationFilter = SCNFilterModeNone;
    SCNMaterial *side = [SCNMaterial material];
    side.diffuse.contents = [UIColor blackColor];
    side.specular.contents = [UIColor whiteColor];
    node.geometry.materials = @[ face, side, side ];
    

    这是使用SCNShape代替的仪表:

    3 draws,276 个多边形,828 个顶点

    我们将数字减少了两个数量级,相应地帧速率要好得多 - 当模型旋转时,我不能让它降到 60 fps 以下。

相关问题