1. 程式人生 > >《OpenGL程式設計指南》第11章——Double-Write 案例分析

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