地图建筑群的光影效果原理和应用实践
- 2021 年 2 月 2 日
- AI
背景
高德开放平台在2020年初推出了AMap JSAPI 2.0版本,现在版本已经稳定下来。在JSAPI 2.0版本中我们采用了新的渲染管线,在每个渲染流程中都针对性的进行了性能优化。
因此,各方面相较于上一个稳定版本都有了很大的提升。为了还原更加真实的世界,我们希望地图中的建筑元素拥有更多的光影效果,来模拟真实世界中无处不在的光照。并且,真实世界的楼体建筑也应该拥有不同的材质,对光源有不同的响应。
今天我们就来聊一下地图上立体建筑元素的光照效果如何渲染。
现状
目前主流地图服务商的地图渲染效果都有各自的侧重点,主要的方案有以下几种:
方案一:楼体没有高度信息,只有贴地的多边形色块代表。
方案一效果图
方案二:拥有盒子形状楼体渲染,支持太阳光模拟光照的简单立体效果。在某些角度下会出立面无法区分的情况。
方案二效果图
方案三:猜测利用倾斜摄影资源,类似3DTile的加载方式,实现了接近真实世界的渲染效果,而且性能优异。
方案三效果图
当时,高德使用的也是类似方案二中的简单光照盒子效果的立体建筑,我们希望在新的数据资源下能够渲染出更加真实的效果。具体希望达到以下效果:
-
实现更加柔和立体的光照效果,解决立面在某些角度下会由于光照强度和角度一致导致糊成一片,丧失立体效果。
-
实现照亮指定的区域,模拟城市的夜晚效果。
-
满足某些特殊场景下立体物体的金属光泽特效。
方案调研
Blinn-Phong光照模型
Blinn-Phong光照模型中规定了一个片元的颜色是有三个不同的光反射量组成:
-
环境光
环境光是模拟现实世界中各种光源在不同的物体表面无休止的反射而最终生成的光,因为现实世界光的反射太过于复杂,在冯氏光照中我们直接定义一个光源,无差别的反射在每个物体的表面来模拟环境光。
<环境光> = 环境光强度 x 环境光颜色。 -
漫射光
漫射光是模拟物体对一个光源的反射强度。从下面的图中我们能看到,漫射光的反射强度取决于物体表面的法向量和入射光的夹角,夹角越大物体反射越弱,反之,越强。
<漫射光> = 光强度 x 光颜色 x cos(光和平面法向量的夹角)。
-
镜面反射光
镜面反射主要针对表面拥有粗糙度的物体,当物体表面比较光滑的时候–比如一个由抛光金属制成的物体,那么光照射到物体表面会形成光点或者光斑。
<镜面反射光> = 光强度 x 光颜色 x cos(光在平面上的反射夹角)^平面光泽度。
一个片段颜色就是三个反射的和:总反射 = 环境反射 + 漫反射 + 镜面反射。
光源和材质
灯光按照不同的类型大致分为四类:
-
环境光
上面冯氏光照中已经介绍。 -
平行光
是一种理想型光源,主要模拟真实世界中的太阳光,因为太阳距离地球很远,射向地球的光可以近似的看做平行光。 -
点光
点光源主要模拟的是现实世界中的灯泡光。也可以理解为太阳是整个太阳系中的一个巨大点光源。 -
聚光灯
聚光灯光源也可以认为是锥形光源,一般使用在一些特殊场景中。
(图片来源于网络)
三点布光法
为了解决单光源导致某些角度下的光线死角问题,我们发现了一种经典和常用的打光方式:三点布光法。它侧重指灯位在不同的三个点上。用三个不同强度和方向的光分布在一个场景中不同的位置将整个场景照的层次分明。
(图片来源于网络)
主要分为:
主光:它规定了方向、角度、与范围,规定了照明光轴与照射角。起着主要造型和确定光影格调的作用,确定了整个环境的主体明暗基调。
辅助光:它起着辅助主光未照眀的区域并通过副光来调整光比,柔化主光形成的阴影。避免光的背面一片漆黑而失去立体感。
轮廓光:前两度光完成后,需要把物体与环境隔开,产生一种深度与层次。增强整个环境的柔和度和层次感。
对比和实施
为了得到比较好的物体光照效果和场景渲染,我们最终决定对上面的三种技术方案都进行实现。
使用Blinn-Phong光照模型模拟物体反射,使用环境光、平行光、点光进行光照模拟,最后使用三点布光法进行光源分布。这样在场景中能保证最好光照效果。
高德JSAPI 2.0版本中,我们绘制了简单的立体楼块。下面我们开始使用新的光照方案。
Blinn-Phong光照模型是基于每个面的法线和光照的方向两个向量,对这两个向量进行各种运算来模拟真实世界中的光照对物体的影响。
我们先着手准备每个平面的法向量。每一个平面其实都有两个法向量,这两个法向量代表平面的“正面”和“反面”。平面中计算法向量的公式就是平面上两个任意向量的叉乘。
<平面法向量> = cross(平面向量A,平面向量 B)。
根据平面自身的缠绕方向,我们需要计算出楼块面朝外的法向量。
(图片来源于网络)
对于环境光和平行光来说是比较简单的,只需要光照强度、光的颜色、光的方向(平行光)。但是对于点光源来说稍微复杂一点,还需要有光的衰减。通常来说一个点光源对不同距离远的物体的光照强度是不一样的,因此需要对物体上的每一个片元都进行衰减计算。
加上平行光和环境光之后我们有了这样一个楼体效果:
为了能聚焦到主要物体上面,应该使用点光源将需要聚焦的范围点亮,让整个场景更加有层次感。
点光源的位置就设置在东方明珠上方1000米处的空中,设置光的衰减距离为一万米。这样他就会照亮整个一万米范围的城市建筑。从下图中我们就可以看出点光源照亮了整个东方明珠的区域。
至此,地图楼体建筑的光照效果已经基本完成。
小结
我们首先使用平行光从正南方向照射进场景中,来模拟太阳的正点照射。但是仅仅有这一个光源会导致上面提到的在某些角度下楼体的立面还是会出现整片的暗色。因此,我们需要在地图的北方增加一个弱化的背面平行光,用来点亮楼体背面。最后,为了突出东方明珠这块区域,又增加了一个半径为十公里的点光源,这样整个区域的光照就能很好的突出层次感。
在地图渲染这个方向上,有很多基础理论可以借鉴其他领域中已经很成熟的理论和最佳实践,来帮助我们渲染出更加接近真实世界的地图。
参考文献
[1] Andreas Anyuru [美] 著,吴文国译《WebGl 高级编程–开发 Web 3D 图形》. 北京:清华大学出版社,2013.06. 第一版
[2] Kouichi Matsuda [美],Rodger Lea [美] 著, 谢光磊译 《WebGL 编程指南》. 北京:电子工业出版社,2014.6