Deferred shading是这样1种技术:将光照/渲染计算推延到第2步进行计算。我们这样做的目的是为了不屡次(超过1次)渲染同1个像素。
其基本思想以下:
1、在第1步中,我们渲染场景,但是与通常情况下利用反射模型计算片断色彩不同的是,我们只是简单的将几何信息(位置坐标,法线向量,纹理坐标,反射系数等等)存储在中间缓冲区中,这样的缓冲区我们称之为g-buffer(g是几何geometry的缩写)。
2、在第2步,我们从g-buffer中读取信息,利用反射模型,计算出每一个像素的终究色彩。
Deferred shading技术的利用使得我们避免了利用反射模型于终究不可见的片断上。例如,斟酌这样的像素,它位于两个多边形堆叠的区域。通常的片断着色器会读对每一个多边形分别计算那个像素1次;但是,两次履行的结果终究只有1个成为该像素的终究色彩(这里基于的1个假定是:混合已被禁用)。这样,其中的1次计算就是无用的。有了Deferred shading技术,反射模型的计算会推延到所有几何体被处理以后,那时候每一个像素位置几何体的可见性也是已知的。这样,对屏幕上的每一个像素,反射模型的计算只会产生1次。
Deferred shading容易懂而且便于使用。它能够帮助实行很复杂的光照/反射模型。
2、结合例子来讲明Deferred shading技术
下面的例子采取Deferred shading技术渲染了1个包括1个茶壶和1个圆环的场景。效果以下:
图1 场景渲染效果图
在这个例子中,我们将位置坐标、法线和漫反射因子存储在g-buffer里。在第2步的时候,我们使用g-buffer里面的数据来进行漫反射光照模型的计算。
g-buffer包括3个纹理:分别用来存储位置坐标、法线和漫反射因子。对应的采取了3个uniform变量:PositionTex、normalTex、ColorTex。
他们均被关联到1个FBO上。关于FBO使用见:FBO。
- gluint depthBuf, posTex, normTex, colorTex;
-
- // Create and bind the FBO
- glGenFramebuffers(1, &deferredFBO);
- glBindFramebuffer(GL_FRAMEBUFFER, deferredFBO);
-
- // The depth buffer
- glGenRenderbuffers(1, &depthBuf);
- glBindRenderbuffer(GL_RENDERBUFFER, depthBuf);
- glrenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
-
- // The position buffer
- glActiveTexture(GL_TEXTURE0); // Use texture unit 0
- glGenTextures(1, &posTex);
- glBindTexture(GL_TEXTURE_2D, posTex);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, 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(1, &normTex);
- glBindTexture(GL_TEXTURE_2D, normTex);
- glTexImage2D(GL_TEXTURE_2D, GL_NEAREST);
-
- // The color buffer
- glActiveTexture(GL_TEXTURE2);
- glGenTextures(1, &colorTex);
- glBindTexture(GL_TEXTURE_2D, colorTex);
- glTexImage2D(GL_TEXTURE_2D, 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, 0);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, 0);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, colorTex, 0);
-
- GLenum drawBuffers[] = {GL_NONE,
- GL_COLOR_ATTACHMENT2};
- glDrawBuffers(4, drawBuffers);
-
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
注意:3个纹理分别使用函数glFramebufferTexture2D()关联到FBO的色彩关联点0、1、2上面。接着调用函数glDrawBuffers把它们和片断着色器的输出变量联系起来。
函数glDrawBuffer唆使了FBO成员和片断着色器输出变量之间的联系。FBO中的第i个成员对应片断着色器中的索引为i的输出变量。这样,片断着色器(下面列出了完全代码)中相对应的输出变量分别是PosiutionData,normalData和ColorData。
顶点着色器实现了1个很简单的功能:将位置坐标和法线转化到eye sapce中,然后传递到片断着色器中。而纹理坐标则没有产生变化。
片断着色器以下: