swift – 透明SCNFloor上的SceneKit阴影()
我有一个地板节点,我需要从定向光投射阴影.此节点需要透明(在AR环境中使用).
当我使用ARKit时这个工作正常,但使用SceneKit的相同设置显示没有阴影或反射.我怎样才能像这样在SceneKit中投射阴影? SceneKit的问题是由于我设置了sceneView.backgroundColor = .clear这一事实引起的 – 但我在这个应用程序中需要这种行为.这可以以某种方式避免吗? 示例代码,演示此问题(仅适用于设备,不适用于模拟器): @IBOutlet weak var sceneView: SCNView! { didSet { sceneView.scene = SCNScene() let cameraNode = SCNNode() cameraNode.camera = SCNCamera() sceneView.pointOfView = cameraNode let testNode = SCNNode(geometry: SCNBox(width: 1,height: 1,length: 1,chamferRadius: 0)) testNode.position = SCNVector3(x: 0,y: 0,z: -5) sceneView.scene!.rootNode.addChildNode(testNode) let animation = SCNAction.rotateBy(x: 0,y: .pi,z: 0,duration: 3.0) testNode.runAction(SCNAction.repeatForever(animation),completionHandler: nil) let floor = SCNFloor() floor.firstMaterial!.colorBufferWriteMask = [] floor.firstMaterial!.readsFromDepthBuffer = true floor.firstMaterial!.writesToDepthBuffer = true floor.firstMaterial!.lightingModel = .constant let floorNode = SCNNode(geometry: floor) floorNode.position = SCNVector3(x: 0,y: -2,z: 0) sceneView.scene!.rootNode.addChildNode(floorNode) let light = SCNLight() light.type = .directional light.shadowColor = UIColor(red: 0,green: 0,blue: 0,alpha: 0.5) light.color = UIColor.white light.castsShadow = true light.automaticallyAdjustsShadowProjection = true light.shadowMode = .deferred let sunLightNode = SCNNode() sunLightNode.position = SCNVector3(x: 1_000,y: 1_000,z: 0) sunLightNode.rotation = SCNVector4(x: 1,w: .pi * 1.5) sunLightNode.light = light sceneView.scene!.rootNode.addChildNode(sunLightNode) let omniLightNode: SCNNode = { let omniLightNode = SCNNode() let light: SCNLight = { let light = SCNLight() light.type = .omni return light }() omniLightNode.light = light return omniLightNode }() sceneView.scene!.rootNode.addChildNode(omniLightNode) } } override func viewDidLoad() { super.viewDidLoad() let tapGR = UITapGestureRecognizer(target: self,action: #selector(toggleTransparent)) view.addGestureRecognizer(tapGR) } @objc func toggleTransparent() { transparent = !transparent } var transparent = false { didSet { sceneView.backgroundColor = transparent ? .clear : .white } } 以下是macOS的相同示例,构建在SceneKit游戏项目之上: import SceneKit import QuartzCore class GameViewController: NSViewController { override func viewDidLoad() { super.viewDidLoad() // create a new scene let scene = SCNScene(named: "art.scnassets/ship.scn")! // create and add a camera to the scene let cameraNode = SCNNode() cameraNode.camera = SCNCamera() scene.rootNode.addChildNode(cameraNode) // place the camera cameraNode.position = SCNVector3(x: 0,z: 15) let testNode = SCNNode(geometry: SCNBox(width: 1,z: -5) scene.rootNode.addChildNode(testNode) let animation = SCNAction.rotateBy(x: 0,z: 0) scene.rootNode.addChildNode(floorNode) let light = SCNLight() light.type = .directional light.shadowColor = NSColor(red: 0,alpha: 0.5) light.color = NSColor.white light.castsShadow = true light.automaticallyAdjustsShadowProjection = true light.shadowMode = .deferred let sunLightNode = SCNNode() sunLightNode.position = SCNVector3(x: 1_000,w: .pi * 1.5) sunLightNode.light = light scene.rootNode.addChildNode(sunLightNode) let omniLightNode: SCNNode = { let omniLightNode = SCNNode() let light: SCNLight = { let light = SCNLight() light.type = .omni return light }() omniLightNode.light = light return omniLightNode }() scene.rootNode.addChildNode(omniLightNode) // retrieve the SCNView let scnView = self.view as! SCNView // set the scene to the view scnView.scene = scene // allows the user to manipulate the camera scnView.allowsCameraControl = true // configure the view scnView.backgroundColor = .clear // scnView.backgroundColor = .white // shadow works in this mode,but I need it to be clear } } 示例项目: MacOS:https://www.dropbox.com/s/1o50mbgzg4gc0fg/Test_macOS.zip?dl=1 iOS:https://www.dropbox.com/s/fk71oay1sopc1vp/Test.zip?dl=1 在macOS中你可以在ViewController的最后一行更改backgroundColor – 我需要它清楚,所以我可以在它下面显示相机预览. 在下面的图片中,您可以看到当sceneView.backgroundColor为白色时,以及下面 – 清除时的样子.在清晰版本上没有阴影. 解决方法
第一:您需要将其作为节点连接到场景,而不是几何类型. let floor = SCNNode() floor.geometry = SCNFloor() floor.geometry?.firstMaterial!.colorBufferWriteMask = [] floor.geometry?.firstMaterial!.readsFromDepthBuffer = true floor.geometry?.firstMaterial!.writesToDepthBuffer = true floor.geometry?.firstMaterial!.lightingModel = .constant scene.rootNode.addChildNode(floor) 隐形SCNFloor()上的阴影: 可见SCNPlane()上的阴影和我们的相机在SCNFloor()下:
第二:对于macOS,必须像这样设置阴影颜色: lightNode.light!.shadowColor = NSColor(calibratedRed: 0,alpha: 0.5) …对于iOS,它看起来像这样: lightNode.light!.shadowColor = UIColor(white: 0,alpha: 0.5) 此处的Alpha分量(alpha:0.5)是阴影的不透明度,RGB分量(白色:0)是阴影的黑色. 附:
在这个特殊情况下,当sceneView.backgroundColor = .clear时,我无法捕捉到强大的阴影,因为你需要在RGBA = 1,1,1(白色模式:白色,alpha = 1)和RGBA = 0之间切换,0(清除模式:黑色,alpha = 0). 为了在背景上看到半透明阴影,组件应该是RGB = 1,1和A = 0.5,但是由于SceneKit的内部合成机制,这些值会使图像变白.但是当我设置RGB = 1,1和A = 0.02时,阴影非常微弱. 现在这是一个可容忍的解决方法(在解决方案部分查找下面的解决方案): @objc func toggleTransparent() { transparent = !transparent } var transparent = false { didSet { // this shadow is very FEEBLE and it's whitening BG image a little bit sceneView.backgroundColor = transparent ? UIColor(white: 1,alpha: 0.02) : .white } } let light = SCNLight() light.type = .directional if transparent == false { light.shadowColor = UIColor(white: 0,alpha: 0.9) } 如果我设置light.shadowColor = UIColor(白色:0,alpha:1)我将在BG图像上获得令人满意的阴影,但在白色上获得纯黑色阴影.
这是OVER操作的公式:
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |