FrameBufferObject.cpp

  帧缓冲区对象,Frame Buffer Object.创建渲染缓冲区,将渲染管线的输出可指定到渲染缓冲区,同时可以读渲染缓冲区.这些都是通过绑定帧缓冲区来做的.代码中将颜色输出分别写到两个渲染缓冲区中,再将这两个缓冲区的内容分别写到默认帧缓冲区中,效果就是左右颜色明暗不一样.书上的代码很复杂,我又实现了一个简单版的.加油吧,抓紧学习渲染,目前的进度比自己预想的慢太多太多了.

//	FrameBufferObject.cpp - 2013/09/28 - 20:35
#include "stdafx.h"
#include <GLTools.h>
#include <GLShaderManager.h>
#include <GLFrustum.h>
#include <GLBatch.h>
#include <GLMatrixStack.h>
#include <GLGeometryTransform.h>
#include <StopWatch.h>

#define FREEGLUT_STATIC
#include <GL/glut.h>

GLenum frameBufferObjectBuffers[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1,} ;
GLuint frameBufferObjectName ;
GLuint renderBufferNames[2] ;

GLFrame             viewFrame;
GLFrustum           viewFrustum;
GLTriangleBatch     sphereBatch;
GLMatrixStack       modelViewMatrix;
GLMatrixStack       projectionMatrix;
GLGeometryTransform transformPipeline;
GLShaderManager     shaderManager;

GLuint	ADSLightShader;
GLint	locAmbient;
GLint   locDiffuse;
GLint   locSpecular;
GLint	locLight;
GLint	locMVP;
GLint	locMV;
GLint	locNM;

GLfloat vEyeLight[] = { -100.0f, 100.0f, 100.0f };
GLfloat vAmbientColor[] = { 0.1f, 0.1f, 0.1f, 1.0f };
GLfloat vDiffuseColor[] = { 0.0f, 0.0f, 1.0f, 1.0f };
GLfloat vSpecularColor[] = { 1.0f, 1.0f, 1.0f, 1.0f };

GLint screenWidth ;
GLint screenHeight ;

void SetupRC(void)
{
	glClearColor(0.0f, 0.0f, 0.0f, 1.0f );

	glEnable(GL_DEPTH_TEST | GL_CULL_FACE);

	shaderManager.InitializeStockShaders();
	viewFrame.MoveForward(4.0f);

	gltMakeSphere(sphereBatch, 1.0f, 26, 13);

	ADSLightShader = shaderManager.LoadShaderPairWithAttributes(
		"ADSGouraud.vp", "ADSGouraud.fp",
		2,
		GLT_ATTRIBUTE_VERTEX, "vVertex",
		GLT_ATTRIBUTE_NORMAL, "vNormal") ;

	locAmbient = glGetUniformLocation(ADSLightShader, "ambientColor");
	locDiffuse = glGetUniformLocation(ADSLightShader, "diffuseColor");
	locSpecular = glGetUniformLocation(ADSLightShader, "specularColor");
	locLight = glGetUniformLocation(ADSLightShader, "vLightPosition");
	locMVP = glGetUniformLocation(ADSLightShader, "mvpMatrix");
	locMV  = glGetUniformLocation(ADSLightShader, "mvMatrix");
	locNM  = glGetUniformLocation(ADSLightShader, "normalMatrix");

	glLinkProgram(ADSLightShader) ;

	glGenFramebuffers(1, &frameBufferObjectName) ;

	glGenRenderbuffers(2, renderBufferNames) ;
	glBindRenderbuffer(GL_RENDERBUFFER, renderBufferNames[0]) ;
	glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, screenWidth, screenHeight) ;
	glBindRenderbuffer(GL_RENDERBUFFER, renderBufferNames[1]) ;
	glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, screenWidth, screenHeight) ;

	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBufferObjectName) ;
	glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderBufferNames[0]) ;
	glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER, renderBufferNames[1]) ;

	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0) ;
}

void ShutdownRC(void)
{
	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0) ;
	glBindFramebuffer(GL_READ_FRAMEBUFFER, 0) ;

	glDeleteRenderbuffers(2, renderBufferNames) ;

	glDeleteFramebuffers(1, &frameBufferObjectName) ;

	glUseProgram(0) ;

	glDeleteProgram(ADSLightShader) ;
}

void ChangeSize(int w, int h)
{
	if(h == 0)
		h = 1;

	glViewport(0, 0, w, h);

	viewFrustum.SetPerspective(35.0f, float(w)/float(h), 1.0f, 100.0f);

	projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
	transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);

	screenWidth = w ;
	screenHeight = h ;

	glBindRenderbuffer(GL_RENDERBUFFER, renderBufferNames[0]);
	glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, screenWidth, screenHeight);
	glBindRenderbuffer(GL_RENDERBUFFER, renderBufferNames[1]);
	glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, screenWidth, screenHeight);
	glBindRenderbuffer(GL_RENDERBUFFER, renderBufferNames[2]);
	glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, screenWidth, screenHeight);
}

void RenderScene(void)
{
	static CStopWatch rotTimer;

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	modelViewMatrix.PushMatrix(viewFrame);
	modelViewMatrix.Rotate(rotTimer.GetElapsedSeconds() * 10.0f, 0.0f, 1.0f, 0.0f);

	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBufferObjectName) ;
	glDrawBuffers(2, frameBufferObjectBuffers) ;

	glUseProgram(ADSLightShader);
	glUniform4fv(locAmbient, 1, vAmbientColor);
	glUniform4fv(locDiffuse, 1, vDiffuseColor);
	glUniform4fv(locSpecular, 1, vSpecularColor);
	glUniform3fv(locLight, 1, vEyeLight);
	glUniformMatrix4fv(locMVP, 1, GL_FALSE, transformPipeline.GetModelViewProjectionMatrix());
	glUniformMatrix4fv(locMV, 1, GL_FALSE, transformPipeline.GetModelViewMatrix());
	glUniformMatrix3fv(locNM, 1, GL_FALSE, transformPipeline.GetNormalMatrix());
	sphereBatch.Draw();

	modelViewMatrix.PopMatrix();

	glBindFramebuffer(GL_READ_FRAMEBUFFER, frameBufferObjectName) ;
	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0) ;

	glReadBuffer(GL_COLOR_ATTACHMENT0) ;
	glBlitFramebuffer(
		0, 0, screenWidth / 2, screenHeight,
		0, 0, screenWidth / 2, screenHeight,
		GL_COLOR_BUFFER_BIT, GL_NEAREST) ;

	glReadBuffer(GL_COLOR_ATTACHMENT1) ;
	glBlitFramebuffer(
		screenWidth / 2, 0, screenWidth, screenHeight,
		screenWidth / 2, 0, screenWidth, screenHeight,
		GL_COLOR_BUFFER_BIT, GL_NEAREST) ;

	glutSwapBuffers();
	glutPostRedisplay();
}

int main(int argc, char* argv[])
{
	gltSetWorkingDirectory(argv[0]);

	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
	glutInitWindowSize(800, 600);
	glutCreateWindow("Frame Buffer");
	glutReshapeFunc(ChangeSize);
	glutDisplayFunc(RenderScene);

	GLenum err = glewInit();
	if (err != GLEW_OK)
	{
		fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
		return 1;
	}

	SetupRC();    
	glutMainLoop();
	ShutdownRC();

	return 0;
}


 

### 如何在Qt中使用OpenGL实现网格(Mesh)渲染 #### 创建项目结构 为了在 Qt 中利用 OpenGL 实现网格渲染,通常会基于 `QWindow` 或者更高级别的组件如 `QOpenGLWidget` 来构建应用程序。对于复杂的场景管理,则可能涉及到 `Qt3DRender::QMesh` 类。 #### 初始化环境设置 当采用 `QOpenGLWidget` 作为绘图窗口时,在其子类内部重载虚函数完成初始化工作: ```cpp void MyGLWidget::initializeGL() { initializeOpenGLFunctions(); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); } ``` 此部分负责加载必要的 OpenGL 函数指针以及设定清除颜色等全局状态[^4]。 #### 加载几何数据 针对静态模型文件(例如 `.obj`, `.fbx`),可以借助第三方库 Assimp 进行导入处理。通过解析这些文件获取顶点位置、法线方向以及其他属性信息,并将其上传至 GPU 缓存区供后续着色器程序调用[^2]。 #### 构建缓冲对象 一旦获得了完整的顶点数组之后,下一步就是创建 VAO (Vertex Array Object),VBO(Vertex Buffer Object), EBO(Element Buffer Object): ```cpp // 假设 vertices 是已经准备好的 float 数组 GLuint vbo; glGenBuffers(1, &vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); GLuint ebo; glGenBuffers(1, &ebo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW); GLuint vao; glGenVertexArrays(1, &vao); glBindVertexArray(vao); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); // 启用第一个属性列表 ... glBindVertexArray(0); ``` 上述代码片段展示了如何分配并绑定各种类型的缓冲资源到当前上下文中去[^1]。 #### 渲染循环内绘制命令 最后一步是在 paintGL 方法里发出实际的绘制指令: ```cpp void MyGLWidget::paintGL() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glBindVertexArray(vao); glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(indices.size()), GL_UNSIGNED_INT, nullptr); glBindVertexArray(0); } ``` 这段逻辑会在每次屏幕刷新期间被执行一次,从而持续更新显示内容直到关闭应用为止。 #### 使用帧缓存对象(FBO) 如果希望进一步优化性能或是实现特殊效果的话,还可以考虑引入 FBO 技术来间接地进行纹理映射操作。比如下面的例子就说明了怎样把一个离屏渲染的结果存储起来再贴附给另一个物体表面作材质用途: ```cpp if (!m_frameBufferObject->bind()) { qDebug("Failed to bind framebuffer object"); } glViewport(0, 0, width(), height()); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 执行一些额外的渲染任务... m_frameBufferObject->release(); // 绑定之前生成过的纹理ID以便于其他地方能够访问该图像数据 glBindTexture(GL_TEXTURE_2D, m_frameBufferObject->texture()); // 接下来就可以像平常那样继续画东西啦~ ``` 以上即为基本流程概述;当然具体细节可能会因个人需求不同有所调整变化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值