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);	
    }

最终结果为:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值