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

Dea*_*xel 13 3d optimization performance scenekit swift

在学习游戏的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)
}
Run Code Online (Sandbox Code Playgroud)

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

var newBoxNode = firstBoxNode.clone()
newBoxNode.position = SCNVector3Make(x, y, z)
Run Code Online (Sandbox Code Playgroud)

这种变化似乎使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())
Run Code Online (Sandbox Code Playgroud)

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

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

Mou*_*ach 0

正如您提到的《我的世界》,我认为值得研究一下它的运作方式。

我没有为您提供技术细节或代码示例,但一切都应该非常简单:

你是否曾经玩过在线《我的世界》,但地形无法加载让你无法看清?那是因为里面没有几何图形。

假设我有一个 2x2x2 的立方体数组。这就是 2*2*2*6*2 = 96 个三角形。

然而,如果您仅测试并绘制从相机角度可见的多边形,也许通过测试法线(很容易,因为它是立方体),这个数字会下降到 48 个三角形。

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

如果你想变得非常深入,你甚至可以组合面,从可见的平面中形成一个 N 边形。如果您创建一种新的方法来动态生成几何图形,该方法结合了前面的两种方法并测试同一平面上的相邻可见面,则可以做到这一点。

如果成功,我们将使用 2 到 6 个多边形而不是 96 个多边形来渲染 8 个立方体。

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

可能有大量类似《我的世界》的渲染文件,谷歌一下就能帮你搞清楚!