在学习游戏 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 提高到了约 30 fps。其他统计信息如下(来自SCNView中显示的统计信息):
10K(我认为这是绘制调用?)
120K(我认为这是面孔)
360K(假设这是顶点数)
大部分运行循环都在渲染中(我估计 98%)。总循环时间为 26.7 毫秒(哎呀)。我在 2013 年末推出的 Mac Pro(6 核,双 D500 GPU)上运行。
鉴于《我的世界》风格的游戏的景观会根据玩家的动作不断变化,我不知道如何在场景套件的范围内对其进行优化。非常令人失望,因为我真的很喜欢这个框架。我很想听听有人对如何解决这个问题的想法 - 否则,我将被迫使用 OpenGL。
2014 年 12 月 30 日下午 2:00 更新(东部时间):使用 flattenedClone() 时,我发现性能显着提高。即使有更多的框和两次绘图调用,FPS 现在也能保持稳定的 60 fps。然而,适应动态环境(如 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 的不可变几何约束意味着我无法利用该框架。