当我使用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为白色时,以及下面 – 清除时的样子.在清晰版本上没有阴影.
解决方法
There are two steps to get a transparent shadow :
第一:您需要将其作为节点连接到场景,而不是几何类型.
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)
可见SCNPlane()上的阴影和我们的相机在SCNFloor()下:
For getting a
transparent shadow
you need to set ashadow color
,not theobject's transparency itself
.
第二:对于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
switching between.clear
colour and.white
colour.
在这个特殊情况下,当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图像上获得令人满意的阴影,但在白色上获得纯黑色阴影.
SOLUTION:
You should grab a render of 3D objects to have premultiplied RGBA image with its useful Alpha channel. After that,you can composite
rgba image of cube and its shadow
overimage of nature
using classicalOVER
compositing operation in another View.
这是OVER操作的公式:
(RGB1 * A1) + (RGB2 * (1 – A1))
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。