opengl deferred shading
原文地址:http://www.verydemo.com/demo_c284_i6147.html
一、Deferred shading技术简介
Deferred shading是这样一种技术:将光照/渲染计算推迟到第二步进行计算。我们这样做的目的是为了避免多次(超过1次)渲染同一个像素。
其基本思想如下:
1、在第一步中,我们渲染场景,但是与通常情况下应用反射模型计算片断颜色不同的是,我们只是简单的将几何信息(位置坐标,法线向量,纹理坐标,反射系数等等)存储在中间缓冲区中,这样的缓冲区我们称之为g-buffer(g是几何geometry的缩写)。
2、在第二步,我们从g-buffer中读取信息,应用反射模型,计算出每个像素的最终颜色。
Deferred shading技术的应用使得我们避免了应用反射模型于最终不可见的片断上。例如,考虑这样的像素,它位于两个多边形重叠的区域。通常的片断着色器会读对每个多边形分别计算那个像素一次;然而,两次执行的结果最终只有一个成为该像素的最终颜色(这里基于的一个假设是:混合已被禁用)。这样,其中的一次计算就是无用的。有了Deferred shading技术,反射模型的计算会推迟到所有几何体被处理之后,那时候每个像素位置几何体的可见性也是已知的。这样,对于屏幕上的每个像素,反射模型的计算只会发生一次。
Deferred shading容易懂而且便于使用。它能够帮助实施很复杂的光照/反射模型。
二、结合例子来说明Deferred shading技术
下面的例子采用Deferred shading技术渲染了一个包含一个茶壶和一个圆环的场景。效果如下:
图一 场景渲染效果图
在这个例子中,我们将位置坐标、法线以及漫反射因子存储在g-buffer里。在第二步的时候,我们使用g-buffer里面的数据来进行漫反射光照模型的计算。
g-buffer包含3个纹理:分别用来存储位置坐标、法线以及漫反射因子。对应的采用了3个uniform变量:PositionTex、NormalTex、ColorTex。
他们均被关联到一个FBO上。关于FBO使用见:FBO。
下面是创建包含g-buffer的FBO的代码:
GLuint depthBuf, posTex, normTex, colorTex;
// Create and bind the FBO
glGenFramebuffers(, &deferredFBO);
glBindFramebuffer(GL_FRAMEBUFFER, deferredFBO);
// The depth buffer
glGenRenderbuffers(, &depthBuf);
glBindRenderbuffer(GL_RENDERBUFFER, depthBuf);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
// The position buffer
glActiveTexture(GL_TEXTURE0); // Use texture unit 0
glGenTextures(, &posTex);
glBindTexture(GL_TEXTURE_2D, posTex);
glTexImage2D(GL_TEXTURE_2D, , GL_RGB32F, width, height, , GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// The normal buffer
glActiveTexture(GL_TEXTURE1);
glGenTextures(, &normTex);
glBindTexture(GL_TEXTURE_2D, normTex);
glTexImage2D(GL_TEXTURE_2D, , GL_RGB32F, width, height, , GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// The color buffer
glActiveTexture(GL_TEXTURE2);
glGenTextures(, &colorTex);
glBindTexture(GL_TEXTURE_2D, colorTex);
glTexImage2D(GL_TEXTURE_2D, , GL_RGB, width, height, , GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// Attach the images to the framebuffer
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuf);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, posTex, );
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, normTex, );
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, colorTex, );
GLenum drawBuffers[] = {GL_NONE, GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1,
GL_COLOR_ATTACHMENT2};
glDrawBuffers(, drawBuffers);
glBindFramebuffer(GL_FRAMEBUFFER, );
GLuint depthBuf, posTex, normTex, colorTex;
// Create and bind the FBO
glGenFramebuffers(, &deferredFBO);
glBindFramebuffer(GL_FRAMEBUFFER, deferredFBO);
// The depth buffer
glGenRenderbuffers(, &depthBuf);
glBindRenderbuffer(GL_RENDERBUFFER, depthBuf);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
// The position buffer
glActiveTexture(GL_TEXTURE0); // Use texture unit 0
glGenTextures(, &posTex);
glBindTexture(GL_TEXTURE_2D, posTex);
glTexImage2D(GL_TEXTURE_2D, , GL_RGB32F, width, height, , GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// The normal buffer
glActiveTexture(GL_TEXTURE1);
glGenTextures(, &normTex);
glBindTexture(GL_TEXTURE_2D, normTex);
glTexImage2D(GL_TEXTURE_2D, , GL_RGB32F, width, height, , GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// The color buffer
glActiveTexture(GL_TEXTURE2);
glGenTextures(, &colorTex);
glBindTexture(GL_TEXTURE_2D, colorTex);
glTexImage2D(GL_TEXTURE_2D, , GL_RGB, width, height, , GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// Attach the images to the framebuffer
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuf);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, posTex, );
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, normTex, );
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, colorTex, );
GLenum drawBuffers[] = {GL_NONE, GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1,
GL_COLOR_ATTACHMENT2};
glDrawBuffers(, drawBuffers);
glBindFramebuffer(GL_FRAMEBUFFER, );
注意:三个纹理分别使用函数glFramebufferTexture2D()关联到FBO的颜色关联点0、1、2上面。接着调用函数glDrawBuffers把它们和片断着色器的输出变量联系起来。
函数glDrawBuffer指示了FBO成员和片断着色器输出变量之间的联系。FBO中的第i个成员对应片断着色器中的索引为i的输出变量。这样,片断着色器(下面列出了完整代码)中相对应的输出变量分别是PosiutionData,NormalData和ColorData。
顶点着色器实现了一个很简单的功能:将位置坐标和法线转化到eye sapce中,然后传递到片断着色器中。而纹理坐标则没有发生变化。
片断着色器如下:
#version
struct LightInfo {
vec4 Position; // Light position in eye coords.
vec3 Intensity; // A,D,S intensity
};
uniform LightInfo Light;
struct MaterialInfo {
vec3 Kd; // Diffuse reflectivity
};
uniform MaterialInfo Material;
subroutine void RenderPassType();
subroutine uniform RenderPassType RenderPass;
uniform sampler2D PositionTex, NormalTex, ColorTex;
in vec3 Position;
in vec3 Normal;
in vec2 TexCoord;
layout (location = ) out vec4 FragColor;
layout (location = ) out vec3 PositionData;
layout (location = ) out vec3 NormalData;
layout (location = ) out vec3 ColorData;
vec3 diffuseModel( vec3 pos, vec3 norm, vec3 diff )
{
vec3 s = normalize(vec3(Light.Position) - pos);
float sDotN = max( dot(s,norm), 0.0 );
vec3 diffuse = Light.Intensity * diff * sDotN;
return diffuse;
}
subroutine (RenderPassType)
void pass1()
{
// Store position, normal, and diffuse color in textures
PositionData = Position;
NormalData = Normal;
ColorData = Material.Kd;
}
subroutine(RenderPassType)
void pass2()
{
// Retrieve position and normal information from textures
vec3 pos = vec3( texture( PositionTex, TexCoord ) );
vec3 norm = vec3( texture( NormalTex, TexCoord ) );
vec3 diffColor = vec3( texture(ColorTex, TexCoord) );
FragColor = vec4( diffuseModel(pos,norm,diffColor), 1.0 );
}
void main() {
// This will call either pass1 or pass2
RenderPass();
}
#version
struct LightInfo {
vec4 Position; // Light position in eye coords.
vec3 Intensity; // A,D,S intensity
};
uniform LightInfo Light;
struct MaterialInfo {
vec3 Kd; // Diffuse reflectivity
};
uniform MaterialInfo Material;
subroutine void RenderPassType();
subroutine uniform RenderPassType RenderPass;
uniform sampler2D PositionTex, NormalTex, ColorTex;
in vec3 Position;
in vec3 Normal;
in vec2 TexCoord;
layout (location = ) out vec4 FragColor;
layout (location = ) out vec3 PositionData;
layout (location = ) out vec3 NormalData;
layout (location = ) out vec3 ColorData;
vec3 diffuseModel( vec3 pos, vec3 norm, vec3 diff )
{
vec3 s = normalize(vec3(Light.Position) - pos);
float sDotN = max( dot(s,norm), 0.0 );
vec3 diffuse = Light.Intensity * diff * sDotN;
return diffuse;
}
subroutine (RenderPassType)
void pass1()
{
// Store position, normal, and diffuse color in textures
PositionData = Position;
NormalData = Normal;
ColorData = Material.Kd;
}
subroutine(RenderPassType)
void pass2()
{
// Retrieve position and normal information from textures
vec3 pos = vec3( texture( PositionTex, TexCoord ) );
vec3 norm = vec3( texture( NormalTex, TexCoord ) );
vec3 diffColor = vec3( texture(ColorTex, TexCoord) );
FragColor = vec4( diffuseModel(pos,norm,diffColor), 1.0 );
}
void main() {
// This will call either pass1 or pass2
RenderPass();
}
片断着色器则包含了关于光源、材料的一些信息,都是uniform变量,以用于光照计算。
片断着色器里面使用了subroutine技术,实现了两个函数pass1和pass2,分别包含了第一步和第二步的操作。我们在OpenGL应用程序中通过设置uniform变量的值可以选择使用相应的功能。
在OpenGL应用程序里面,
实施第一步的步骤如下:
1、绑定FBO;
2、情况颜色以及深度缓冲区,选择pass1 subroutine函数,启用深度测试;
3、渲染场景。
实施第二步的步骤是:
1、去除FBO绑定(将其绑定到0),目的是能够渲染场景到默认缓冲区,而不是FBO里面,它就能显示到屏幕上;
2、清除颜色缓冲去对象。禁用深度测试;
3、选择pass2 subroutine函数,渲染一个充满屏幕的四边形,带有纹理坐标,每个方向的纹理坐标的范围都是从0到1.计算光照模型,得出最后的片断颜色。
三、如何选择使用Deferred shading技术
在图形学领域,关于Deferred shading技术的优点和缺陷备受争议。这种技术并不适用所有的场合,它取决于你的应用程序的需求。因此在觉得是否采用这个技术之前一定要权衡它带来的优点和缺陷。
Deferred shading技术带来一个很重要的缺点就是不能使用基于硬件实现的多重采样抗锯齿功能。因为渲染过程发生在第二步,所以我们在第二步需要多个样本。但是,在第二步我们只有每一个像素的一个样本。
另外一个缺点就是不能使用混合技术。
参考资料:
《GPU Gems 2》的第9章
《GPU Gems 3》的第19章
http://blog.csdn.net/zhuyingqingfen/article/details/19406163
opengl deferred shading的更多相关文章
- Deferred shading rendering path翻译
Overview 概述 When using deferred shading, there is no limit on the number of lights that can affect a ...
- D3D Deferred Shading
在3D图形计算中,deferred shading是一个基于屏幕空间的着色技术.之所以被称为deferred shading,是因为我们将场景的光照计算与渲染"deferred"到 ...
- 引擎设计跟踪(九.14.3.2) Deferred shading的后续实现和优化
最近完成了deferred shading和spot light的支持, 并作了一部分优化. 之前forward shading也只支持方向光, 现在也支持了点光源和探照光. 对于forward sh ...
- 引擎设计跟踪(九.14.3.1) deferred shading: Depthstencil as GBuffer depth
问题汇总 1.Light support for Editor编辑器加入了灯光工具, 可以添加和修改灯光. 问题1. light object的用户互交.point light可以把对应的volume ...
- 引擎设计跟踪(九.14.3) deferred shading 准备
目前做的一些准备工作 1.depth prepass for forward shading. 做depth prepass的原因是为了完善渲染流程, 虽然架构上支持多个pass, 但实际上从来没有测 ...
- Deferred Shading 延迟着色(翻译)
原文地址:https://en.wikipedia.org/wiki/Deferred_shading 在3D计算机图形学领域,deferred shading 是一种屏幕空间着色技术.它被称为Def ...
- Deferred Shading,延迟渲染(提高渲染效率,减少多余光照计算)【转】
Deferred Shading,看过<Gems2> 的应该都了解了.最近很火的星际2就是使用了Deferred Shading. 原帖位置: http://blog.csdn.net ...
- Deferred Shading延迟渲染
Deferred Shading 传统的渲染过程通常为:1)绘制Mesh:2)指定材质:3)处理光照效果:4)输出.传统的过程Mesh越多,光照处理越费时,多光源时就更慢了. 延迟渲染的步骤:1)Pa ...
- Unity的Deferred Shading
什么是Deferred Shading Unity自身除了支持前向渲染之外,还支持延迟渲染.Unity的rendering path可以通过Edit/Project Settings中的Graphic ...
随机推荐
- maven deploy distributionManagement
分发构件至远程仓库 mvn install 会将项目生成的构件安装到本地Maven仓库,mvn deploy 用来将项目生成的构件分发到远程Maven仓库.本地Maven仓库的构件只能供当前用户使用, ...
- Python3求m以内的素数、求m个数中最小的n个数
[本文出自天外归云的博客园] 题1:求m以内的素数(m>2) def find_all_primes_in(m): def prime(num): for i in range(2, num): ...
- django HttpRequest对象
概述: 服务器接收http请求后,会根据报文创建HttpRequest对象 视图的第一个参数就是HttpRequest对象 django创建的,之后调用视图时传递给视图 属性 path:请求的完整路径 ...
- 开发错误处理记录(无法激活服务,因为它不支持 ASP.NET 兼容性)
错误提示:无法激活服务,因为它不支持 ASP.NET 兼容性.已为此应用程序启用了 ASP.NET 兼容性.请在 web.config 中关闭 ASP.NET 兼容性模式或将 AspNetCompat ...
- phpstorm设置断点过程
1.为php安装xdebug,方法在上一篇中有详细介绍 2.注意这个时候需要修改php.ini内容如下: [Xdebug]zend_extension_ts ="d:/wamp/php/ex ...
- curl Array to string conversion 错误
0x00 故障 由于GuzzleHttp在iis上使用错误,于是开始替换其为Unirest,没想到发送了一个curl Array to string conversion 错误 0x01 原因 跟踪调 ...
- 使用jquery的$.ajax向服务端传递中文,避免乱码的解决办法!
在js里,对中文使用下面的方法 encodeURIComponent(var) 函数 就ok了!
- Map 与 JavaBean 的相互装换
目的 为了方便使用 DbUtils,在插入数据时需要传入含有占位符的 SQL 语句和对应占位符的值(数组),封装代码如下: /** * 插入实体 */ public static <T> ...
- Go Revel - Filters(过滤器链)
`Fitlers`过滤器链是一个中间件,它们具有单独的功能,并作为管道对请求做链式处理.过滤器链执行框架的所有功能. 对过滤器链的源码分析,请移步 Go Revel - Filter(过滤器)源码分析 ...
- table中超过长度的列,显示省略号
<style type="text/css"> .table-ellipsis { table-layout: fixed; width: 100%; } .table ...