• opengl 教程(24) shadow mapping (2)


     
     
    原帖地址:http://ogldev.atspace.co.uk/www/tutorial24/tutorial24.html
         本篇教程中,我们通过shadowmap来实现阴影渲染。
                 
           我们知道shadow mapping是一个两趟渲染技术,在第一趟渲染过程中,光源位置作为视点,下面我们回顾一下第一趟渲染时候,顶点的z分量是如何变化的。
    1. 局部坐标空间中的顶点位置被传入vertex shader。
    2. 在vertex shader中,局部坐标的顶点值被转化为clip空间表示的顶点值。
    3. 执行透视除法,顶点被转化到归一化的clip空间,这个空间中x,y,z值的范围都是[-1,1],这个范围之外的顶点值都被clip掉。
    4. 光栅化时候映射x,y值到屏幕空间坐标系。(例如: 800x600, 1024x768, etc)。
    5. 光栅化阶段在屏幕空间中对三角形的顶点进行差值,得到该三角形覆盖的每个像素的x,y值。顶点的z值(仍在[-1,1]范围内)也被差值,结果放在深度缓冲中。
    6. 由于第一趟渲染中,禁止颜色写,所以fs(PS)不会被执行,但深度测试仍会进行,深度buffer也会更新。

    在第二趟渲染中,视点在摄像机的位置,所以我们会得到一个不同的深度缓冲。两个缓冲都是需要的,一个用来保证物体渲染顺序,一个用来判断顶点是否在阴影内。 我们可以通过在第二趟渲染的vertex shader中传入两个WVP矩阵来做到这个。

    1. 内建的 gl_Position是摄像机WVP矩阵转化后得到的顶点位置。
    2. 另一个传输到下一个阶段的向量则是光源位置WVP矩阵转化后的顶点值。

    向量gl_Position用作通常的渲染,另一个向量在光栅化阶段也被差值,每个fragment也有自己相应的值。 该向量的z值即为光源到该点的距离。该z值可以和shadow map中的深度值比较,决定该fragment是否在阴影内。

    1. 硬件会自动对gl_Position进行透视除法,但是对于我们传入的第二个向量,我们必须在fs(ps)中手工进行透视除法,以便把该向量转化为归一化clip空间中。
    2. 把[-1,1]范围的x,y坐标转为到[0,1]范围,以便能够作为纹理坐标,来采样shadow map值。
      • u = 0.5 * X + 0.5
      • v = 0.5 * Y + 0.5
    源码:

    lighting_technique.h

    class LightingTechnique : public Technique {
        public:
        ...
            void SetLightWVP(const Matrix4f& LightWVP);
            void SetShadowMapTextureUnit(unsigned int TextureUnit);
        ...
        private:
            GLuint m_LightWVPLocation;
            GLuint m_shadowMapLocation;
    ...

    增加一个新的属性,用来表示光源位置作为视点的WVP矩阵。我们用texture unit 0表示通常的纹理,texture unit 1表示shadow map。

    lighting.vs

    #version 400
    layout (location = 0) in vec3 Position;
    layout (location = 1) in vec2 TexCoord;
    layout (location = 2) in vec3 Normal;
    uniform mat4 gWVP;
    uniform mat4 gLightWVP;
    uniform mat4 gWorld;
    out vec4 LightSpacePos;
    out vec2 TexCoord0;
    out vec3 Normal0;
    out vec3 WorldPos0;
    void main()
    {
        gl_Position = gWVP * vec4(Position, 1.0);
    LightSpacePos = gLightWVP * vec4(Position, 1.0);
        TexCoord0 = TexCoord;
        Normal0 = (gWorld * vec4(Normal, 0.0)).xyz;
        WorldPos0 = (gWorld * vec4(Position, 1.0)).xyz;
    }

    lighting.fs:58

    float CalcShadowFactor(vec4 LightSpacePos)
    {
        vec3 ProjCoords = LightSpacePos.xyz / LightSpacePos.w;
        vec2 UVCoords;
        UVCoords.x = 0.5 * ProjCoords.x + 0.5;
        UVCoords.y = 0.5 * ProjCoords.y + 0.5;
        float z = 0.5 * ProjCoords.z + 0.5;
        float Depth = texture(gShadowMap, UVCoords).x;
        if (Depth < (z + 0.00001))
            return 0.5;
        else
            return 1.0;
    }

    上面这个shader函数用来计算阴影因子。

  • 相关阅读:
    django URL路由基础
    Django2.0 URL配置
    【转】MSMQ 微软消息队列 简单 示例
    Equeue初识
    有关C#标签Attribute的熟悉
    【原创】C#模拟Post请求,正文为json数据的代码参考
    2016年5月11日摘自知乎的一些Redis大概了解
    【原创】网站抓包HttpWebRequest不返回Javascript生成的Cookie的解决办法
    【原创】Silverlight客户端发起WebRequest请求分析
    【原创】记一次HttpWebRequest中国移动查账单爬虫的攻克历程
  • 原文地址:https://www.cnblogs.com/mikewolf2002/p/5140554.html
Copyright © 2020-2023  润新知