【问题标题】:Back face culling in SceneKitSceneKit 中的背面剔除
【发布时间】:2019-01-30 01:07:45
【问题描述】:

我目前正在尝试在场景套件中设置一个旋转球。我已经创建了球并对其应用了纹理。

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

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

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

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

【问题讨论】:

    标签: ios swift scenekit


    【解决方案1】:

    发生这种情况是因为透明度的效果取决于绘制顺序。 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]
    

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

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

    【讨论】:

    • 谢谢。我怀疑我需要创建两个带有前后剔除的对象。
    • 我没想到着色器,现在看起来很棒!
    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 2017-12-16
      • 1970-01-01
      • 2014-09-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多