ARKit从入门到精通(6)--光照估计

以下内容由公众号:AIRX社区(国内领先的AI、AR、VR技术学习与交流平台) 整理

光照估计是AR很重要的一个功能,它能让3D虚拟物体在现实环境更具有真实感,ARKit对光照估计有着很好的支持,本部分的教程我们通过几个小案例来了解ARKit的Light特性。

实现流程:

1.在检测到的水平面上放置一个球体节点。

2.添加光照亮球体

3.测试光的强度和温度特性

4.更新和实现ui

5.最后,在SceneKit的场景渲染方法中实现光照估计。

在开始之前先下载基础工程(https://pan.baidu.com/s/1JnBBYytgCtoMj8y9jS8fPw  密码:rj8w),我们在此基础上进行开发(一些UI控件已经准备好)。

Step 1:创建球体

首先打开下载好的项目并运行,效果如下图:

ARKit从入门到精通(6)--光照估计_第1张图片

ARKit从入门到精通(6)--光照估计_第2张图片

在Xcode中打开ViewController.swift文件。在ViewController类中添加以下方法:


func getSphereNode(withPosition position: SCNVector3) -> SCNNode {
    let sphere = SCNSphere(radius: 0.1)
    
    let sphereNode = SCNNode(geometry: sphere)
    sphereNode.position = position
    sphereNode.position.y += Float(sphere.radius) + 1
    
    return sphereNode
}

getSphereNode(withPosition:)方法主要执行以下操作:

1.接受一个位置参数。

2.创建一个半径为0.1 的球体。

3.球体的位置坐标y值为球体的半径。

4.返回球 node。

简而言之,该方法创建一个球体,并将其置于检测到的水平面之上。

Step 2:添加光源

接下来,添加一个光源(即SCNLight)来照亮场景。在ViewController类中创建以下方法:


func getLightNode() -> SCNNode {
    let light = SCNLight()
    light.type = .omni
    light.intensity = 0
    light.temperature = 0
    
    let lightNode = SCNNode()
    lightNode.light = light
    lightNode.position = SCNVector3(0,1,0)
    
    return lightNode
}

首先,创建一个SceneKit light对象(即SCNLight),其类型设置为omni。omni(泛光灯类型)从一个点向四面八方照亮一个场景。还有其他类型的光,包括directional(定向光)、spot和ambient(环境光)。

接下来,将light对象的强度和温度属性值设置为零。

将light节点对象的y位置设置为其父节点上方1米的位置。

在ViewController类中添加另一个方法:

func addLightNodeTo(_ node: SCNNode) {
    let lightNode = getLightNode()
    node.addChildNode(lightNode)
    lightNodes.append(lightNode)
}

在renderer(_:didAdd:for:)方法中添加以下内容:


let sphereNode = getSphereNode(withPosition: planeAnchorCenter)
addLightNodeTo(sphereNode)
node.addChildNode(sphereNode)
detectedHorizontalPlane = true

Step 3:测试Light的一些属性

ambientIntensitySliderValueDidChange(_:) 方法:

@IBAction func ambientIntensitySliderValueDidChange(_ sender: UISlider) {
    DispatchQueue.main.async {
        let ambientIntensity = sender.value
        self.ambientIntensityLabel.text = "Ambient Intensity: \(ambientIntensity)"
        
        guard !self.lightEstimationSwitch.isOn else { return }
        for lightNode in self.lightNodes {
            guard let light = lightNode.light else { continue }
            light.intensity = CGFloat(ambientIntensity)
        }
    }
}

上面的代码运行在主线程上,并将light节点的light intensity属性值设置为slider的sender值。同样,更新ambientColorTemperatureSliderValueDidChange(_:)方法:


@IBAction func ambientColorTemperatureSliderValueDidChange(_ sender: UISlider) {
    DispatchQueue.main.async {
        let ambientColorTemperature = self.ambientColorTemperatureSlider.value
        self.ambientColorTemperatureLabel.text = "Ambient Color Temperature: \(ambientColorTemperature)"
        
        guard !self.lightEstimationSwitch.isOn else { return }
        for lightNode in self.lightNodes {
            guard let light = lightNode.light else { continue }
            light.temperature = CGFloat(ambientColorTemperature)
        }
    }
}

通过slider控件的值来动态设置Light的temperature属性。测试效果如下:

更新detectedHorizontalPlane属性的didSet方法来动态显示slider控件:

var detectedHorizontalPlane = false {
    didSet {
        DispatchQueue.main.async {
            self.mainStackView.isHidden = !self.detectedHorizontalPlane
            self.instructionLabel.isHidden = self.detectedHorizontalPlane
            self.lightEstimationStackView.isHidden = !self.detectedHorizontalPlane
        }
    }
}

在lightEstimationSwitchValueDidChange(_:)方法中添加以下内容:

ambientIntensitySliderValueDidChange(ambientIntensitySlider)
ambientColorTemperatureSliderValueDidChange(ambientColorTemperatureSlider)

Step 4:实现光估计

剩下的是光估计的实现。对于为什么要光估计?正如在本教程一开始提到的,光估计更进一步增强了3D物体与AR现实世界的融合。例如,如果将房间的灯光调暗,你肯定希望将灯光条件反射到虚拟对象上,使其更真实。所以在ViewController类中添加以下方法:

func updateLightNodesLightEstimation() {
    DispatchQueue.main.async {
        guard self.lightEstimationSwitch.isOn,
            let lightEstimate = self.sceneView.session.currentFrame?.lightEstimate
            else { return }
        
        let ambientIntensity = lightEstimate.ambientIntensity
        let ambientColorTemperature = lightEstimate.ambientColorTemperature
        
        for lightNode in self.lightNodes {
            guard let light = lightNode.light else { continue }
            light.intensity = ambientIntensity
            light.temperature = ambientColorTemperature
        }
    }
}

接下来,在renderer(_:updateAtTime:)方法中调用以下方法:

updateLightNodesLightEstimation()

接下来测试完整项目,效果如下图:

ARKit从入门到精通(6)--光照估计_第3张图片

你还可以通过开/关你的灯来尝试光的估计。参考效果如下图:

ARKit从入门到精通(6)--光照估计_第4张图片

 

完整项目链接:

https://github.com/appcoda/ARKitLightEstimationDemo

参考资料:

https://www.appcoda.com/arkit-light-estimation/

关于更多机器学习、人工智能、增强现实资源和技术干货,可以关注公众号:AIRX社区,共同学习,一起进步!

 

你可能感兴趣的:(AIRX)