《OpenGL编程指南》第11章——Double-Write 案例分析

本案例主要讲解在Shader中如何使用图像(Images)对象。
案例通过创建了一维纹理Buffer(TBO)用来作为颜色数据,通过绘制多个圆柱体,将绘制结果缓存到另一个Image中,再在后续的模型绘制中使用该图像数据。
程序的主要执行流程:
###1 创建TBO对象,用于保存1D 纹理数据:

	GLuint m_image_palette_buffer; // 纹理缓冲区对象
	GLuint m_image_palette_texture; //纹理 

2. 创建输出纹理

	// 输出纹理,渲染第一阶段,在shader中写入数据,渲染第二阶段,在shader中读取数据
	GLuint m_output_texture;   
	// Output iamge and PBO for clear it 
	GLuint m_output_texture_clear_buffer;

3. 绘制流程:

  • 绑定m_iamge_palette_texture绑定到0号绑定点的图像对象,用于Shader中读取数据
  • 使用m_output_texture_clear_buffer,清空m_output_texture中的数据
  • 将m_output_texture绑定到1号绑定点的图像对象
  • 设置投影、模型、视图矩阵
  • 禁用颜色缓冲区,绘制多个圆柱体,通过shader,将颜色数据写入到m_output_texture中。
  • 将m_output_texture绑定到0号绑定点的图像对象
  • 绘制四边形

主要代码:

	// DoubleWrite.cpp
	#include <vapp.h>
	#include <vutils.h>
	#include <LoadShaders.h>
	#include <vbm.h>
	#include <vmath.h>
	#include <stdio.h>
	#include <iostream>
	
	#define MAX_FRAMEBUFFER_WIDTH 1024
	#define MAX_FRAMEBUFFER_HEIGHT 1024
	
	BEGIN_APP_DECLARATION(DoubleWrite)
		virtual void Initialize(const char* title);
		virtual void Display(bool auto_redraw);
		virtual void Finalize();
		virtual void Reshape(int width, int height);
		
		void InitShaders();
		void InitBuffers();
		
		
	private:
		// Color palette buffer texture  TBO 
		GLuint m_image_palette_buffer; // 纹理缓冲区对象
		GLuint m_image_palette_texture; //纹理 
		
		// 输出纹理,渲染第一阶段,在shader中写入数据,渲染第二阶段,在shader中读取数据
		GLuint m_output_texture;   
		// Output iamge and PBO for clear it 
		GLuint m_output_texture_clear_buffer;
	
		GLuint m_render_program; // 渲染模型着色器
		GLuint m_resolve_program; // 重显示着色器
		
		GLuint m_quad_vao;
		GLuint m_quad_vbo;
		
		GLuint m_xfb;
		GLfloat m_aspect;
		
		GLuint m_projection_matrix_loc;
		GLuint m_model_matrix_loc;
		GLuint m_view_matrix_loc;
		GLuint m_aspect_loc;
		GLuint m_time_loc;
		
		VBObject m_object;
		
		float m_current_height;
		float m_current_width;
		
	END_APP_DECLARATION()
	
	DEFINE_APP(DoubleWrite, "DoubleWrite")
	
	void DoubleWrite::InitShaders()
	{
		ShaderInfo render_shaders[] = {
			{GL_VERTEX_SHADER,"Media/Shaders/11/DoubleWrite.vs.glsl"},
			{GL_FRAGMENT_SHADER,"Media/Shaders/11/DoubleWrite.fs.glsl"},
			{GL_NONE,NULL} 
		};
		m_render_program = LoadShaders(render_shaders);
		m_model_matrix_loc = glGetUniformLocation(m_render_program,"model_matrix");
		m_view_matrix_loc = glGetUniformLocation(m_render_program,"view_matrix");
		m_projection_matrix_loc = glGetUniformLocation(m_render_program,"projection_matrix");
	
		ShaderInfo blit_shaders[] = {
			{GL_VERTEX_SHADER,"Media/shaders/11/DoubleWrite_blit.vs.glsl"},
			{GL_FRAGMENT_SHADER,"Media/shaders/11/DoubleWrite_blit.fs.glsl"},
			{GL_NONE,NULL}
		};
		m_resolve_program = LoadShaders(blit_shaders);
	}
	
	void DoubleWrite::InitBuffers()
	{
		// TBO
		glGenBuffers(1,&m_image_palette_buffer);
		glBindBuffer(GL_TEXTURE_BUFFER,m_image_palette_buffer); 
		// glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage);
		glBufferData(GL_TEXTURE_BUFFER,256*4*sizeof(float),NULL,GL_STATIC_DRAW); // 此处分配内存大小类似于一个1D纹理,使用256*1 的GL_RGBA32F,每个颜色一个float(4字节 4*8=32bit)
		glGenTextures(1,&m_image_palette_texture);
		glBindTexture(GL_TEXTURE_BUFFER,m_image_palette_texture); // 将纹理绑定到纹理缓冲区对象
		glTexBuffer(GL_TEXTURE_BUFFER,GL_RGBA32F,m_image_palette_buffer);
		
		vmath::vec4* data = (vmath::vec4*)glMapBuffer(GL_TEXTURE_BUFFER,GL_WRITE_ONLY);
		for(int i = 0; i < 256; i++)
		{
			// 初始化1D纹理数据
			//data[i] = vmath::vec4((float)i);
			data[i] = vmath::vec4((float)i, (float)(256-i),(float)(rand()&0xFFFF),1.0f);
		}
		glUnmapBuffer(GL_TEXTURE_BUFFER);
		
		// create output texture
		glActiveTexture(GL_TEXTURE0);
		glGenTextures(1,&m_output_texture);
		glBindTexture(GL_TEXTURE_2D,m_output_texture);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
		// glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
		glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA32F,MAX_FRAMEBUFFER_WIDTH,MAX_FRAMEBUFFER_HEIGHT,0,GL_RGBA,GL_FLOAT,NULL);
		glBindTexture(GL_TEXTURE_2D,0);
		// (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format);
		// glBindImageTexture(GLuint unit, GLuint texture, GLint level, GLboolean layerd, GLint layer, GLenum acces, GLenum format);
		glBindImageTexture(0,m_output_texture,0,GL_TRUE,0,GL_READ_WRITE,GL_RGBA32F); // 绑定 Image
		
		glGenBuffers(1,&m_output_texture_clear_buffer);
		glBindBuffer(GL_PIXEL_UNPACK_BUFFER,m_output_texture_clear_buffer); // 从buffer -->> Framebuffer or texture buffer
		// 对buffer 分配空间 ,红宝书使用GLuint,改成GLFloat也是可以的
		glBufferData(GL_PIXEL_UNPACK_BUFFER,MAX_FRAMEBUFFER_WIDTH*MAX_FRAMEBUFFER_HEIGHT* 4 *sizeof(GLfloat),NULL,GL_STATIC_DRAW); 
		data = (vmath::vec4*)glMapBuffer(GL_PIXEL_UNPACK_BUFFER,GL_WRITE_ONLY);
		memset(data,0x00,MAX_FRAMEBUFFER_HEIGHT*MAX_FRAMEBUFFER_WIDTH * 4 *sizeof(GLfloat));
		glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
	
		// creat  vao 
		static const GLfloat quad_vertices[] = {
			-1.0f, -1.0f,
			 1.0f, -1.0f,
			-1.0f,  1.0f,
			 1.0f,  1.0f,
		};
		
		glGenVertexArrays(1,&m_quad_vao);
		glGenBuffers(1,&m_quad_vbo);
		glBindVertexArray(m_quad_vao);
		glBindBuffer(GL_ARRAY_BUFFER,m_quad_vbo);
		glBufferData(GL_ARRAY_BUFFER,sizeof(quad_vertices),quad_vertices,GL_STATIC_DRAW);
		glVertexAttribPointer(0,2,GL_FLOAT,GL_FALSE,0,NULL);
		glEnableVertexAttribArray(0);
		
		glClearDepth(1.0f);
		
		glBindVertexArray(0);
	}
	void DoubleWrite::Initialize(const char* title)
	{
		base::Initialize(title);
		
		InitShaders();
		InitBuffers();
		
		std::string filePath = Utils::instance()->getMediaPath() + "Media/unit_pipe.vbm";
		m_object.LoadFromVBM(filePath.c_str(),0,1,2);
	}
	
	void DoubleWrite::Display(bool auto_redraw)
	{
		float t = float(GetTickCount() & 0xFFFF)/0x3FFF;
		static vmath::vec3 X(1.0f, 0.0f, 0.0f);
		static vmath::vec3 Y(0.0f, 1.0f, 0.0f);
		static vmath::vec3 Z(0.0f, 0.0f, 1.0f);
		
		glDisable(GL_DEPTH_TEST);
		glDisable(GL_CULL_FACE);
		
		glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
		glClear(GL_COLOR_BUFFER_BIT);
		
		// bind palette buffer
		//glBindBuffer(GL_TEXTURE_BUFFER,m_image_palette_buffer);
		//绑定图像数据到0上
		glBindImageTexture(0,m_image_palette_texture,0,GL_FALSE,0,GL_READ_ONLY,GL_RGBA32F);
		
		// clear output image  使用 m_output_texture_clear_buffer中的数据,重新覆盖m_output_texture中的数据,即清空原有数据,准备重新写入。
		glBindBuffer(GL_PIXEL_UNPACK_BUFFER,m_output_texture_clear_buffer);
		glBindTexture(GL_TEXTURE_2D,m_output_texture);
		glTexSubImage2D(GL_TEXTURE_2D,0,0,0,m_current_width,m_current_height,GL_RGBA,GL_FLOAT,NULL);
		glBindTexture(GL_TEXTURE_2D,0);
		
		//Bind output image for read-write
		// 绑定图像数据到1上
		glBindImageTexture(1,m_output_texture,0,GL_FALSE,0,GL_READ_WRITE,GL_RGBA32F);
		
		  vmath::mat4 model_matrix = vmath::translate(0.0f, 0.0f, -15.0f) *
	                               vmath::rotate(t * 360.0f, 0.0f, 0.0f, 1.0f) *
	                               vmath::rotate(t * 435.0f, 0.0f, 1.0f, 0.0f) *
	                               vmath::rotate(t * 275.0f, 1.0f, 0.0f, 0.0f);
	    vmath::mat4 view_matrix = vmath::mat4::identity();
	    vmath::mat4 projection_matrix = vmath::frustum(-1.0f, 1.0f, m_aspect, -m_aspect, 1.0f, 40.f);
		
		glUseProgram(m_render_program);
		glUniformMatrix4fv(m_projection_matrix_loc,1,GL_FALSE,projection_matrix);
		glUniformMatrix4fv(m_model_matrix_loc,1,GL_FALSE,model_matrix);
		glUniformMatrix4fv(m_view_matrix_loc,1,GL_FALSE,view_matrix);
		/*glColorMask, glColorMaski — enable and disable writing of frame buffer color components
		void glColorMask(	GLboolean red,
	 	GLboolean green,
	 	GLboolean blue,
	 	GLboolean alpha);
		*/
		// 禁止写入颜色缓存
		glColorMask(GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE);	
		m_object.Render(0,4 * 4 * 4);
		// 启用写入颜色缓存
		glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);
		glBindImageTexture(0,m_output_texture,0,GL_FALSE,0,GL_READ_ONLY,GL_RGBA32F);
		glBindVertexArray(m_quad_vao);
		glUseProgram(m_resolve_program);
		glDrawArrays(GL_TRIANGLE_STRIP,0,4);
		base::Display(auto_redraw);
	}
	void DoubleWrite::Finalize()
	{
		glUseProgram(0);
		glDeleteVertexArrays(1,&m_quad_vao);
		glDeleteBuffers(1,&m_quad_vbo);
	}
	void DoubleWrite::Reshape(int width, int height)
	{
		m_aspect  = GLfloat(width)/height;
		glViewport(0,0,width,height);
		m_current_width = width;
		m_current_height = height;
	}

猜你喜欢

转载自blog.csdn.net/kasteluo/article/details/83347121