在特定的3D场景中,阴影效果有时还是显得十分重要的,在一般的3D引擎当中设置阴影可以直接通过对物体设置属性来实现,十分的方便,这里我们就用webgl来实现一下平面效果。
平面阴影是通过灯光将物体的阴影投射在一个平面内,但是物体之间没有阴影的叠加,也就是说A物体的阴影不会投射到B物体上,在本案例中我们主要是通过着色器来实现平面阴影的效果的,这里首先介绍一下平面阴影的计算公式:
V'=S+(V-S)(n·(A-S))/(n·(V-S))
上述公式中每一部分的含义如下。
V'代表沿光线投影到绘制阴影的平面上顶点的坐标。
S为光源的位置。
V为投影前顶点的实际位置。
n为法向量,其属于绘制阴影的平面。
A为任意一个点的坐标,其位于绘制阴影的平面上。
•代表向量的点积计算。
下面介绍阴影的顶点着色器,其主要功能是根据有阴影的物体的位置和投影摄像机矩阵,通过平面阴影计算公式来计算阴影的位置和所在的平面。下面是顶点着色器的代码:
uniform mat4 uMVPMatrix; //总变换矩阵 uniform mat4 uMMatrix; //变换矩阵 uniform mat4 uMProjCameraMatrix; //投影、摄像机组合矩阵 uniform vec3 uLightLocation; //光源位置 uniform vec3 uCamera; //摄像机位置 attribute vec3 aPosition; //顶点位置 void main(){ vec3 A=vec3(0.0,0.1,0.0); //绘制阴影平面上任意一点的坐标 vec3 n=vec3(0.0,1.0,0.0); //绘制阴影平面的法向量 vec3 S=uLightLocation; //光源位置 vec3 V=(uMMatrix*vec4(aPosition,1)).xyz; //经过平移和旋转变换后的点的坐标 vec3 VL=S+(V-S)*(dot(n,(A-S))/dot(n,(V-S)));//顶点沿光线投影到需要绘制阴影的平面上点的坐标 gl_Position = uMProjCameraMatrix*vec4(VL,1); //根据组合矩阵计算此次绘制此顶点位置 }
片元着色器主要是对阴影的颜色进行赋值,所以顶点着色器不用给片元着色器传递任何参数,只需要一行代码即可。
precision mediump float; //给出默认的浮点精度 void main(){ gl_FragColor = vec4(0.2,0.2,0.2,1.0); //片元最终颜色为阴影的颜色 }
最后放我自己踩的一个坑:当遇到如下图所示报错时一般是没有指定当前绘制使用的着色器,从而导致送入缓冲的数据不一致,最终导致错误。
最后是演示图片与github:https://github.com/StringKun/WebGL-Shadow