代码之家  ›  专栏  ›  技术社区  ›  tospig

使SCNNode透明,以便通过它查看其他节点

  •  0
  • tospig  · 技术社区  · 1 年前

    如何使圆柱体透明,以便始终通过圆柱体看到绿色的墙,而不管绿色的alpha值如何?

    问题描述

    (末尾为完整代码)

    我有一个 SCNNode() 定义为两个正方形(形成立方体的两侧),材料定义为

    var meshMaterial: SCNMaterial = {
        let mat = SCNMaterial()
        mat.diffuse.contents = UIColor.green
        mat.lightingModel = .constant
        return mat
    }()
    

    我在每面墙上放置两个圆柱体,圆柱体的不透明度设置为0.3。你可以透过圆柱体看到绿色的墙壁。

    enter image description here

    问题

    当我设置 meshMaterial 的alpha为1.0以外的任何值

    var meshMaterial: SCNMaterial = {
        let mat = SCNMaterial()
        mat.diffuse.contents = UIColor.green.withAlphaComponent(0.5)
        mat.lightingModel = .constant
        return mat
    }()
    

    你再也看不到穿过圆柱体的绿色墙壁了。相反,你可以通过Clinders看到黑色背景

    enter image description here

    在特定的旋转角度下 可以 通过圆柱体看到绿色(本例中为右侧墙圆柱体)

    enter image description here

    游戏场

    以下是复制该问题的完整游乐场代码。

    import UIKit
    import SceneKit
    import PlaygroundSupport
    import SceneKit.ModelIO
    
    // MARK: Set up Scene
    let scene = SCNScene()
    
    var sceneView: SCNView = {
        let sv = SCNView(frame: CGRect(x: 0, y: 0, width: 800, height: 800))
        sv.autoenablesDefaultLighting = false
        sv.allowsCameraControl = true
        sv.backgroundColor = .black
        sv.scene = scene
        return sv
    }()
    
    var cameraNode: SCNNode = {
        let n = SCNNode()
        n.camera = SCNCamera()
        n.camera?.contrast = 0.0
        n.camera?.wantsHDR = false
        n.position = SCNVector3(x: 0, y: 0, z: 10)
        //n.addChildNode(omniLightNode)
        return n
    }()
    
    var ambientLightNode: SCNNode = {
        let n = SCNNode()
        n.light = SCNLight()
        n.light!.type = SCNLight.LightType.ambient
        n.light!.intensity = 100
        return n
    }()
    
    private var omniLightNode: SCNNode = {
        let n = SCNNode()
        n.light = SCNLight()
        n.light!.type = SCNLight.LightType.directional
        n.light!.color = UIColor.white
        n.position = SCNVector3(x: 0, y: 10, z: 0)
        n.light!.intensity = 800
        return n
    }()
    
    scene.rootNode.addChildNode(omniLightNode)
    scene.rootNode.addChildNode(ambientLightNode)
    scene.rootNode.addChildNode(cameraNode)
    
    PlaygroundPage.current.liveView = sceneView
    
    // MARK: - Mesh
    let vertices: [SCNVector3] = [
        // back square
        SCNVector3(-1, -1,  0),
        SCNVector3( 1, -1,  0),
        SCNVector3( 1,  1,  0),
        SCNVector3(-1,  1,  0),
        
        // right wall
        SCNVector3(1,  -1,  0),
        SCNVector3(1,  -1,  2),
        SCNVector3(1,   1,  2),
        SCNVector3(1,   1,  0)
    ]
    let vertexSource = SCNGeometrySource(vertices: vertices)
    
    let indices: [Int32] = [
        0,1,2,
        0,2,3,
        
        4,5,6,
        4,6,7
    ]
    let indexElement = SCNGeometryElement(
        indices: indices,
        primitiveType: .triangles
    )
    
    let textures: [CGPoint] = [
        CGPoint(x: 0, y: 0),
        CGPoint(x: 0, y: 1),
        CGPoint(x: 1, y: 1),
        CGPoint(x: 1, y: 0),
        
        CGPoint(x: 0, y: 0),
        CGPoint(x: 0, y: 1),
        CGPoint(x: 1, y: 1),
        CGPoint(x: 1, y: 0)
    ]
    let textureSource = SCNGeometrySource(textureCoordinates: textures)
    let meshGeometry = SCNGeometry(
        sources: [vertexSource, textureSource],
        elements: [indexElement]
    )
    
    
    var meshMaterial: SCNMaterial = {
        let mat = SCNMaterial()
        mat.diffuse.contents = UIColor.green.withAlphaComponent(0.5) // <-- set alpha to 1.0 
        mat.lightingModel = .constant
        return mat
    }()
    
    meshGeometry.materials = [meshMaterial]
    let meshNode = SCNNode(geometry: meshGeometry)
    meshNode.position = SCNVector3(0, 0, 0)
    
    // MARK: Cylinders
    
    // Define a Node to hold the cylinders
    let shapeNode = SCNNode()
    shapeNode.position = SCNVector3(0, 0, 0)
    
    let cylinderBack = SCNNode(
        geometry: SCNCylinder(
            radius: 0.1,
            height: 1.0
        )
    )
    
    let cylinderRight = SCNNode(
        geometry: SCNCylinder(
            radius: 0.1,
            height: 1.0
        )
    )
    
    let cylinderMaterial: SCNMaterial = {
        let mat = SCNMaterial()
        mat.lightingModel = .physicallyBased
        mat.diffuse.contents = UIColor.red
        mat.roughness.contents = 0.8
        mat.metalness.contents = 0.4
        return mat
    }()
    
    cylinderBack.geometry?.materials = [cylinderMaterial]
    cylinderBack.position = SCNVector3(0, 0, 0.05)
    
    cylinderRight.geometry?.materials = [cylinderMaterial]
    cylinderRight.position = SCNVector3(1, 0, 1)
    
    // Set Cylinders opacity
    shapeNode.opacity = 0.3
    
    
    sceneView.scene?.rootNode.addChildNode(meshNode)
    sceneView.scene?.rootNode.addChildNode(shapeNode)
    
    shapeNode.addChildNode(cylinderBack)
    shapeNode.addChildNode(cylinderRight)
    
    1 回复  |  直到 1 年前
        1
  •  1
  •   codetiger    1 年前

    问题在于渲染顺序,这对于实现正确的透明度非常重要。有很多方法可以解决这个问题,一个简单的选择是将几何体设计为不重叠,这会使排序变得困难。或者使用设置手动渲染顺序 renderingOrder

    有一篇帖子详细介绍了这个话题。 https://stackoverflow.com/a/60840898/409315