【问题标题】:SceneKit. How to achieve default scene light behavior without autoenablesDefaultLighting?场景套件。如何在没有 autoenablesDefaultLighting 的情况下实现默认场景光行为?
【发布时间】:2022-12-12 07:06:10
【问题描述】:

我尝试为我的 SCNView 设置 autoenablesDefaultLighting=true,它看起来不错。但是我想在没有autoenablesDefaultLighting的情况下通过设置灯光并稍微调整一下来实现相同的行为。

我用这段代码尝试了全光灯:

let lightNode = SCNNode()
lightNode.light = SCNLight()
lightNode.light?.castsShadow = true
lightNode.light?.type = .omni
lightNode.light?.intensity = 10000
lightNode.position = SCNVector3(x: 0, y: 0, z: 100)
scene.rootNode.addChildNode(lightNode)

得到这个:

通过autoenablesDefaultLighting=true,我得到了这个:

【问题讨论】:

  • 你的光强度太高了,把它从 10000 设置到 1000
  • 是的。但是你看到边框是黑色的,但它们应该像在默认闪电的图像上一样。所以如果我将它设置为 1000,它们会更暗,那么它有什么帮助呢?
  • 您可以使用光的位掩码来定义要在哪些表面上发光。您可以尝试将此光位掩码设为 -1 吗? (-1 意味着闪耀一切)。如果没有,是否可以分享您的项目?
  • 我认为默认照明是由定向光和环境光组成的,而不是泛光灯。

标签: swift scenekit


【解决方案1】:

自定义默认照明

我相信,在 SceneKit 中,默认场景照明是没有任何阴影的定向光,直接附加到默认相机节点(即 pointOfView 节点)。要模拟与 .autoenablesDefaultLighting 属性为 true 时相同的照明条件,请使用以下代码:

委托的渲染器方法——光的位置方向将每秒更新 60 次:

import SceneKit

extension GameViewController: SCNSceneRendererDelegate {
    
    func renderer(_ renderer: SCNSceneRenderer,
           updateAtTime time: TimeInterval) {
        
        sunNode.transform = (sceneView?.pointOfView?.worldTransform)!
        
        let cameraAngles = (self.sceneView?.pointOfView?.eulerAngles)!
        let lightAngles = self.sunNode.eulerAngles
        
        print("Camera: " + String(format: "%.2f, %.2f, %.2f", cameraAngles.x,
                                                              cameraAngles.y,
                                                              cameraAngles.z))

        print("Light: " + String(format: "%.2f, %.2f, %.2f", lightAngles.x,
                                                             lightAngles.y,
                                                             lightAngles.z))
    }
}

这是 GameViewController 类:

class GameViewController: NSViewController {
    
    var sceneView: SCNView? = nil
    let sunNode = SCNNode()
    
    override func viewDidLoad() {
        super.viewDidLoad()
       
        sceneView = self.view as? SCNView
        sceneView?.delegate = self
        let scene = SCNScene(named: "ship.scn")!
        sceneView?.scene = scene
        
        sceneView?.scene?.lightingEnvironment.contents = .none
        sceneView?.scene?.background.contents = .none
        
        sceneView?.backgroundColor = .black
        sceneView?.allowsCameraControl = true
        // sceneView?.autoenablesDefaultLighting = true
        
        sunNode.light = SCNLight()
        sunNode.light?.type = .directional
        sceneView?.scene?.rootNode.addChildNode(sunNode)
    }
}

说明

我想补充一点,如果场景中根本没有光(包括autoenablesDefaultLighting参数),那么场景中唯一无法控制的光源将是不可切换的环境光。

除了上述之外,基于物理的着色器始终需要额外的环境光灯具(否则基于物理的表面将是黑色的)。该光源的位置和方向无关紧要。

如果 Directional Light 垂直照亮表面,则表面以 100% 强度照亮(默认强度为 1000 流明),但如果光源的光线与表面平行,则表面不会被此光源照亮。

如您所见,第一张和最后一张图像具有相同的照明环境。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-05
    • 1970-01-01
    • 2023-01-13
    • 1970-01-01
    相关资源
    最近更新 更多