场景套件性能与立方体测试

时间:2014-12-31 02:00:30

标签: swift performance optimization 3d scenekit

在学习游戏的3D图形编程时,我决定通过使用Scene Kit 3D API开始简单。我的第一个游戏目标是构建一个非常简化的模拟MineCraft。只是立方体的游戏 - 它有多难。

下面是我编写的一个循环,用于放置100 x 100立方体(10,000)并且FPS性能非常差(~20 FPS)。对于Scene Kit,我的初始游戏目标是否过多,或者有更好的方法来解决这个问题吗?

我已阅读StackExchange上的其他主题,但感觉不到他们回答我的问题。将暴露的表面块转换为单个网格将不起作用,因为SCNGeometry是不可变的。

func createBoxArray(scene : SCNScene, lengthCount: Int, depthCount: Int) {
    let startX : CGFloat = -(CGFloat(lengthCount) * CUBE_SIZE) + (CGFloat(lengthCount) * CUBE_MARGIN) / 2.0
    let startY : CGFloat = 0.0
    let startZ : CGFloat = -(CGFloat(lengthCount) * CUBE_SIZE) + (CGFloat(lengthCount) * CUBE_MARGIN) / 2.0

    var currentZ : CGFloat = startZ

    for z in 0 ..< depthCount {
        currentZ += CUBE_SIZE + CUBE_MARGIN

        var currentX = startX
        for x in 0 ..< lengthCount {
            currentX += CUBE_SIZE + CUBE_MARGIN

            createBox(scene, x: currentX, y: startY, z: currentZ)
        }
    }
}


func createBox(scene : SCNScene, x: CGFloat, y: CGFloat, z: CGFloat) {
    var box = SCNBox(width: CUBE_SIZE, height: CUBE_SIZE, length: CUBE_SIZE, chamferRadius: 0.0)
    box.firstMaterial?.diffuse.contents = NSColor.purpleColor()

    var boxNode = SCNNode(geometry: box)
    boxNode.position = SCNVector3Make(x, y, z)
    scene.rootNode.addChildNode(boxNode)
}

更新12-30-2014: 我修改了代码,以便创建SCNBoxNode一次,然后通过以下方式创建100 x 100数组中的每个附加框:

var newBoxNode = firstBoxNode.clone()
newBoxNode.position = SCNVector3Make(x, y, z)

此更改似乎将FPS增加到~30fps。其他统计信息如下(根据SCNView中显示的统计信息):

10K(我假设这是抽奖电话?) 120K(我假设这是面孔) 360K(假设这是顶点计数)

大部分运行循环都在渲染中(我估计是98%)。总循环时间为26.7ms(ouch)。我正在使用Mac Pro Late 2013(6核w / Dual D500 GPU)。

鉴于MineCraft风格的游戏有一个根据玩家行为不断变化的风景,我不知道如何在Scene Kit的范围内优化它。令我非常失望,因为我非常喜欢这个框架。我很想听听别人对如何解决这个问题的看法 - 没有这个,我不得不使用OpenGL。

更新12-30-2014 @美国东部时间下午2:00: 使用flattenedClone()时,我看到了显着的性能提升。即使有更多的盒子和两个绘图调用,FPS现在也是稳定的60fps。然而,适应动态环境(正如MineCraft支持)仍然存在问题 - 见下文。

由于数组会随着时间的推移改变成分,我添加了一个keyDown处理程序,以便在现有的时候添加一个更大的盒子数组,并定时添加盒子数组之间的差异,从而产生更多的调用,而不是添加为flattenedClone。这是我发现的:

在keyDown上我添加另一个120 x 120盒(14,400盒)的数组

// This took .0070333 milliseconds
scene?.rootNode.addChildNode(boxArrayNode)
// This took .02896785 milliseconds
scene?.rootNode.addChildNode(boxArrayNode.flattenedClone())

再次调用flattenedClone()比添加数组慢4倍。

这导致两个绘图调用具有293K个面和878K个顶点。我还在玩这个,如果我发现任何新内容,我会更新。最重要的是,通过我的额外测试,我仍然觉得Scene Kit的不可变几何约束意味着我无法利用框架。

1 个答案:

答案 0 :(得分:0)

正如你提到的Minecraft,我认为值得研究它是如何运作的。

我没有技术细节或代码示例,但一切都应该是非常直接的:

你有没有在网上玩过我的世界,地形没有加载让你透透?那是因为里面没有几何形状。

让我们假设我有一个2x2x2的立方体数组。这使得2 * 2 * 2 * 6 * 2 = 96个三角形。

但是,如果从相机的角度测试和绘制可见光上的多边形,可能是通过测试法线(因为它是立方体),这个数字可以下降到48个三角形。

如果你找到一种方法来查看哪些面被其他面遮挡(考虑到你正在使用平面,背面,基于网格的面,这不应该太难)你只能绘制这些面。这样,我们绘制了8到24个三角形。这是高达90%的优化。

如果你想变得非常深,你甚至可以组合面部,从可见的平面上制作一个N-gon。如果您创建一种新的方法来动态生成几何体,并且在同一平面上测试相邻的可见面,则可以这样做。

如果你成功了,我们会说2到6个多边形而不是96个,来渲染8个立方体。

请注意,最后一种方法仅在您的块相互接触时才有效。

可能有大量类似Minecraft的渲染器文件,一些谷歌将帮助您解决这个问题!