图形学-几何-阴影原理
这是游戏“古墓丽影”中人物的阴影,给人一种人物跟地面接触的真实感。
所有着色点的直线光、漫反射和环境光的光栅化计算都是不考虑遮挡的局部关系,而如果要考虑遮挡,从投影的角度计算出阴影,光栅化将非常复杂。
因此我们另辟蹊径,从另一个角度来看待阴影,即:
阴影就是摄像机能看到,但光线看不到的区域。
就是说,我们在光源的位置再放一台摄像机,看向场景,这是角度一;从真正的摄像机看向场景,是角度二。
角度一和角度二做一个对比,角度一“看不到”而角度二“看得到”的区域(像素),即认为是阴影。
如何做对比呢?
如图所示,从光源的角度看向物体,我们可以得到一张“深度贴图”,记录每个物体的深度值,这张深度图叫做Shading Mapping
然后我们再从真正摄像机的角度看向物体,得到的着色点和光源的距离,反对应到Shading Mapping上记录的深度。
如果深度不一致则认为被阻挡了,即这个地方(像素)会产生阴影。
如图,绿色部分光源和着色点距离=Shading Map上的深度;非绿色部分不等于,可以认为被阻挡了。白色区域即被阻挡又在地面上,则认为是阴影。
基于Shading Map,计算出来着色点要么阻挡要么非阻挡,所有得到的阴影具有两个特征,即:
1.一片阴影看起来都是一样的,没有渐变;
2.边缘很明显。
我们管这种阴影叫做硬阴影。
左图为塞尔达荒野之息,人物的阴影为硬阴影;有图为马里奥,人物的阴影为软阴影。
我们回看这张绿图,为什么被看到的部分仍然会有一些脏脏的黑色?是因为基于Shading Map的硬阴影计算存在几个“硬伤”:
硬伤一.走样问题:
1 基于光栅化,如果Shading Map的精度不够,一个像素表示多个逻辑点,这些到光源的位置实际上会有微小差异,但在Shading Map中却是同样的深度值;
2 浮点数的对比是很困难的。
这就造成了,有些点明明没有被阻挡,却计算出被阻挡了;有些被阻挡了,却计算出没被阻挡。
例如一个点到光源的真实距离是2.0,真实深度也是2.0,按理说是没有被阻挡的。但是由于Shading Map精度不够,这个点所在的像素深度是1.9,小于距离,则被认为值阻挡;即使精度够,两个都是2.0,但在一些CPU上深度的2.0当成了1.99999,又小于距离了。
硬伤二.Shading Map只能做硬阴影。
如果想做软阴影,先理解一下软阴影的原理。
上面的是硬阴影,下面的是软阴影。
以日全食为例,太阳是个大光源,月亮是个小阻挡,光线照到地球上,有一小部分完全被月亮阻挡了,看不到任何光线,这块区域称为本影Umbra;有一块比较大的区域,能看到部分的阳光,这块区域称为半影Penumbra。
软阴影我们即认为是半影。