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函数用来计算阴影因子。

时间: 2024-10-17 22:24:25

opengl 教程(24) shadow mapping (2)的相关文章

opengl 教程(23) shadow mapping (1)

   原帖地址:http://ogldev.atspace.co.uk/www/tutorial23/tutorial23.html          当光投射到物体上时,会在地面或者墙壁等物体上产生阴影.在计算机图形学中,有很多种技术可以产生阴影,本篇教程中,我们学习一种最常用的阴影技术-shadow mapping.       对于OpenGL程序中的阴影问题,可以归结为:如何判定一个像素是否在阴影区域.简单的说,我们可以把像素的位置和光源的位置连接起来(如下图所示),如果连接线通过物体(

c++-opengl shadow mapping 和原有纹理冲突

问题描述 opengl shadow mapping 和原有纹理冲突 在opengl的阴影贴图的时候,创建了阴影纹理之后,要对当前纹理状态改变,然后绘制模型,但是我模型里面有之前的问题,改变了纹理状态之后之前的纹理就会错乱了,不知道怎么能在不影响之前的纹理的情况下创建阴影贴图呢 解决方案 Shadow Mapping Using OpenGLOpenGL Shadow mapping 解决方案二: 解决方案三: 在opengl的阴影贴图的时候,创建了阴影纹理之后,要对当前纹理状态改变,然后绘制模

NeHe的OpenGL教程6(Bang翻译Delphi版)-如何用图片进行纹理映射

NeHe的OpenGL教程6(Bang翻译Delphi版)-如何用图片进行纹理映射 在这一课里,我将教会你如何把纹理映射到立方体的六个面,如下图: 将下图放在应用程序data目录下,起名NeHe.bmp program lesson6a; {    OpenGL DelphiXE    出处:根据NeHe代码翻译而来(http://nehe.gamedev.net/)    作者:帅宏军 shuaihj@163.com     注:本单元用到了glaux.dll和glaux.pas,下载地址为:

NeHe的OpenGL教程1(Bang翻译Delphi版)-如何绘制OpenGL窗口

NeHe的OpenGL教程1(Bang翻译Delphi版)-如何绘制OpenGL窗口 在这个教程里,我将教你在Windows环境中创建OpenGL程序.它将显示一个空的OpenGL窗口,可以在窗口和全屏模式下切换,按ESC退出.它是我们以后应用程序的框架.如下图: program lesson1a; {    OpenGL DelphiXE    出处:根据NeHe代码翻译而来(http://nehe.gamedev.net/)    作者:帅宏军 shuaihj@163.com} uses 

NeHe的OpenGL教程2(Bang翻译Delphi版)-如何绘制平面图形

NeHe的OpenGL教程2(Bang翻译Delphi版)-如何绘制平面图形 这一课中,我将教您如何创建三角形和四边形.如下图: program lesson2a; {    OpenGL DelphiXE    出处:根据NeHe代码翻译而来(http://nehe.gamedev.net/)    作者:帅宏军 shuaihj@163.com} uses  Windows,  Messages,  OpenGL; // 全局变量var  h_Rc: HGLRC;               

NeHe的OpenGL教程5(Bang翻译Delphi版)-如何绘制立方体

NeHe的OpenGL教程5(Bang翻译Delphi版)-如何绘制立方体 在这一课里,我们把三角形变为立体的金子塔形状,把四边形变为立方体,如下图: program lesson5a; {    OpenGL DelphiXE    出处:根据NeHe代码翻译而来(http://nehe.gamedev.net/)    作者:帅宏军 shuaihj@163.com} uses  Windows,  Messages,  OpenGL; // 全局变量var  h_Rc: HGLRC;    

NeHe的OpenGL教程4(Bang翻译Delphi版)-如何让图形旋转

NeHe的OpenGL教程4(Bang翻译Delphi版)-如何让图形旋转 在这一课里,我将教会你如何旋转三角形和四边形.左图中的三角形沿Y轴旋转,四边形沿着X轴旋转.如下图 program lesson4a; {    OpenGL DelphiXE    出处:根据NeHe代码翻译而来(http://nehe.gamedev.net/)    作者:帅宏军 shuaihj@163.com} uses  Windows,  Messages,  OpenGL; // 全局变量var  h_Rc

NeHe的OpenGL教程7(Bang翻译Delphi版)-如何使用光源

NeHe的OpenGL教程7(Bang翻译Delphi版)-如何使用光源        在这一课里,我将教会你如何用光源照亮立方体的六个面,如下图: 将下图放在应用程序data目录下,起名NeHe.bmp program lesson7a; {    OpenGL DelphiXE    出处:根据NeHe代码翻译而来(http://nehe.gamedev.net/)    作者:帅宏军 shuaihj@163.com     在这一课里,我将教会你如何用光源照亮立方体的六个面     注:本

Dreamweaver MX 2004视频宝典教程(24)

dreamweaver|教程 第 24 集:一个HTML的示例 课程目标:通过示例了解html的基本构成. 课程要点:通过一个简单的html示例,介绍html的基本组成部分. [全屏观看] | [下载视频] |