如何在 SceneKit 中实现逼真的景深效果?

How to achieve realistic Depth of Field effect in SceneKit?

我正在尝试渲染具有真实景深效果的帧。我已经在 camera 节点中尝试了景深属性,但它没有产生可用的结果。

有景深效果的最大渲染质量切换吗?性能不是一个因素,我只需要渲染一帧,用户可以等待。

SceneKit 无法(开箱即用)进行这种类型的繁重、高质量 post 处理或静态图像渲染计算。从理论上讲,您可能会构建一个使用其渲染方法来完成这两项工作的设置。但它不是高质量的渲染器。如果用户可以等待,而你真的想关注图像质量,Unreal Engine 有能力做这种事情,内置的,质量更高 post 处理,效果,灯光,材质、粒子和渲染。

SceneKit 中逼真的景深效果

在 SceneKit 中,您可以轻松实现炫酷的 shallow/deep 景深 (DoF)。而且它的处理不是非常强烈。 .focusDistance.fStop 参数对于应用 DoF 至关重要:

cameraNode.camera?.wantsDepthOfField = true
cameraNode.camera?.focusDistance = 5
cameraNode.camera?.fStop = 0.01
cameraNode.camera?.focalLength = 24


使用以下代码进行测试(macOS版本):

import SceneKit
import Cocoa

class GameViewController: NSViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        let scene = SCNScene()
        
        let cameraNode = SCNNode()
        cameraNode.camera = SCNCamera()
        cameraNode.camera?.wantsDepthOfField = true
        cameraNode.camera?.focusDistance = 5
        cameraNode.camera?.fStop = 0.01
        cameraNode.camera?.focalLength = 24
        scene.rootNode.addChildNode(cameraNode)
        cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)
        
        let lightNode = SCNNode()
        lightNode.light = SCNLight()
        lightNode.light!.type = .omni
        lightNode.position = SCNVector3(x: 0, y: 10, z: 10)
        scene.rootNode.addChildNode(lightNode)
        
        let ambientLightNode = SCNNode()
        ambientLightNode.light = SCNLight()
        ambientLightNode.light!.type = .ambient
        ambientLightNode.light!.color = NSColor.darkGray
        scene.rootNode.addChildNode(ambientLightNode)
        
        let cylinderNode01 = SCNNode()
        cylinderNode01.geometry = SCNCylinder(radius: 2, height: 10)
        cylinderNode01.position = SCNVector3(0, 0, 0)
        cylinderNode01.geometry?.materials.first?.diffuse.contents = NSImage(named: NSImage.Name("checker01.png"))
        scene.rootNode.addChildNode(cylinderNode01)
        
        let cylinderNode02 = SCNNode()
        cylinderNode02.geometry = SCNCylinder(radius: 2, height: 10)
        cylinderNode02.position = SCNVector3(5, 0, 5)
        cylinderNode02.geometry?.materials.first?.diffuse.contents = NSImage(named: NSImage.Name("checker02.jpg"))
        scene.rootNode.addChildNode(cylinderNode02)
        
        let cylinderNode03 = SCNNode()
        cylinderNode03.geometry = SCNCylinder(radius: 2, height: 10)
        cylinderNode03.position = SCNVector3(10, 0, 10)
        cylinderNode03.geometry?.materials.first?.diffuse.contents = NSImage(named: NSImage.Name("checker01.png"))
        scene.rootNode.addChildNode(cylinderNode03)
        
        let cylinderNode04 = SCNNode()
        cylinderNode04.geometry = SCNCylinder(radius: 2, height: 10)
        cylinderNode04.position = SCNVector3(-5, 0, -5)
        cylinderNode04.geometry?.materials.first?.diffuse.contents = NSImage(named: NSImage.Name("checker02.jpg"))
        scene.rootNode.addChildNode(cylinderNode04)
        
        let cylinderNode05 = SCNNode()
        cylinderNode05.geometry = SCNCylinder(radius: 2, height: 10)
        cylinderNode05.position = SCNVector3(-10, 0, -10)
        cylinderNode05.geometry?.materials.first?.diffuse.contents = NSImage(named: NSImage.Name("checker01.png"))
        scene.rootNode.addChildNode(cylinderNode05)
       
        let scnView = self.view as! SCNView
        scnView.scene = scene
        scnView.allowsCameraControl = true
        scnView.backgroundColor = NSColor.black
    }
}