OGL(教程35)——延迟渲染1——代码结构梳理
项目代码:git@gitee.com:yichichunshui/DeferredRendering1.git
int main(int argc, char** argv)
{
Magick::InitializeMagick(*argv);
GLUTBackendInit(argc, argv);
if (!GLUTBackendCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, 32, false, "Tutorial 35")) {
return 1;
}
SRANDOM;
首先是读取图片库的初始化;然后是初始化窗口的显示设置;然后初始化窗口;
Tutorial35* pApp = new Tutorial35();
Tutorial35()
{
m_pGameCamera = NULL;
m_scale = 0.0f;
m_persProjInfo.FOV = 60.0f;
m_persProjInfo.Height = WINDOW_HEIGHT;
m_persProjInfo.Width = WINDOW_WIDTH;
m_persProjInfo.zNear = 1.0f;
m_persProjInfo.zFar = 100.0f;
m_frameCount = 0;
m_fps = 0.0f;
m_time = glutGet(GLUT_ELAPSED_TIME);
}
一些初始化的操作。
if (!pApp->Init()) {
return 1;
}
初始化。
bool Init()
{
if (!m_gbuffer.Init(WINDOW_WIDTH, WINDOW_HEIGHT)) {
return false;
}
看下gbuffer的Init方法。
bool GBuffer::Init(unsigned int WindowWidth, unsigned int WindowHeight)
{
// Create the FBO
glGenFramebuffers(1, &m_fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo);
创建帧缓冲对象,绑定帧缓冲对象到GL_DRAW_FRAMEBUFFER目标。
// Create the gbuffer textures
glGenTextures(ARRAY_SIZE_IN_ELEMENTS(m_textures), m_textures);
glGenTextures(1, &m_depthTexture);
创建一个纹理数组,创建一个深度纹理。
for (unsigned int i = 0 ; i < ARRAY_SIZE_IN_ELEMENTS(m_textures) ; i++) {
glBindTexture(GL_TEXTURE_2D, m_textures[i]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, WindowWidth, WindowHeight, 0, GL_RGB, GL_FLOAT, NULL);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, m_textures[i], 0);
}
对每个纹理绑定,绑定目标为2D格式图片,为每个纹理分配内存,将每个纹理绑定到帧缓冲,以及设置其附件类型为GL_COLOR_ATTACHMENT0+i。
// depth
glBindTexture(GL_TEXTURE_2D, m_depthTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, WindowWidth, WindowHeight, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_depthTexture, 0);
绑定深度缓冲到2D格式,为深度纹理分配内存,绑定深度纹理到帧缓冲,设置其附件类型为GL_DEPTH_ATTACHMENT。
GLenum DrawBuffers[] = { GL_COLOR_ATTACHMENT0,
GL_COLOR_ATTACHMENT1,
GL_COLOR_ATTACHMENT2,
GL_COLOR_ATTACHMENT3 };
需要绘制四个类型的附件:分别是:
enum GBUFFER_TEXTURE_TYPE {
GBUFFER_TEXTURE_TYPE_POSITION, //对应GL_COLOR_ATTACHMENT0,位置
GBUFFER_TEXTURE_TYPE_DIFFUSE, //对应GL_COLOR_ATTACHMENT1,漫反射贴图
GBUFFER_TEXTURE_TYPE_NORMAL, //对应GL_COLOR_ATTACHMENT2,法线
GBUFFER_TEXTURE_TYPE_TEXCOORD, //GL_COLOR_ATTACHMENT1,纹理坐标
GBUFFER_NUM_TEXTURES //最后一个表示纹理数量,这里为4
};
glDrawBuffers(ARRAY_SIZE_IN_ELEMENTS(DrawBuffers), DrawBuffers);
绘制四个贴图。
GLenum Status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (Status != GL_FRAMEBUFFER_COMPLETE) {
printf("FB error, status: 0x%x\n", Status);
return false;
}
检查帧缓冲状态。
// restore default FBO
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
解绑当前自创建的缓冲,也就是恢复到默认的帧缓冲,
回到main的Init方法:
m_pGameCamera = new Camera(WINDOW_WIDTH, WINDOW_HEIGHT);
创建相机。
if (!m_DSGeomPassTech.Init()) {
printf("Error initializing DSGeomPassTech\n");
return false;
}
延迟渲染的几何阶段初始化:
bool DSGeomPassTech::Init()
{
if (!CompileProgram("GeometryPass")) {
return false;
}
编译程序GeometryPass程序,这个字符串在哪里,实际上我们要看下DSGeomPassTech的构造函数:
DSGeomPassTech::DSGeomPassTech() : Technique("shaders/geometry_pass.glsl")
{
}
基类为Technique:
Technique::Technique(const char* pEffectFile)
{
m_pEffectFile = pEffectFile;
m_shaderProg = 0;
m_effect = glfxGenEffect();
}
这个geometry_pass.glsl中的代码:
interface VSOutput
{
vec3 WorldSpacePos;
vec2 TexCoord;
vec3 Normal;
};
uniform mat4 gWVP;
uniform mat4 gWorld;
shader VSmain(in vec3 Pos, in vec2 TexCoord, in vec3 Normal, out VSOutput VSout)
{
gl_Position = gWVP * vec4(Pos, 1.0);
VSout.TexCoord = TexCoord;
VSout.Normal = (gWorld * vec4(Normal, 0.0)).xyz;
VSout.WorldSpacePos = (gWorld * vec4(Pos, 1.0)).xyz;
};
struct FSOutput
{
vec3 WorldSpacePos;
vec3 Diffuse;
vec3 Normal;
vec3 TexCoord;
};
uniform sampler2D gColorMap;
shader FSmain(in VSOutput FSin, out FSOutput FSout)
{
FSout.WorldSpacePos = FSin.WorldSpacePos;
FSout.Diffuse = texture(gColorMap, FSin.TexCoord).xyz;
FSout.Normal = normalize(FSin.Normal);
FSout.TexCoord = vec3(FSin.TexCoord, 0.0);
};
program GeometryPass
{
vs(410)=VSmain();
fs(410)=FSmain();
};
GLSL语言,书写的shader程序。
顶点着色器的输出是:位置、纹理坐标、法线、世界坐标。
片段着色器的输出是:世界坐标、漫反射、法线、纹理坐标。
这就是要输出四个颜色值。
m_WVPLocation = GetUniformLocation("gWVP");
m_WorldMatrixLocation = GetUniformLocation("gWorld");
m_colorTextureUnitLocation = GetUniformLocation("gColorMap");
得到属性的位置:gWVP、gWorld、gColorMap
if (m_WVPLocation == INVALID_UNIFORM_LOCATION ||
m_WorldMatrixLocation == INVALID_UNIFORM_LOCATION ||
m_colorTextureUnitLocation == INVALID_UNIFORM_LOCATION) {
return false;
}
return true;
}
判断获取是否出错。
回到main函数的Init方法:
m_DSGeomPassTech.Enable();
m_DSGeomPassTech.SetColorTextureUnit(COLOR_TEXTURE_UNIT_INDEX);
//#define COLOR_TEXTURE_UNIT_INDEX 0
if (!m_mesh.LoadMesh("../Content/phoenix_ugv.md2")) {
return false;
}
#ifdef FREETYPE
if (!m_fontRenderer.InitFontRenderer()) {
return false;
}
#endif
return true;
}
加载模型。
看函数:RenderSceneCB()
void DSGeometryPass()
{
m_DSGeomPassTech.Enable();
m_gbuffer.BindForWriting();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Pipeline p;
p.Scale(0.1f, 0.1f, 0.1f);
p.Rotate(0.0f, m_scale, 0.0f);
p.WorldPos(-0.8f, -1.0f, 12.0f);
p.SetCamera(m_pGameCamera->GetPos(), m_pGameCamera->GetTarget(), m_pGameCamera->GetUp());
p.SetPerspectiveProj(m_persProjInfo);
m_DSGeomPassTech.SetWVP(p.GetWVPTrans());
m_DSGeomPassTech.SetWorldMatrix(p.GetWorldTrans());
m_mesh.Render();
}
这个样之后,颜色都被存储在缓冲中了。
下面就是读取并展示出来:
void DSLightPass()
{
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
m_gbuffer.BindForReading();
GLint HalfWidth = (GLint)(WINDOW_WIDTH / 2.0f);
GLint HalfHeight = (GLint)(WINDOW_HEIGHT / 2.0f);
m_gbuffer.SetReadBuffer(GBuffer::GBUFFER_TEXTURE_TYPE_POSITION);
glBlitFramebuffer(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0, 0, HalfWidth, HalfHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR);
m_gbuffer.SetReadBuffer(GBuffer::GBUFFER_TEXTURE_TYPE_DIFFUSE);
glBlitFramebuffer(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0, HalfHeight, HalfWidth, WINDOW_HEIGHT, GL_COLOR_BUFFER_BIT, GL_LINEAR);
m_gbuffer.SetReadBuffer(GBuffer::GBUFFER_TEXTURE_TYPE_NORMAL);
glBlitFramebuffer(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, HalfWidth, HalfHeight, WINDOW_WIDTH, WINDOW_HEIGHT, GL_COLOR_BUFFER_BIT, GL_LINEAR);
m_gbuffer.SetReadBuffer(GBuffer::GBUFFER_TEXTURE_TYPE_TEXCOORD);
glBlitFramebuffer(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, HalfWidth, 0, WINDOW_WIDTH, HalfHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR);
}
最终结果为: