【iOS ARKit】光照估计

光照估计

        AR与VR 在光照上最大的不同在于VR 世界是纯数字世界,有一套完整的数学模型,而AR则是将计算机生成的虚拟物体或关于真实物体的非几何信息叠加到真实世界的场景之上实现对真实世界的增强,融合了真实世界与数字世界。就光照而言,VR中的光照完全由开发人员决定,光照效果是一致的,即不会受到运行时其他因素的影响,而AR 中则不得不考虑真实世界的光照与虚拟的3D光照信息的一致性,举个例子,假如在AR 3D应用中设置了一个模拟太阳的高亮度方向光,而用户是在晚上使用这个 AR应用,如果不考虑光照一致性,那么渲染出来的虚拟物体的光照与真实世界其他物体的光照反差将会非常明显,由于人眼对光照信息的高度敏感性,这种渲染可以说是完全失败的,完全没有沉浸感。在AR 中,由于用户与真实世界的联系并未被切断,光照的交互方式也要求更自然,如果真实世界的阴影向左而渲染出来的虚拟物体图影向右,这也是让人难以接受的,所以在 AR 中,必须要能达到虛拟光照与真实光照的一致,虚拟物体渲染出来的阴影应与真实环境中的阴影基本保持一致,这样才能提商虛拟物体的可信度和真实感。

ARKit 中的光照估汁

     ARKit 支持对用户所处环境光照信息的估计,在 ARConfiguration 类中定义了 isLightEstimationEnabled 布尔属性用于开启和关闭光照估计,该功能默认为启用状态。由于 ARConfiguration 是所有其他配置类的父类,因此 ARKit所有的配置类都支持光照估计功能。

     当设置 isLightEstimationEnabled 值为true 时,ARKit 每帧都会对从设备摄像头中采集的图像进行光照估计计算,并且将估计值保存在 frame. lightEstimate 属性中,frame. lightEstimate 是 ARLightEstimate类的实例,ARLightEstimate类只包含两个属性,

  1. 环境光强度值 (ambientIntensity) 取值范围[0,2000],在光照条件良好的环境中,该值约为1000,0表示环境非常黑暗,2000表示环境非常明亮
  2. 环境光温度值(ambientColorTemperature) 单位开尔文(K),纯白光次6500,低于该值表示环境更温暖,更偏向于黄光或者橘黄光,而高于该值表示环境更冷,更偏向于蓝光

     在 RealityKit 中,一般情况下开发人员无须关注 frame. lightEstimate 中的值,当设置 isLightEstimationEnabled值为 true 时,RealityKit 会自动使用环境光照估计值渲染虚拟元素的光照。但在使用自定义渲染时,开发人员必须自行处理光照估计。

    但在一些情况下,我们也可能需要实时获取当前环境光照估计值,如根据环境光照动态调整特效类型,下面演示如何启用光照估计并获取实时的光照估计值,如代码所示。

//
//  LightEstimate.swift
//  ARKitDeamo
//
//  Created by zhaoquan du on 2024/1/29.
//import SwiftUI
import ARKit
import RealityKit
import Combinestruct LightEstimate: View {@State var isFaceTracking = falsevar body: some View {LightEstimateContainer(isFaceTracking: isFaceTracking).overlay(content: {VStack{Spacer()Button {isFaceTracking.toggle()} label: {Text( !isFaceTracking ? "人脸追踪光照": "普通光照估计").frame(width:150,height:50).font(.system(size: 17)).foregroundColor(.black).background(Color.white).opacity(0.6)}.cornerRadius(10)Spacer().frame(height: 40)}}).edgesIgnoringSafeArea(.all).navigationTitle("光照估计")}
}struct LightEstimateContainer: UIViewRepresentable {var isFaceTracking: Bool = falseinit(isFaceTracking: Bool = false) {self.isFaceTracking = isFaceTracking}func makeUIView(context: Context) -> ARView {let arView = ARView(frame: .zero)return arView}func updateUIView(_ uiView: ARView, context: Context) {if isFaceTracking {let config = ARFaceTrackingConfiguration()config.isLightEstimationEnabled = trueuiView.session.delegate = context.coordinatorcontext.coordinator.times = 0uiView.session.run(config, options: [.resetTracking,.removeExistingAnchors])return}let config = ARWorldTrackingConfiguration()config.planeDetection = .horizontalconfig.isLightEstimationEnabled = truecontext.coordinator.arView = uiViewuiView.session.delegate = context.coordinatoruiView.session.run(config)}func makeCoordinator() -> Coordinator {Coordinator(parent: self)}class  Coordinator: NSObject,ARSessionDelegate {var arView:ARView? = nilvar isPlaced = falsevar times = 0var parent: LightEstimateContainerinit(parent: LightEstimateContainer) {self.parent = parent}func session(_ session: ARSession, didAdd anchors: [ARAnchor]) {guard let anchor = anchors.first as? ARPlaneAnchor,!isPlaced else {return}do {let planEntity = AnchorEntity(anchor: anchor)let mesh = MeshResource.generateBox(size: 0.1, cornerRadius: 0.003)let texture = MaterialParameters.Texture.init(try TextureResource.load(named: "Box_Texture.jpg"))var meterial = SimpleMaterial(color: .blue,roughness: 0.8 ,isMetallic: false)meterial.color = .init(tint:.blue,texture:texture)let modelEntity = ModelEntity(mesh: mesh, materials: [meterial])planEntity.addChild(modelEntity)arView?.installGestures(for:modelEntity)arView?.scene.addAnchor(planEntity)}catch{print("无法加载纹理")}}func session(_ session: ARSession, didUpdate frame: ARFrame) {guard let estimatLight = frame.lightEstimate , times < 10 else {return }print("light intensity: \(estimatLight.ambientIntensity),light temperature: \(estimatLight.ambientColorTemperature)")if let estimatLight = frame.lightEstimate as? ARDirectionalLightEstimate {print("primary light direction: \(estimatLight.primaryLightDirection), primary light intensity: \(estimatLight.primaryLightIntensity)")}times += 1}}
}

        代码中代码逻辑非常清晰,我们使用 session(:didUpdate frame:)代理方法实时地获取每一帧的光照估计值,并打印了光照估计值强度及色温信息。运行代码,在检测到的水平平面上加载木箱物体后,改变真实环境中的光照,可以看到虚拟的木箱光照信息也发生了明显的变化。

  • 经过测试,发现在使用 RealityKit 渲染时,即使设置 isLightEstimation Enabled 为 false 也会在渲染虛拟元素时考虑光照估计,但此时无法从 frame. lightEstimate 中获取光照估计值。

      除了通用的光照估计,在使用 ARFaceTrackingConfiguration 配置运行 ARSession 时,ARKit 会提供更多关于环境光照的估计信息。在使用 ARFace TrackingConfiguration 配置运行 ARSession,当设置 isLightEstimationEnabled 值为 true 时,ARKit 每帧都会对从设备摄像头中采集的图像进行光照估计计算,并且将估计值保存在 frame. lightEstimate 属性中,但此时 frame. lightEstimate 为 ARDirectionalLightEstimate 类的实例,ARDirectionalLightEstimate类为 ARLightEstimate 的子类,不仅包括 ARLightEstimate 中的属性,还包含另外3个光照估计值属性。

  • primary LightDirectio 场景中最强光线的方向向量,这是一个在世界空间中归一化的向量
  • primary LightIntensit  场景中最强光线的光照强度,单位为流明,取值范围[0,2000],在光照条件良好的环境中,该值约在1000,0表示环境非常黑暗,2000表示环境非常明亮
  • spherical HarmonicsCoefficients  对环境中多个光源方向与强度的综合表达。球谐因子提供了一种在某点反映全局环境光照信息的简洁紧凑模型,描述了在该点的多个光源光照分布与颜色值。在IML. 渲染中,球谐因子非常高效。ARKit 光照估计提供二级(Second level)红、绿、蓝分离的3通道球谐因子,总数据包括3级9个因子,总计27个32位的浮点值。

      在Reality Kit 中,开发人员亦无须关注这些光照估计值,当设置 isLightEstimationEnabled 值为 true5,Reality Kit就会自动使用环境光照估计值渲染虚拟元素。但在使用自定义谊染时,开发人员必须自己处理光照估计。下面代码是演示在使用 ARFaceTrackingConfiguration 配置时,启用光照估计并获取实时的光照估计值。

func updateUIView(_ uiView: ARView, context: Context) {let config = ARFaceTrackingConfiguration()config.isLightEstimationEnabled = trueuiView.session.delegate = context.coordinatorcontext.coordinator.times = 0uiView.session.run(config, options: [.resetTracking,.removeExistingAnchors])return}func session(_ session: ARSession, didUpdate frame: ARFrame) {guard let estimatLight = frame.lightEstimate , times < 10 else {return }print("light intensity: \(estimatLight.ambientIntensity),light temperature: \(estimatLight.ambientColorTemperature)")if let estimatLight = frame.lightEstimate as? ARDirectionalLightEstimate {print("primary light direction: \(estimatLight.primaryLightDirection), primary light intensity: \(estimatLight.primaryLightIntensity)")}times += 1}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/654740.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

uniapp - editor 富文本的使用

目录 editor 组件 属性说明 editorContext uni.createSelectorQuery() SelectorQuery selectorQuery.in(component) selectorQuery.select(selector) selectorQuery.selectAll(selector) selectorQuery.selectViewport() selectorQuery.exec(callback) NodesRef nod…

STM32 有源蜂鸣器

模块介绍: 结构&#xff1a;有源蜂鸣器通常由一个振膜和一个驱动电路组成。振膜是负责产生声音的部分&#xff0c;而驱动电路则负责控制振荡频率和幅度。 工作原理&#xff1a;有源蜂鸣器的驱动电路会向振膜施加电压&#xff0c;使其振动产生声音。驱动电路可以根据输入信号的…

ChatGPT升级,价格降低,不再懒惰!

OpenAI 1月26号宣布推出5种新模型&#xff0c;包括两款新的嵌入式模型、更新后的 GPT-4 Turbo 预览模型、GPT-3.5 Turbo 模型以及文本审核模型。 此外&#xff0c;chatgpt的价格也有低至50%的下降。新模型的输入价格下降 50% 至 $0.0005 /1K tokens&#xff0c;输出价格下降 2…

借助gpt生成ppt:文心一言(chatgpt)、chatppt

提供一种简单的基于gpt快速生成ppt的方式。前置条件&#xff1a; 文心一言chatpptwps/office ppt Step1: 下载chatppt插件 https://chat-ppt.com/invitelinke?share_code47949695&channelchat-ppt.com 注册地址 下载完成后&#xff0c;安装即可&#xff0c;安装完成后…

MyBatis框架-XML映射器

文章目录 XML映射器CRUD操作select根据id查询用户根据名字和密码查询方法一&#xff1a;使用对象UserMapper.javaUserMapper.xml测试用例方法二&#xff1a;使用MapUserMapper.javaUserMapper.xml测试用例方法三&#xff1a;方法种传递参数UserMapper.javaUserMapper.xml测试用…

如何看待开发者是否需要入坑鸿蒙?

前言 自打华为2019年发布鸿蒙操作系统以来&#xff0c;网上各种声音百家争鸣。尤其是2023年发布会公布的鸿蒙4.0宣称不再支持Android&#xff0c;更激烈的讨论随之而来。 通过本文&#xff0c;我将给大家介绍以下几点&#xff0c;让大家清楚的了解到鸿蒙开发的趋势&#xff1…

win11设置mysql开机自启

目录 命令式 1、打开命令提示符或 PowerShell&#xff1a; 2、使用管理员权限运行命令行工具&#xff1a; 3、设置 MySQL 服务为开机自启动&#xff1a; 4、启动 MySQL 服务&#xff1a; 5、 验证设置是否生效&#xff1a; 操作视图式 1、右击任务栏 ---> 选择任务管…

深入了解DRAM和SDRAM:内存带宽的计算与封装形式的奥秘

SSD SDRAM DDR SDRAM简介 动态随机存取存储器DRAM&#xff08;Dynamic Random Access Memory&#xff0c;DRAM&#xff09;是一种半导体存储器。 其主要的作用原理是利用电荷内存储电荷的数量来代表一个二进制比特&#xff08;bit&#xff09;是1还是0。 由于在现实中品体管…

【物联网之·协议·ZigBee】

系列文章目录 文章目录 前言一、ZigBee技术概述1.1 ZigBee的起源和发展历程1.2 ZigBee的工作原理和网络拓扑结构1.3 ZigBee的应用领域和主要优势 二、ZigBee协议栈2.1 Zigbee的协议栈结构和各层功能2.2 Zigbee协议栈的协议消息和数据格式 三、ZigBee网络配置3.1 Zigbee网络的组…

嵌⼊式⾯试宝典

