在学习游戏的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的不可变几何约束意味着我无法利用框架。
答案 0 :(得分:0)
正如你提到的Minecraft,我认为值得研究它是如何运作的。
我没有技术细节或代码示例,但一切都应该是非常直接的:
你有没有在网上玩过我的世界,地形没有加载让你透透?那是因为里面没有几何形状。
让我们假设我有一个2x2x2的立方体数组。这使得2 * 2 * 2 * 6 * 2 = 96个三角形。
但是,如果从相机的角度测试和绘制可见光上的多边形,可能是通过测试法线(因为它是立方体),这个数字可以下降到48个三角形。
如果你找到一种方法来查看哪些面被其他面遮挡(考虑到你正在使用平面,背面,基于网格的面,这不应该太难)你只能绘制这些面。这样,我们绘制了8到24个三角形。这是高达90%的优化。
如果你想变得非常深,你甚至可以组合面部,从可见的平面上制作一个N-gon。如果您创建一种新的方法来动态生成几何体,并且在同一平面上测试相邻的可见面,则可以这样做。
如果你成功了,我们会说2到6个多边形而不是96个,来渲染8个立方体。
请注意,最后一种方法仅在您的块相互接触时才有效。
可能有大量类似Minecraft的渲染器文件,一些谷歌将帮助您解决这个问题!