我使用此方法来获取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;
}
答案 0 :(得分:3)
这个答案解决了最初提出的问题 - 如何合并几何。但是,合并几何图形似乎并不能解决您的实际问题 - 如何获得像素化&#34; sprite&#34;有一定厚度,性能不错。请参阅my other answer。
SCNNode
方法flattenedClone
会将节点子节点的所有几何体组合成一个具有单个几何体的节点。这将减少场景处理开销并在单个OpenGL绘图调用中渲染......但它也会使立方体不能独立移动并且所有共享相同的材料,因此它们不会是不同的颜色。此外,根据您希望如何排列多维数据集,您可能需要推送比GPU更多的顶点数据,这仍然会损害您的性能。
根据您正在寻求的效果,可能会有更好的解决方案。
答案 1 :(得分:2)
发布一个单独的答案,因为你的评论已经表明你实际上正在寻找的东西并不是你所要求的 - 我会留下另一个答案,因为它回答了最初提出的问题,即使它无法解决您的问题。
所以,听起来你真正需要的不是立方体的集合,每个立方体都可以独立移动,每个立方体都有自己的颜色,而是将2D形状挤压成3D - 特别是由不透明形成的形状图像的像素:
在这种情况下,制作一堆立方体确实会损害您的性能 - 以及您的渲染结果。查看此详细信息(来自使用多块立方体方法的版本):
那些小白点来自两个立方体相遇的圆角误差。这里的问题 - 无论你是否使用flattenedClone
- 是推送到GPU的几何数据描述了一大堆不可见的多边形(因为它们在两个立方体之间)或不相关(因为两个相邻立方体的共享面也可以是单个多边形)。这是我对多块立方体方法的测试中的性能指标:
这是408绘制,4.9K多边形,14.7K顶点。在iPad Air上旋转该模型每秒可获得14帧 - 哎呀。
您可以使用SCNShape
类从Bézier路径制作拉伸形状。诀窍就是从非透明像素的形状中制作最简单的路径。 (你想要的是形成轮廓轮廓的路径,而不是每个像素的一堆方形路径的并集 - 否则你就会回到立方体问题。)
这是一个非常重要的计算几何,但是there are solutions out there。并且有一些外部工具可以离线跟踪(大多数设计用于在SpriteKit成为iOS 8 / OS X 10.10中的SpriteKit功能之前为SpriteKit制作基于精灵的物理主体):here's one。< / p>
一旦你有了路径,就可以从中创建一个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 ];
这是使用SCNShape
代替的指标:
我们已经将数字减少了两个数量级,相应地帧速率要好得多 - 当模型旋转时,我无法将其降低到60 fps以下。