在某些iOS设备(iPhone 6s Plus)上,对象部分部分或任意消失。
如何避免这种情况?

ios - 关于SCNNode渲染的奇怪错误/伪像-LMLPHP
ios - 关于SCNNode渲染的奇怪错误/伪像-LMLPHP

所有棒必须相同,并且是一个SCNNode的克隆。
16个复杂的SCNNode,来自3个SCNNode:盒子,球和棍子。通过node.flattenedClone()包含几何的节点。

必须是这样的:

ios - 关于SCNNode渲染的奇怪错误/伪像-LMLPHP

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 ->

ios - 关于SCNNode渲染的奇怪错误/伪像-LMLPHP

可以通过将默认渲染API更改为OpenGL ES来解决图形问题。

ios - 关于SCNNode渲染的奇怪错误/伪像-LMLPHP ios - 关于SCNNode渲染的奇怪错误/伪像-LMLPHP ios - 关于SCNNode渲染的奇怪错误/伪像-LMLPHP

...但是您可能会在与iPhone 6S Plus上的图形无关的纯计算模块中遇到意想不到的问题。 (iPhone 6没有此类问题)。

怎么了?

最佳答案

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)

关于ios - 关于SCNNode渲染的奇怪错误/伪像,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/34058503/

10-10 20:31