为什么要使用灯光
AR就是在现实中插入新物体,一些时候,新物体看起来会不真实。如何能让物体看起来和现实的场景融为一体呢?一个很好的办法就是使用灯光。
举个例子,如果在一个全黑的房间放入一个明亮的物体,看起来的效果就特别不真实,如下图。
灯光的类别
Ambient(全景灯光): 灯光从每个方向过来,而且灯光的强度都是一致的,所以看起来没有阴影。
** directional(定向光)**:该灯光只有方向,没有光源,可以想象从无限远的地方发射出光源。
omni(泛光灯): 该灯光有方向,也有光源,灯光的强度和距离有关系,距离越近,强度越大。
spot(聚光灯):和泛光灯一样,有方向也有光源,而且是以锥形的方式到平面上,就如同现实中的聚光灯一样。
ARKit灯光估计技术
ARKit使用灯光估计技术,根据场景进行分析估算出全景灯光的强度,返回值1000代表中间值,小于这个值则变暗,大于这个值则变亮,打开灯光估计技术,只需要在场景配置里设置lightEstimationEnabled 属性即可:
configuration.lightEstimationEnabled = YES;
在ARSCNViewDelegate里,就可以使用估计出来的灯光值进行一些工作,具体怎么做,下面的章节一一解释。
- (void)renderer:(id <SCNSceneRenderer>)renderer updateAtTime:(NSTimeInterval)time {
ARLightEstimate *estimate = self.sceneView.session.currentFrame.lightEstimate;
if (!estimate) {
return;
}
// TODO: Put this on the screen
NSLog(@"light estimate: %f", estimate.ambientIntensity);
// Here you can now change the .intensity property of your lights
// so they respond to the real world environment
}
添加场景灯光
有3种设置灯光的办法:
1:autoenablesDefaultLighting会加入一个Onmi (泛光灯),该灯光的位置是摄像头的位置,方向也是摄像头的拍摄方向。不过该默认灯光有下面几个特点:
- 灯光的强度一直都是1000(中性值)。
- 该灯光的方向可以随时改变,方向都是从摄像头方向出去,就好像是你拿着火炬时的感觉。
2:automaticallyUpdatesLighting会自动基于灯光估计技术加入灯光,听起来好像很完美,不过貌似没有生效。
3:在这里我们自定义灯光,把图片里面的灯光,利用灯光估计技术提取出来.
- (void)setupLights {
// Turn off all the default lights SceneKit adds since we are handling it ourselves
self.sceneView.autoenablesDefaultLighting = NO;
self.sceneView.automaticallyUpdatesLighting = NO;
UIImage *env = [UIImage imageNamed: @"./Assets.scnassets/Environment/spherical.jpg"];
self.sceneView.scene.lightingEnvironment.contents = env;
//TODO: wantsHdr
}
图片如下:
调节灯光的强度
在代理里面,利用灯光估计技术,获得实时的灯光强度,设置入场景。
- (void)renderer:(id <SCNSceneRenderer>)renderer updateAtTime:(NSTimeInterval)time {
ARLightEstimate *estimate = self.sceneView.session.currentFrame.lightEstimate;
if (!estimate) {
return;
}
// TODO: Put this on the screen
NSLog(@"light estimate: %f", estimate.ambientIntensity);
// Here you can now change the .intensity property of your lights
// so they respond to the real world environment
//估计出来的灯光设置进去
CGFloat intensity = estimate.ambientIntensity / 1000.0;
self.sceneView.scene.lightingEnvironment.intensity = intensity;
}
光线跟踪:基于物理的渲染(PBR)
先看几张渲染图,体会一下,PBR的细节比较复杂,具体参看PBR.
当你给物体加入纹理的时候,你需要提供以下信息:
Albedo(反照率):这是模型的基本颜色。它映射到物质的漫反射部分,它是在光照或阴影信息中没有任何烘烤的物质纹理。
Roughness(粗糙度):描述材料的粗糙程度,粗糙的表面显示出暗淡的反射,平滑的材料显示明亮的镜面反射。
Metalness(金属度):相当于材料光泽的粗略方法。
比较难以理解,大家可以看看这里PBR详细介绍
利用PBR技术添加物体纹理
从http://freepbr.com/ 抓取一些纹理的图片下来,设置成纹理:
mat = [SCNMaterial new];
mat.lightingModelName = SCNLightingModelPhysicallyBased;
mat.diffuse.contents = [UIImage imageNamed:@"wood-albedo.png"];
mat.roughness.contents = [UIImage imageNamed:@"wood-roughness.png"];
mat.metalness.contents = [UIImage imageNamed:@"wood-metal.png"];
mat.normal.contents = [UIImage imageNamed:@"wood-normal.png"];
可以看到这里的灯光模式设置成了PBR.
具体可以参考demo:
demo