编程功底问题 1. 简单描述下C语⾔中⼤⼩端的概念 ⼤⼩端是⼀种计算机存储数据的⽅式,它决定了在内存中如何排列多字节数据的字节顺序。 ⼤端:多字节数据的⾼位字节存储在内存的低地址处。 ⼩端:多字节数据的低位字节存储在内存的低地址处。 8051 stc单⽚机是⼩端模式 …

进京证12次不够用怎么办?(北京进京证探头分布,进京证365,进京365)外地车在京如何行驶——躲猫猫外地车在京地图导航

其实想要在北京驾驶外地牌照的车辆主要有两种方式&#xff0c;一种是办理进京证(六环内进京证一年只能办12次&#xff0c;一次有效期7天&#xff0c;所以大多数人是不够用的);另一种就是在非监控区域行驶&#xff0c;可以借助于一些摄像头定位工具&#xff0c;有效躲避摄像头&a…

洗地机哪个牌子好?2024洗地机推荐

洗地机作为一种几乎替代了传统无线吸尘器的清洁工具&#xff0c;近年来在市场上迅速崛起。其优越的清洁效果和智能化设计使其成为许多家庭不可或缺的家电之一。在短短的几年时间里&#xff0c;市场上涌现出了各种各样的品牌和型号&#xff0c;价格也从几百元到数千元不等&#…

LVGL部件

一.标签部件 1.如何创建标签部件以及设置文本 ![2024-01-28T09:54:08.png][3] void my_lvgl(void) {lv_obj_t *lablelv_label_create(lv_scr_act()); //创建一个标签lv_label_set_text(lable,"hello"); //普通更改文字lv_label_set_text_fmt(lab…

【C语言】(9)分支结构

一.if-else 语句 if-else 适用于简单和复杂的条件判断。 a. 基本 if 语句 用途&#xff1a;基本的条件测试。语法&#xff1a;if (condition) {// 代码块 }示例&#xff1a;if (score > 60) {printf("及格\n"); }b. if-else 语句 用途&#xff1a;二选一的条件…

基础小白快速学习c语言 ---c语言的简单介绍

c语言是由一个或者多个函数组成的&#xff0c;函数是由语句组成的&#xff0c;语句要用&#xff1b;结束 c语言开发过程&#xff1a; 1 创建一个源程序 2 预处理并且编程 c语言中的标准输入和标准输出 标准输出&#xff1a;printf printf是c语言标准库中提供的一个函数&…

有哪些原型图设计工具是你应该熟悉的?

今天我们将介绍 5 优秀的原型设计工具及其功能。每个软件都有不同的平台和价格范围。相信你能找到最适合你的原型工具&#xff01; 1、Sketch 以友好的用户而闻名 Sketch&#xff0c;对于设计师来说&#xff0c;有很多实用的功能。这个软件在图形编辑方面很受欢迎&#xff0c;…

【Django开发】前后端分离美多商城项目:项目准备和搭建(附代码,文档)

本系列文章md笔记&#xff08;已分享&#xff09;主要讨论django商城项目开发相关知识。本项目利用Django框架开发一套前后端不分离的商城项目&#xff08;4.0版本&#xff09;含代码和文档。功能包括前后端不分离&#xff0c;方便SEO。采用Django Jinja2模板引擎 Vue.js实现…

【webrtc】m98 : vs2019 直接构建webrtc及moduletest工程 2

字数有限制,我们继续 【webrtc】m98 : vs2019 直接构建webrtc及unitest工程 1modules_unittests 构建 Build started... 1>------ Build started: Project: modules_unittests, Configuration: GN Win32 ------ 1>ninja: Entering directory `G:\CDN\rtcCli\m98\src\o…

linux centos 查看端口是否打开与打开端口

查看端口是否打开 talnet talnet ip 端口linux查看防火墙开放情况 firewall-cmd --list-all打开端口 其中permanent表示永久生效&#xff0c;public表示作用域&#xff0c;443/tcp表示端口和类型&#xff0c;执行规则的重载 firewall-cmd --zonepublic --add-port443/tcp …

VitePress-04-文档中的表情符号的使用

说明 vitepress 的文档中是支持使用表情符号的&#xff0c;像 &#x1f602; 等常用的表情都是支持的。 本文就来介绍它的使用方式。 使用语法 语法 &#xff1a; :表情名称: 例如 &#xff1a; :joy: &#x1f602; 使用案例代码 # 体会【表情】的基本使用 > hello world …