【问题标题】:SceneKit – Change object's opacity depending on how close it is to the cameraSceneKit – 根据物体与相机的距离来改变物体的不透明度
【发布时间】:2020-10-20 22:13:14
【问题描述】:

我目前有 6 个球体,分别代表 x、-x、y、-y、z、-z 的方向,我想将每个 SCNSphere 的不透明度更改为 0,当它靠近我的相机并且满时远处时透明。

struct SceneKitView: UIViewRepresentable {
    var transparency: CGFloat = 0.5
    let sceneView = SCNView()
    
    func makeUIView(context: UIViewRepresentableContext<SceneKitView>) -> SCNView {
        
        sceneView.scene = SCNScene()
        sceneView.allowsCameraControl = true
        sceneView.autoenablesDefaultLighting = true
        sceneView.backgroundColor = UIColor.clear
        let radius: Float = 0.75
        
        createSphere(x: 0, y: radius, z: 0)
        createSphere(x: 0, y: -radius, z: 0)
        createSphere(x: radius, y: 0, z: 0)
        createSphere(x: -radius, y: 0, z: 0)
        createSphere(x: 0, y: 0, z: radius)
        createSphere(x: 0, y: 0, z: -radius)
        
        return sceneView
    }
    
    func updateUIView(_ uiView: SCNView, context: UIViewRepresentableContext<SceneKitView>) {
    }
    
    typealias UIViewType = SCNView
    
    func createSphere(x: Float, y: Float, z: Float) {
        let sphere = SCNSphere(radius: 0.1)
        sphere.firstMaterial?.diffuse.contents = UIColor.black
        sphere.firstMaterial?.transparency = transparency
        let spherenode = SCNNode(geometry: sphere)
        spherenode.position = SCNVector3(x: x, y: y, z: z)
        sceneView.scene?.rootNode.addChildNode(spherenode)
    }
}

【问题讨论】:

    标签: swift augmented-reality scenekit arkit


    【解决方案1】:

    在 SceneKit 中,要以 60 fps 的帧速率更新任何属性,您需要符合 SCNSceneRendererDelegate 协议并使用其名为 renderer(_:updateAtTime:) 的实例方法。

    这是一个代码:

    import SceneKit
    
    class GameViewController: NSViewController, SCNSceneRendererDelegate {
        
        var scnView = SCNView()
        let sphereNode = SCNNode()
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            let scene = SCNScene()
            scnView = self.view as! SCNView
            scnView.delegate = self               // SCNSceneRendererDelegate
            scnView.scene = scene
            scnView.allowsCameraControl = true
            scnView.backgroundColor = NSColor.systemIndigo
            
            sphereNode.geometry = SCNSphere(radius: 1.0)
            scene.rootNode.addChildNode(sphereNode)
        }
        
        func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {
    
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
    
                let sphereTransform = self.sphereNode.simdTransform.columns.3
                let cameraTransform = (self.scnView.pointOfView?.simdTransform.columns.3)!
            
                self.sphereNode.opacity = CGFloat((simd_distance(sphereTransform, 
                                                                 cameraTransform) / 5.0) - 0.5)
            }
        }
    }
    


    或者您可以使用guard let 语句(UIKit 示例)查看可选绑定:

    import SceneKit
    
    class ViewController: UIViewController, SCNSceneRendererDelegate {
        
        @IBOutlet var scnView: SCNView!
        let sphereNode = SCNNode()
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            let scene = SCNScene()
            scnView.delegate = self               // SCNSceneRendererDelegate
            scnView.scene = scene
            scnView.allowsCameraControl = true
            scnView.backgroundColor = UIColor.systemIndigo
            
            sphereNode.geometry = SCNSphere(radius: 1.0)
            scene.rootNode.addChildNode(sphereNode)
        }
    
        func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {
    
            let sphereTransform = self.sphereNode.simdTransform.columns.3
        
            guard let cameraTransform = self.scnView.pointOfView?.simdTransform.columns.3
            else { return }
        
            self.sphereNode.opacity = CGFloat((simd_distance(sphereTransform,
                                                             cameraTransform) / 5.0) - 0.5)
        }
    }
    

    【讨论】:

    • 为什么异步调度到主队列?这不是必需的,并且会引入延迟。
    • 嗨@mnuages,没有异步调度应用程序在打开之前崩溃并出现以下错误EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)。如果你愿意,试试吧。
    • 可能是因为强制解包可选?
    • 感谢您的帮助。在您的示例中,如何让 GameViewController 符合 NSObject?
    • 或者你可以使用这里发布的代码在iOS项目中。而不是scnView = self.view as! SCNView 使用@IBOutlet var scnView: SCNView!。而不是 NSClasses 使用 UIClasses。
    猜你喜欢
    • 2017-01-25
    • 1970-01-01
    • 2011-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-16
    • 2019-07-22
    相关资源
    最近更新 更多