原帖地址: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函数用来计算阴影因子。

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

  1. OpenGL 阴影之Shadow Mapping和Shadow Volumes

    先说下开发环境.VS2013,C++空项目,引用glut,glew.glut包含基本窗口操作,免去我们自己新建win32窗口一些操作.glew使我们能使用最新opengl的API,因winodw本身只 ...

  2. OpenGL阴影,Shadow Mapping(附源程序)

    实验平台:Win7,VS2010 先上结果截图(文章最后下载程序,解压后直接运行BIN文件夹下的EXE程序): 本文描述图形学的两个最常用的阴影技术之一,Shadow Mapping方法(另一种是Sh ...

  3. OpenGL核心技术之Shadow Mapping改进版

    笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者;已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D实战核心技术详解 ...

  4. OpenGL核心技术之Shadow Mapping

    笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人;已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D ...

  5. OpenGL阴影,Shadow Volumes(附源程序,使用 VCGlib )

    实验平台:Win7,VS2010 先上结果截图:    本文是我前一篇博客:OpenGL阴影,Shadow Mapping(附源程序)的下篇,描述两个最常用的阴影技术中的第二个,Shadow Volu ...

  6. Tutorial - Deferred Rendering Shadow Mapping 转

    http://www.codinglabs.net/tutorial_opengl_deferred_rendering_shadow_mapping.aspx Tutorial - Deferred ...

  7. NeHe OpenGL教程 第四十六课:全屏反走样

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  8. NeHe OpenGL教程 第三十五课:播放AVI

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  9. NeHe OpenGL教程 第三十二课:拾取游戏

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

随机推荐

  1. Python - 计算个人所得税

    最近在学python,写了个计算个人所得税计算的脚本,分享. 以下为python3适用版本 #!/usr/bin/python # -*- coding: UTF-8 -*- # 该python脚本用 ...

  2. 使用React Hooks新特性useReducer、useContext替代传统Redux高阶组件案例

    当我们使用redux进行数据管理的时候,一般都是在根组件通过Provider的方式引入store,然后在每个子组件中,通过connect的方式使用高阶组件进行连接,这样造成的一个问题是,大量的高阶组件 ...

  3. Activity-Flag标志位

    Activity-Flag标志位 学习自 <Android开发艺术探索> 标志位漫谈 var intent: Intent = Intent(this, Test2Activity::cl ...

  4. http://blog.mn886.net/jqGrid/

    http://blog.mn886.net/jqGrid/  中文版 http://www.trirand.com/blog/jqgrid/jqgrid.html  英文版

  5. # 2017-2018-20172309 暑期编程作业:APP

    2017-2018-20172309 暑期编程作业:基于有道词典API的翻译软件的实现. 写在前面:这个博客可以说是拖了很久了.因为做这个APP已经很久了,很多东西都已经忘记了,所以一直都懒得写.但是 ...

  6. Codeforces Round #370 (Div. 2) C. Memory and De-Evolution 水题

    C. Memory and De-Evolution 题目连接: http://codeforces.com/contest/712/problem/C Description Memory is n ...

  7. CentOS的epel源rpm最新下载地址获取技巧

    最近发现以前的的脚本上安装epel不起作用,最后发现是官方更新了,且每次更新都会把以前旧的删除. 鉴于上面这种情况,不建议安装rpm包,直接转投阿里云的镜像站点,下载文件替换,阿里云的好处是不改文件名 ...

  8. 使用CefSharp在.Net程序中嵌入Chrome浏览器(四)——启动优化

    在实际使用过程中,发现有的客户端会出现chrome加载网页过慢问题,定位后发现很多是因为设置系统代理所致,此时可以通过如下启动参数禁止系统代理. {"proxy-auto-detect&qu ...

  9. LPC18xx and LPC43xx 选型及差异

    Q LPC43xx和LPC18xx有相同的USB接口以及片内USB驱动吗?A 是的. Q LPC4300和LPC1800只是内核不同吗?外设和管脚配置都完全一致?A 为LPC18xx的映像可以直接在L ...

  10. LPC43xx SGPIO Experimentation

    LPC4350 SGPIO Experimentation The NXP LPC43xx microcontrollers have an interesting, programmable ser ...