如何使圆柱体透明,以便无论绿色的 alpha 值如何,您始终可以透过它们看到绿色的墙壁?
(完整代码在最后)
我有一个
SCNNode()
定义为两个正方形(形成立方体的两侧),其材质定义为
var meshMaterial: SCNMaterial = {
let mat = SCNMaterial()
mat.diffuse.contents = UIColor.green
mat.lightingModel = .constant
return mat
}()
我在每面墙上放置两个圆柱体,圆柱体的不透明度设置为 0.3。透过圆柱体你可以看到绿色的墙壁。
当我将
meshMaterial
的 alpha 设置为 1.0 以外的任何值时
var meshMaterial: SCNMaterial = {
let mat = SCNMaterial()
mat.diffuse.contents = UIColor.green.withAlphaComponent(0.5)
mat.lightingModel = .constant
return mat
}()
你再也无法透过圆柱体看到绿色的墙壁了。相反,你透过气缸看到黑色背景
在某些旋转角度,您可以透过圆柱体(本例中的右壁圆柱体)看到绿色
这是复制该问题的完整 Playground 代码。
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)
问题在于渲染顺序,这对于实现正确的透明度非常重要。有很多方法可以解决这个问题,一个简单的选择是将几何图形设计为不相互重叠,这使得排序变得困难。或者使用
renderingOrder
设置手动渲染顺序
有一篇文章详细讨论了这个主题。 https://stackoverflow.com/a/60840898/409315