OpenGL(十九) 阴影 通过ShadowMap的shader实现

版权声明:本文为 松阳 (blog.csdn.net/fansongy) 原创文章,转载必须注明出处: https://blog.csdn.net/fansongy/article/details/79303712

阴影 可以使角色与地面的关系更加明确。本文主要介绍如何通过 ShadowMap 在OpenGL中实现 阴影 。

核心原理

Shadow Map的基本思想:通过LightView画一张DepthMap,然后Camera View渲场景的时候,把Pixel坐标变换到Light Space,比较Depth即可(Pixel的Depth大于Shadow Map的Depth即在阴影区)。也可以直接是ScreenSpaceDepthMapPost-processing

阴影 生成需要三个步骤:

  1. 在角色正上方照出一张深度图。
  2. 视线方向的模型绘制点,在上方摄像机视口的Z值与深度图相同位置的Z值进行比较,如果比深度图中的值小则为亮区,反之需要绘制阴影。
  3. 将颜色物体颜色与阴影绘制在一起。

实现

深度图其实就是一张灰度图片,可以简单的将摄像机放到物体正上方,绘制出常规效果之后,只提取R通道。另外通过pow可以加深depthValue。

//fs
varying vec2 V_Texcoord;
uniform sampler2D U_MainTexture;
void main()
{
    float depthValue=texture2D(U_MainTexture,V_Texcoord).r;
    gl_FragColor=vec4(vec3(pow(depthValue,2.0)),1.0);
}

有了shadowmap,接下来需要在比较阴影区域的深度值,可以通过

//vs
attribute vec3 pos;
attribute vec2 texcoord;
attribute vec3 normal;
uniform mat4 M;
uniform mat4 P;
uniform mat4 V;
uniform mat4 U_ProjectorMatrix;
varying vec2 V_Texcoord;
varying vec3 V_WorldPos;
varying vec4 V_ProjectCoord;
void main()
{
    V_Texcoord=texcoord;
    vec4 worldPos=M*vec4(pos,1.0);
    V_WorldPos=worldPos.xyz;
    V_ProjectCoord=U_ProjectorMatrix*worldPos;
    gl_Position=P*V*worldPos;
}
//fs
float CalculateShadow()
{
    vec3 fragPos=V_ProjectorSpaceFragPos.xyz/V_ProjectorSpaceFragPos.w;
    fragPos=fragPos*0.5+vec3(0.5); //to 0-1
    float depthInShadowMap=texture2D(U_ShadowMap,fragPos.xy).r;
    float currentDepth=fragPos.z;
    float shadow=(currentDepth-0.001)>depthInShadowMap?1.0:0.0;
    return shadow;
}
void main()
{
    //...
    vec4 color=ambientColor+(diffuseColor+specularColor)*vec4(vec3(1.0-CalculateShadow()),1.0);
}

总结

经过上述步骤可以将 阴影 绘制出来。如果希望阴影能降低锯齿,可以将深度图进行高斯模糊,或使用PCF(Percentage Closer Filtering)进行柔化。

猜你喜欢

转载自blog.csdn.net/fansongy/article/details/79303712
今日推荐