Tutorial - Deferred Rendering Shadow Mapping 转
http://www.codinglabs.net/tutorial_opengl_deferred_rendering_shadow_mapping.aspx
Tutorial - Deferred Rendering Shadow Mapping
In this tutorial I will present the shadow mapping technique implemented in a deferred renderer. This tutorial will lean on a previous one, Simple Deferred Rendering in OpenGL; I strongly reccomend you to read it before proceeding with this tutorial as most of the code is shared and I will not present those bits that have already been covered in the other tutorial.
Shadow Mapping is the most widely used technique in real time rendering engines today. Almost every game uses some sort of shadow mapping technique to render its shadows, even if often the actual implementation relies on extensions of the basic shadow mapping that we will see in this tutorial. Some more advanced implementations are Cascade Shadow Mapping, Soft Shadow Mapping, Parallel Split Shadow Mapping, etc etc. For this tutorial we will simply try to understand the basics ideas that all these techniques use, which is using a texture (map) to encode useful information to render shadows.
![]() |
![]() |
Determining whether a pixel is in shadow or if it's lit by a given light is a visibility problem. What we want to test is if that specific point in the world is visible or not from the light point of view. We apply this idea to every pixel that we are rendering on screen thus what we want to do is to calculate what position each pixel is mapped to in world space. Once we have the position we can cast a ray back to the light. If the ray can reach the light without being interrupted, the pixel is in light, otherwise is in shadow. Watch the picture below (Figure 1). You can see how the two point are both visible from the camera, but just one is visible from the light.
| Figure 1: Points in shadow and in light |
So now we know the principle and we can proceed to the practice. How can we determine whether a pixel (remapped in world) is visible or not from the light position. There are many many ways, but the one we are going to implement takes advantage of the ability of the GPU to render the depth of a scene. So if we set an imaginary camera in the light position and we render the depth of the scene as seen from the light what we get is a texture that contains a bunch of distances. Every pixel of this shadow map can be remapped in world space and will tell you what pixel the light see and how far that point is from the light itself. Watch Figure 2 below. The first point, P1, is visible from both the camera point of view and the light point of view. So if when we render it we also calculate its world position and then calculate the distance from the light we can compare it with the distance saved in the shadow map. When we compare P1's distance we will find that the value we calculate is the same value contained in the map (minus some error due to the way we store depth in the map). This because the pixel is visible frome the light point of view.
If we try to do the same with P2 we'll find a substantial difference. Say we calculate P2 in world space and then we calculate the distance between P2 in world space and the light as we did for P1. Now, if we compare the calculated distance with the distance saved in the shadow map we'll find that the one in the map is way smaller than the one we have just calculated. This because in the map the light will have the distance between P3 and the light itself. In fact, if you see from the light point of view P2 and P3 are overlapped, and since P3 is the closest one it "overrides" P2 which is then not visible. This tells us that P2 is in shadow.
| Figure 2: Points in shadow and in light seen from light and camera |
This is all you need to implement shadow mapping. Let's see the sample code and let's try to make it as clear as possible.
1 |
I'll try to present the code not from the first to the last line but instead picking various funcionality and explaining what is doing what. So, let's start from the the rendering function. /** To start we want to acquire the shadow map, therefore we position the camera in the light's position and we orient it so that it looks down to the scene. We also flip from the standard CCW to CW when rendering the shadow map. This is a nice trick that works as far as every object is "closed". Flipping to CW renders the object "inside out" which means that we will use the back faces for comparing the distances reducing the shadow acne that typically shows up with shadow mapping. This is not mandatory, it just helps a bit in most of the cases (but make it worst in others). // Render the shadow map We then render all the models into the shadow map. We'll check how the shadow map is created in a moment, for now all we need to know is that here we render all the models' depth into a texture. // We then save out the matrices and send them to the deferred rendering, so when it comes to do the deferred pass We store the matrices in some local variables because we need to provide them to the shader to reproject the pixels back in world and into the light clip/projection space. Notice that we also restore the renderer back to render faces CCW. // Render our geometry into the FBO This is the core of the rendering procedure. Summarizing we acquire the shadow map, save the matrices, send the matrices to the shader and then render. So we now have to see in detail two more things: how we create and use the shadow map and, the most important one, the shader that composes and renders the final frame. |
2 |
Let's see how do we capture the shadow map. Since all we need to store in the shadow map is the depth, we don't have to create a colour render target. All we need is a render target that can receive depth. To isolate this feature I've created a class called DepthRenderTexture which provides some methods to render the depth into the render target and some debug functionality to show the render target as a texture. The constructor of this class tells OpenGL that we only want to render depth into an FBO: // Generate the OGL resources for what we need Once the OpenGL resource is created we can acquire the texture as we would do with a normal FBO. This is wrapped by the start and stop methods. |
3 |
We are now to the last step of this tutorial. How to combine everything and define whether a pixel is in shadow or not. All the magic happens in the shader, so we will now analyze it bit by bit. uniform sampler2D tDiffuse; So what's different from the previous tutorial? For a start we now read the light position from the light matrix (since we have it), but the important bit is obviously the line that calls readShadowMap(eyeDir). At that line we call the funcion that given the camera to pixel vector decides if the pixel we see is in shadow or not. We will see the function in a moment. The shadow value ranges between 0.0 to 1.0. We then use this value to make the diffuse light black and to kill the specular reflection. float readShadowMap(vec3 eyeDir) The eyeDir that comes in input is in View Space. To find the pixel in the shadow map we need to take that point and covert it into the light's clip space, which means going from Camera View Space into World Space, then into Light View Space, than into Light Projection Space/Clip space. All these transformations are done using matrices; if you are not familiar with space changes you may want to read my article about spaces and transformations. Once we are in the right space we calculate the texture coordinates and we are finally ready to read from the shadow map. Bias is a small offset that we apply to the values in the map to avoid that because of rounding errors a point ends up shading itself! So we shift all the map back a bit so that all the values in the map are slightly smaller than they should. Finally we check if the distance between the point and the light (projectedEyeDir) is smaller than the value stored in the depth map. Notice how we need to scale back projectedEyeDir from the -1 -> 1 range to the 0->1 range as the shadow map is in this latter range. That's it, not too difficult if you graps the idea of chaning space and mapping pixels into a map of dephts! Feel free to grab the code and have a play with it, as usual, trying yourself is way more useful than any explanation. |
Tutorial - Deferred Rendering Shadow Mapping 转的更多相关文章
- (转)Shadow Mapping
原文:丢失,十分抱歉,这篇是在笔记上发现的.SmaEngine 阴影和级联部分是模仿UE的结构设计 This tutorial will cover how to implement shadow ...
- OpenGL阴影,Shadow Mapping(附源程序)
实验平台:Win7,VS2010 先上结果截图(文章最后下载程序,解压后直接运行BIN文件夹下的EXE程序): 本文描述图形学的两个最常用的阴影技术之一,Shadow Mapping方法(另一种是Sh ...
- Tile-Based Deferred Rendering
目前所有的移动设备都使用的是 Tile-Based Deferred Rendering(TBDR) 的渲染架构.TBDR 的基本流程是这样的,当提交渲染命令的时候,GPU 不会立刻进行渲染,而是一帧 ...
- Shadow mapping
http://www.cnblogs.com/cxrs/archive/2009/10/17/1585038.html 1.什么是Shadow Maping? Shadow Mapping是 ...
- opengl 教程(24) shadow mapping (2)
原帖地址:http://ogldev.atspace.co.uk/www/tutorial24/tutorial24.html 本篇教程中,我们通过shadowmap来实现阴影渲染. 我们知道shad ...
- OpenGL 阴影之Shadow Mapping和Shadow Volumes
先说下开发环境.VS2013,C++空项目,引用glut,glew.glut包含基本窗口操作,免去我们自己新建win32窗口一些操作.glew使我们能使用最新opengl的API,因winodw本身只 ...
- shadow mapping实现动态shadow实现记录 【转】
http://blog.csdn.net/iaccepted/article/details/45826539 前段时间一直在弄一个室内场景,首先完成了render,效果还可以.然后给其加上shado ...
- OpenGL核心技术之Shadow Mapping改进版
笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者;已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D实战核心技术详解 ...
- OpenGL核心技术之Shadow Mapping
笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人;已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D ...
随机推荐
- 代码审计之SQL注入
0x00概况说明 0x01报错注入及利用 环境说明 kali LAMP 0x0a 核心代码 现在注入的主要原因是程序员在写sql语句的时候还是通过最原始的语句拼接来完成,另外SQL语句有Select. ...
- Ubuntu14.04安装OpenCV2.4.9
1.安装依赖 sudo apt-get install build-essential libgtk2.0-dev libjpeg-dev libtiff4-dev libjasper-dev lib ...
- 基于配置文件(xml)的S2S3H3搭建
本次环境选择:JDK1.6+MySQL数据库+C3P0连接池+(struts2,spring3,hibernate3) 首先,创建WEB工程 然后倒入相关jar包(maven项目,在pom.xml中导 ...
- Android studio 中的配置编译错误总结
1.编译Andorid 工程的时候,有时候出现gradle 报下面的错误. Error:(1, 0) Cause: com/android/build/gradle/LibraryPlugin : U ...
- Android例子源码非第三方实现根据字母排序的城市列表
values 下dimens.xml <resources> <!-- Default screen margins, per the Android Design guidelin ...
- angular_ui-router ——依赖注入
Angularjs ui-router - 组件: $state / $stateProvider:管理状态定义.当前状态和状态转换.包含触发状态转换的事件和回调函数,异步解决目标状态的任何依赖项,更 ...
- edittext把软键盘上的回车键改为搜索、发送或者 下一步,窗口随软键盘弹出而改变。
http://m.blog.csdn.net/article/details?id=51350501 以上博文讲解很详细. 如图所示,有时候为了布局美观,在搜索时没有搜索按钮,而是调用软件盘上的按钮. ...
- 测试机安装fd-server问题记录
今天在239测试机上安装了fd-server来代替apache,汇总下遇到的问题和解决方法. 1. 安装git时使用yum安装,命令 yum install git 2. 启动fd-server之前要 ...
- JS调用JCEF方法
坐下写这篇文章的时候,内心还是有一点点小激动的,折腾了一个多星期,踩了一个又一个的坑,终于找到一条可以走通的路,内心的喜悦相信经历过的人都会明白~~~~~今儿个老百姓啊,真呀个真高兴啊,哈哈,好了,废 ...
- C扩展python的module和Type
有许多理由给CPython写扩展,比如 1.性能低 2.重复用别人的C/C++代码 3.在自己的程序中定制python 4.为了方便 等等. 写这种扩展其实都是套路,不过最好要有对CPython源码有 ...

