完整代码已上传:https://github.com/kaiwu119/BallFreeFallAnimation
阴影是光线被物体遮挡而产生的,当光线照射不到物体表面时,这个物体就处于阴影中了, 阴影的存在可以让场景更加真实,而且更容易分辨出物体的相对位置。现在有很多阴影的实现方法,但是都不是那么容易实现的,而阴影映射是比较容易实现的,这次主要介绍阴影映射实现实时阴影,下面先看效果图:
还是比较懒,素材选用了之前的自由落体小程序,但是对之前的效果进行了修改,可以很明显的看出现在渲染出的效果更好。
我们从上面的图看出小球的影子是实时跟着小球移动的,附加了阴影之后这个小球是不是更具有真实感了呢。
阴影映射
先说一下阴影贴图的好处:不需要了解场景中的物体,对于每个灯光而言,只需要一张纹理来保存阴影信息。
缺点是 易走样。后面会讲到。
阴影映射是实现阴影的一种方法,这种方法思路非常简单,简单来说:光源发出的一条射线中与光线触碰到的第一个物体,那么这个就是光亮点,也是在这个射线中距离光源的最近点,然后我们把这个最近点和射线上的其余点进行比较,只要比最近点远那就是处于阴影中。但是我们遍历所有的射线显然效率是很低的,于是我们引入了一种类似的举措,但是效率上更可观——深度缓冲。在深度缓冲中,里面的一个值对应于在摄像机的视角下的一个片元的深度值(取值为0~1),那么我们就可以简单的获取这些最近点的深度值了,我们只需要把摄像机架在光源的位置对屏幕进行渲染,然后把获取到的深度值保存到一张纹理中,这个纹理就叫做深度贴图,或是阴影贴图。之后我们正常渲染的时候,我们就可以让每一个片元的深度值和阴影贴图相对应的深度值比较,我们就能知道这个片元是否处于阴影之中。
那么如何比较呢?因为我们的阴影贴图是在光源的位置上获取的,那么我们同样也要将所有的片元转换到光源空间中,然后再进行比较。
技术路线是:
- 创建阴影贴图
- 渲染场景到阴影贴图
- 正常渲染场景(使用阴影贴图)
下面我们分别具体阐述方法和代码:
1. 创建阴影贴图
glGenFramebuffers(1, depthMapFBO); //生成一个帧缓冲对象
glGenTextures(1, depthMap);
glBindTexture(GL_TEXTURE_2D, *depthMap);//绑定深度图
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT