在SceneKit中背面剔除

时间:2015-12-07 21:57:36

标签: ios swift scenekit

我正在尝试在场景套件中设置一个旋转球。我创造了球,并在其上应用了纹理。

ballMaterial.diffuse.contents = UIImage(named: ballTexture)
ballMaterial.doubleSided = true
ballGeometry.materials = [ballMaterial]

当前的ballTexture是一个半透明的纹理,因为我希望看到背面滚动。

然而,我得到了一些奇怪的剔除,即使doubleSided属性设置为true,也只会显示一半背面多边形。

任何帮助都将不胜感激,谢谢。

2 个答案:

答案 0 :(得分:13)

这是因为透明度的影响取决于绘制顺序。 SceneKit不知道在面向正面之前绘制球体的背面多边形。 (事实上​​,如果没有为每个帧重新组织GPU上的顶点缓冲区,它就无法真正做到这一点,这将对渲染性能造成巨大拖累。)

SCNSphere的顶点布局使其设置为地球上的纬度/长度网格:三角形沿着0°到360°的子午线顺序渲染,因此取决于球体的方向相对于相机,球体远端的一些面将在较近的面前渲染。

要解决此问题,您需要直接或通过深度缓冲区强制渲染顺序。这是一种方法,使用内部表面的单独材料来说明差异。

// add two balls, one a child of the other
let node = SCNNode(geometry: SCNSphere(radius: 1))
let node2 = SCNNode(geometry: SCNSphere(radius: 1))
scene.rootNode.addChildNode(node)
node.addChildNode(node2)

// cull back-facing polygons on the first ball
// so we only see the outside
let mat1 = node.geometry!.firstMaterial!
mat1.cullMode = .Back
mat1.transparent.contents = bwCheckers
// my "bwCheckers" uses black for transparent, white for opaque
mat1.transparencyMode = .RGBZero

// cull front-facing polygons on the second ball
// so we only see the inside
let mat2 = node2.geometry!.firstMaterial!
mat2.cullMode = .Front
mat2.diffuse.contents = rgCheckers

// sphere normals face outward, so to make the inside respond
// to lighting, we need to invert them
let shader = "_geometry.normal *= -1.0;"
mat2.shaderModifiers = [SCNShaderModifierEntryPointGeometry: shader]

2-sided ball

(最后的着色器修改器位不是必需的 - 它只是使内部材质得到漫反射着色。您也可以使用不涉及法线或光照的材质属性,例如emission ,取决于你想要的外观。)

您也可以通过禁用writesToDepthBuffer使用带有双面材质的单个节点来执行此操作,但这也可能导致与其他场景内容的不良交互 - 您可能还需要使用{在这种情况下{3}}。

答案 1 :(得分:0)

macOS 10.13和iOS 11添加了SCNTransparencyMode.dualLayer,据我所知,它甚至不需要将isDoubleSided设置为true(文档完全不提供任何信息)。因此,对我有用的简单解决方案是:

ballMaterial.diffuse.contents = UIImage(named: ballTexture)
ballMaterial.transparencyMode = .dualLayer  
ballGeometry.materials = [ballMaterial]