在某些iOS设备(iPhone 6s Plus)上,对象部分会有部分和任意消失。 怎么避免这个?
所有棒必须相同,并且是一个SCNNode的克隆。 16个复杂的SCNNode,来自3个SCNNode:盒子,球和棒。节点包含node.flattenedClone()的几何。
必须是这样的:
Сode片段:
func initBox()
{
var min: SCNVector3 = SCNVector3()
var max: SCNVector3 = SCNVector3()
let geom1 = SCNBox(width: boxW, height: boxH, length: boxL, chamferRadius: boxR)
geom1.firstMaterial?.reflective.contents = UIImage(data: BoxData)
geom1.firstMaterial?.reflective.intensity = 1.2
geom1.firstMaterial?.fresnelExponent = 0.25
geom1.firstMaterial?.locksAmbientWithDiffuse = true
geom1.firstMaterial?.diffuse.wrapS = SCNWrapMode.Repeat
let geom2 = SCNSphere(radius: 0.5 * boxH)
geom2.firstMaterial?.reflective.contents = UIImage(data: BalData)
geom2.firstMaterial?.reflective.intensity = 1.2
geom2.firstMaterial?.fresnelExponent = 0.25
geom2.firstMaterial?.locksAmbientWithDiffuse = true
geom2.firstMaterial?.diffuse.wrapS = SCNWrapMode.Repeat
let geom3 = SCNCapsule(capRadius: stickR, height: stickH)
geom3.firstMaterial?.reflective.contents = UIImage(data: StickData)
geom3.firstMaterial?.reflective.intensity = 1.2
geom3.firstMaterial?.fresnelExponent = 0.25
geom3.firstMaterial?.locksAmbientWithDiffuse = true
geom3.firstMaterial?.diffuse.wrapS = SCNWrapMode.Repeat
let box = SCNNode()
box.castsShadow = false
box.position = SCNVector3Zero
box.geometry = geom1
Material.setFirstMaterial(box, materialName: Materials[boxMatId])
let bal = SCNNode()
bal.castsShadow = false
bal.position = SCNVector3(0, 0.15 * boxH, 0)
bal.geometry = geom2
Material.setFirstMaterial(bal, materialName: Materials[balMatId])
let stick = SCNNode()
stick.castsShadow = false
stick.position = SCNVector3Zero
stick.geometry = geom3
stick.getBoundingBoxMin(&min, max: &max)
stick.pivot = SCNMatrix4MakeTranslation(0, min.y, 0)
Material.setFirstMaterial(stick, materialName: Materials[stickMatId])
box.addChildNode(bal)
box.addChildNode(stick)
boxmain = box.flattenedClone()
boxmain.name = "box"
}
将节点添加到场景中:
func Boxesset()
{
let Boxes = SCNNode()
Boxes.name = "Boxes"
var z: Float = -4.5 * radius
for _ in 0..<4
{
var x: Float = -4.5 * radius
for _ in 0..<4
{
let B: SCNNode = boxmain.clone()
B.position = SCNVector3(x: x, y: radius, z: z)
Boxes.addChildNode(B)
x += 3 * Float(radius)
}
z += 3 * Float(radius)
}
self.rootNode.addChildNode(Boxes)
}
这是经过测试,在模拟器上运行良好 - 所有设备, 在物理设备上 - iPad Retina和iPhone 5。
仅在超现代的iPhone 6s Plus(128 Gb)上观察到故障。
The problem is clearly visible on the video ->
通过将默认渲染API更改为OpenGL ES ...
,可以解决图形问题...但是在iPhone 6S Plus上与图形无关的纯计算模块中可能会出现意外问题。 (iPhone 6没有这样的问题)。
怎么了?
答案 0 :(得分:2)
TL; DR
将scnView.prepareObject(boxmain, shouldAbortBlock: nil)
添加到initBox
。
我快速查看了在6s Plus上运行的代码并看到了类似的结果。其中一个角落节点丢失了,并且每次运行都一直缺失。但我们没有运行相同的代码,我的错过了材料数据...
SceneKit是懒惰的,通常在将对象添加到场景之前不会完成任务。我首先从SceneKit原语(SCNSphere
等)中看到了这个提取几何体,当你通过以下行克隆某个东西的克隆时,你会发现它。
let B: SCNNode = boxmain.clone()
...
boxmain = box.flattenedClone()
我认为在第二次克隆发生之前,SceneKit根本没有完成克隆。我无法确定这一点。
删除第一个克隆为我解决了这个问题。例如,将boxmain = box.flattenedClone()
替换为boxmain = box
。但是我要说你所做的是最好的做法,展平这些节点会减少绘制调用次数并提高性能(可能不是6s的问题)。
SceneKit还提供了一个方法- prepareObject:shouldAbortBlock:
,它将在将对象添加到场景之前执行所需的操作(在本例中为.flattenedClone()
)。
将以下行添加到initBox
函数的末尾也可以解决问题并且是更好的解决方案。
scnView.prepareObject(boxmain, shouldAbortBlock: nil)
答案 1 :(得分:1)
简单地说,我不知道我的问题的正确答案,但我找到了一个可以接受的解决方案。
事实证明,这一切都在SCNMaterial的“漫反射”属性中。
无论出于何种原因,当diffuse = UIColor(...)时,Metal不太喜欢 但是,如果复合SCNNode中的至少一个元素(如我的情况)是diffuse.contents = UIImage(...),那么一切都开始完美。
它有效
diffuse=<SCNMaterialProperty: 0x7a6d50a0 | contents=<UIImage: 0x7a6d5b40> size {128, 128} orientation 0 scale 1.000000>
它不起作用
diffuse=<SCNMaterialProperty: 0x7e611a50 | contents=UIDeviceRGBColorSpace 0.25 0.25 0.25 0.99>
我发现问题的解决方案很简单:
我刚用diffuse.contents = UIColor(...)添加了一个带有diffuse.contents = UIImage(...)的小而不显眼的元素,并且效果很好。
所以,我的建议:
使用Metal时要小心。 (我在5S及以上设备上遇到问题)
在真实设备上彻底测试SceneKit应用程序,不要只信任模拟器
我希望,这是暂时的错误,它将在未来的Xcode版本中修复。
有一个不错的应用程序!
P.S。顺便说一句,完成的应用程序现在在AppStore中完全免费 Qubic: tic-tac-toe 4x4x4