简体   繁体   English

组合两个或更多SCNGeometries

[英]Combining two or more SCNGeometries

I made this method to grab a UIImage and turn it into a 3D model. 我使用这种方法来获取UIImage并将其转换为3D模型。 However that means I add in a whole lot of nodes.. I was thinking maybe it could be optimized by adding all the geometries into a single node. 然而,这意味着我添加了大量节点。我想也许可以通过将所有几何添加到单个节点来优化它。 Is there a way to accomplish that? 有办法实现吗?

Here's the code 这是代码

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;
}

This answer addresses the question originally asked — how to merge geometries. 这个答案解决了最初提出的问题 - 如何合并几何。 However, merging geometries doesn't seem to be the solution to your actual problem — how to get a pixelated "sprite" with some thickness, with decent performance. 但是,合并几何图形似乎并不能解决您的实际问题 - 如何获得具有一定厚度的像素化“精灵”,并具有良好的性能。 See my other answer for that. 看到我的其他答案


The SCNNode method flattenedClone will combine all the geometries of a node's children into a single node with a single geometry. SCNNode方法flattenedClone将节点子节点的所有几何结构组合成具有单个几何的单个节点。 That'll cut down on scene processing overhead and render in a single OpenGL draw call... But it also will make the cubes not independently movable and all share the same material, so they won't be different colors. 这将减少场景处理开销并在单个OpenGL绘制调用中渲染......但它也会使立方体不能独立移动并且所有共享相同的材质,因此它们将不会是不同的颜色。 Moreover, depending on how you want your cubes arranged, you're probably pushing more vertex data than you need to the GPU, which can still hurt your performance. 此外,根据您希望多维数据集排列的方式,您可能会推送比GPU更多的顶点数据,这仍然会损害您的性能。

Depending on just what kind of effect you're going for, there are probably better solutions. 取决于你想要的效果,可能有更好的解决方案。

Posting a separate answer because your comments have shown that what you're actually looking for isn't quite what you're asking about — I'm leaving the other answer around because it answers the question as originally asked, even if it doesn't solve your problem. 发表一个单独的答案,因为你的评论已经证明你实际上正在寻找的并不是你所要求的 - 我会留下另一个答案,因为它回答了最初提出的问题,即使它没有解决你的问题。


So, it sounds like what you really need is not a collection of cubes, each independently movable and each with its own color, but rather the extrusion of a 2D shape into 3D — specifically, the shape formed by the non-transparent pixels of an image: 所以,听起来你真正需要的不是立方体的集合,每个立方体都可以独立移动,每个立方体都有自己的颜色,而是将2D形状挤压成3D - 具体地说,是由非透明像素形成的形状。图片:

矮胖的精灵

In that case, making a bunch of cubes will indeed hurt your performance — and your rendering results, too. 在这种情况下,制作一堆立方体确实会损害您的性能 - 以及您的渲染结果。 Check out this detail (from a version that uses the lots-of-cubes method): 查看此详细信息(来自使用批量多维数据集方法的版本):

文物

Those little white dots come from rounding errors where two cubes meet. 那些小白点来自两个立方体相遇的圆角误差。 The problem here — whether you use flattenedClone or not — is that the geometry data being pushed to the GPU describes a whole darn lot of polygons that are either invisible (because they're between two cubes) or irrelevant (because the shared face of two adjacent cubes could just as well be a single polygon). 这里的问题 - 无论你是否使用flattenedClone是推送到GPU的几何数据描述了一大堆多边形,这些多边形要么是不可见的(因为它们位于两个立方体之间),要么不相关(因为两个共享的面)相邻的立方体也可以是单个多边形)。 Here's the performance gauge from my test of the lots-of-cubes method: 这是我对多块立方体方法测试的性能指标:

408绘制,4.9K多边形,14.7K顶点

That's 408 draws, 4.9K polygons, 14.7K vertices. 这是408绘制,4.9K多边形,14.7K顶点。 Spinning that model on an iPad Air gets 14 frames per second — yuck. 在iPad Air上旋转该模型每秒可获得14帧 - 哎呀。

You can make an extruded shape from a Bézier path using the SCNShape class. 您可以使用SCNShape类从Bézier路径创建拉伸形状。 The trick to that is making the simplest possible path from the shape of your non-transparent pixels. 诀窍就是从非透明像素的形状中制作最简单的路径。 (You want the path that makes the outline of the shape, not the union of a bunch of square paths for each pixel — otherwise you're right back to the cubes problem.) (你想要的是形成轮廓轮廓的路径,而不是每个像素的一堆方形路径的并集 - 否则你就会回到立方体问题。)

That's a nontrivial bit of computational geometry, but there are solutions out there . 这是一个非常重要的计算几何,但有解决方案 And there are external tools that can do the tracing for you offline (most of them designed for making sprite-based physics bodies for SpriteKit back before that became a SpriteKit feature in iOS 8 / OS X 10.10): here's one . 并且有一些外部工具可以离线跟踪(大多数设计用于在SpriteKit成为iOS 8 / OS X 10.10中的SpriteKit功能之前为SpriteKit制作基于精灵的物理主体): 这是一个

Once you have the path, you can make a SCNShape from it, texture-map your image as onto the front of the shape (and the back, too, if you like), and use a flat color for the sides: 一旦你有了路径,你就可以从它做一个SCNShape ,将你的图像纹理映射到形状的正面(如果你愿意的话,也可以是背面),并对边使用平面颜色:

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 ];

Here's the gauge using an SCNShape instead: 这是使用SCNShape的量表:

3幅画,276个多边形,828个顶点

We've cut the numbers by two orders of magnitude, and correspondingly the framerate is much better — I can't get it to drop below 60 fps when the model is spinning. 我们将数字减少了两个数量级,相应地帧速率要好得多 - 当模型旋转时,我不能让它降到60 fps以下。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM