使用立方体测试的场景套件性能

Posted

技术标签:

【中文标题】使用立方体测试的场景套件性能【英文标题】:Scene Kit Performance with cube test 【发布时间】:2015-02-27 04:41:57 【问题描述】:

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

下面是我编写的一个循环,用于放置 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)

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

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

此更改似乎已将 FPS 提高到 ~30fps。其他统计数据如下(来自 SCNView 中显示的统计数据):

10K(我认为这是绘制调用?) 120K(我假设这是面孔) 360K(假设这是顶点数)

大部分运行循环都在渲染中(我估计 98%)。总循环时间为 26.7 毫秒(哎呀)。我在 2013 年末的 Mac Pro(6 核 w/双 D500 GPU)上运行。

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

更新 2014 年 12 月 30 日@美国东部时间下午 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 的不可变几何约束意味着我无法利用该框架。

【问题讨论】:

你在什么环境下测试?你的性能瓶颈在哪里?请参阅使用 SceneKit 构建游戏谈话 from WWDC 2014 了解追踪后者的技巧。 我不知道scenekit,但通常“幼稚”的方法会相当慢。考虑到像我的世界这样的游戏可能会确保不渲染任何完全被其他人隐藏的块,它实现了实例化(一次绘制相同的块)和其他一般和特定于游戏的优化。 SceneKit 是一个通用的渲染器,所以你必须尝试看看可以实现什么样的优化,什么最适合 SceneKit。如果您确定需要更多低级控制,则可能需要恢复为 GLKit 或原始 OpenGL。 10K 绘制调用方式太多了。尝试瞄准更接近 100 的值。您可以通过展平几何图形(flattenedClone())大大减少绘制调用的数量。如果稍后某个框应该被用户的操作分开,我会在该操作时处理该框,而不是让您的整个场景处于分离状态,因为用户可能会与之交互。 你做了什么决定?您可以使用 SceneKit 还是需要使用 OpenGL? 我认为 SceneKit 不能满足我的需求。我喜欢这个想法,并认为 Apple 在设计框架方面做得很好,但它不够灵活,无法满足我的需求。学习Metal框架是我目前的方向。可以肯定的是,学习曲线要​​高得多,但我一直很喜欢接近金属编程(双关语 - 汇编程序曾经是我最喜欢的语言)。 【参考方案1】:

正如您提到的 Minecraft,我认为值得研究一下它是如何工作的。

我没有给你的技术细节或代码示例,但一切都应该很简单:

您是否曾经在线玩过《我的世界》,并且无法加载地形让您看穿?那是因为里面没有几何体。

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

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

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

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

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

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

可能有大量类似 Minecraft 的渲染器论文,一些 google 将帮助您找出答案!

【讨论】:

我同意你的 cmets Moustach 但这种方法的挑战是 SCNGeometry 类。它支持你所说的一切,但它是不可变的。因此,您必须为 SCNGeometry 创建一个表示地形的网格,并且一旦发生变化,您就会转储该网格(我打赌巨大的内存释放周期)并重新创建所有内容以适应一个小的“块”变化。跨度> 没错,但您可以使用 Minecraft 的“Chunks”方法。通过在各种元素中分离几何,您可以单独测试它们中的每一个,看看是否需要考虑当前的 POV 来更新它们。除非用户移动得非常快,否则块不应超过每隔几帧更新一次,因为单个生成的网格可用于许多观点。并不是说您也可以渲染完整的对象,但仍然可以通过组合共面多边形和摆脱内部几何体进行优化。 如果你看到有人“玩得很好”我的世界,让我吃惊的是他们移动的速度有多快,以及 Minecraft 的反应是多么令人难以置信。我认为它持久的吸引力的一部分是它的性能令人难以置信。就减速而言,用户体验很少有烦恼。甚至项目的菜单也以惊人的速度弹出和交换。 考虑到它是用 Java 制作的,它非常令人印象深刻......但再一次,我们最多只谈论几千个多边形,几乎没有深度测试,没有真正的粒子,物理...... . 同意。它在图形或几何上没有太多意义。但是,有什么是引人入胜的、引人入胜的体验,部分(很大程度上?)是因为响应能力。当它滞后时,我见过玩它的孩子​​们听得见。他们将其性能视为体验的重要组成部分。

以上是关于使用立方体测试的场景套件性能的主要内容,如果未能解决你的问题,请参考以下文章

为啥不更新重绘场景?

如何让我的灯光相对于我的场景(在立方体中)保持固定?

Stone教程:如何在3D场景中使用音频和视频

Three.js - 立方体和球体与平面奇怪地剪裁

使用vue学习three.js之加载和使用纹理-使用CubeCamera创建反光效果,动态环境贴图实现,立方体全景贴图

带有立方体贴图的 OpenGL 点光阴影映射