关于OpenGL实现VBO绘制的旗帜飘扬的作业的一个小思路

发布时间 2023-11-14 21:42:34作者: qbning

遇到一个问题,要求我用VBO画的旗帜有飘扬的动态,进一步,VBO绘制的图像怎么用曲面细分着色器。

下面是思路:

把VBO先绘制到帧缓冲里,然后保存成纹理

用纹理绘制的形式,使用曲面细分添加控制点

曲面细分评估里加入sin()函数即可

程序在有N卡的电脑上不显示不知道为什么

把VBO转换成纹理的函数

void convertTrianglesToFBOTexture(GLuint vbo,const int numTriangles,GLuint &textureId)
{
	int textureWidth;
	int textureHeight;
	GLuint fbo;

	// 创建临时顶点着色器和片段着色器源码
	const char* vertexShaderSource = R"(
        #version 430 core
		layout (location = 0) in vec3 position;
		layout (location = 1) in vec3 color;
		out vec3 fargcolor;
		uniform mat4 proj_matrix;
		uniform mat4 mv_matrix;
        void main()
        {
			gl_Position = proj_matrix * mv_matrix * vec4(position, 1.0);
			fargcolor = color; 
         }
    )";

	const char* fragmentShaderSource = R"(
        #version 430 core
        out vec4 color; // 声明color变量
		in vec3 fargcolor;
        void main()
        {
			color=vec4(fargcolor,1.0);
        }
    )";
	GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
	glCompileShader(vertexShader);

	// 检查顶点着色器编译是否成功
	GLint success;
	glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
	if (!success) 
	{
		char infoLog[512];
		glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
		std::cout << "顶点着色器编译失败!\n" << infoLog << std::endl;
		glDeleteShader(vertexShader);
		return;
	}

	// 编译片段着色器
	GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
	glCompileShader(fragmentShader);

	// 检查片段着色器编译是否成功
	glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
	if (!success) 
	{
		// 编译失败,处理错误
		char infoLog[512];
		glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
		std::cout << "段着色器编译失败!\n" << infoLog << std::endl;
		glDeleteShader(vertexShader);
		glDeleteShader(fragmentShader);
		return;
	}

	// 创建渲染程序并关联着色器
	GLuint shaderProgramTmp = glCreateProgram();
	glAttachShader(shaderProgramTmp, vertexShader);
	glAttachShader(shaderProgramTmp, fragmentShader);
	glLinkProgram(shaderProgramTmp);

	// 检查渲染程序链接是否成功
	glGetProgramiv(shaderProgramTmp, GL_LINK_STATUS, &success);
	if (!success) 
	{
		// 链接失败,处理错误
		char infoLog[512];
		glGetProgramInfoLog(shaderProgramTmp, 512, NULL, infoLog);
		std::cout << "链接失败!\n" << infoLog << std::endl;
		glDeleteShader(vertexShader);
		glDeleteShader(fragmentShader);
		glDeleteProgram(shaderProgramTmp);
		return;
	}

	// 绑定VBO并获取顶点数据
	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	float* vertexData = (float*)glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY);

	// 初始化最小和最大坐标为第一个顶点的坐标
	float minX = vertexData[0];
	float minY = vertexData[1];
	float maxX = vertexData[0];
	float maxY = vertexData[1];
	// 遍历顶点数据,找到最小和最大坐标
	for (int i = 0; i < numTriangles; i++) 
	{
		float x = vertexData[i * 6];
		float y = vertexData[i * 6 + 1];
		if (x < minX) 
			minX = x;
		if (x > maxX) 
			maxX = x;
		if (y < minY) 
			minY = y;
		if (y > maxY) 
			maxY = y;
	}
	textureWidth = 1200;
	textureHeight = 800;
	//cout << "纹理宽度 " << textureWidth << "\n纹理高度 " << textureHeight << "\n";
	// 创建帧缓冲对象
	glGenFramebuffers(1, &fbo);
	glBindFramebuffer(GL_FRAMEBUFFER, fbo);

	// 创建纹理对象
	glGenTextures(1, &textureId);
	glBindTexture(GL_TEXTURE_2D, textureId);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, textureWidth, textureHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureId, 0);

	//创建渲染缓冲对象
	//可参考https://zhuanlan.zhihu.com/p/109107214
	GLuint rbo;
	glGenRenderbuffers(1, &rbo);
	glBindRenderbuffer(GL_RENDERBUFFER, rbo);
	glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, textureWidth, textureHeight);
	//封装了24位的深度和8位的模板缓冲
	glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);

	// 检查帧缓冲是否完整
	if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
		glBindFramebuffer(GL_FRAMEBUFFER, 0);
		glDeleteFramebuffers(1, &fbo);
		glDeleteTextures(1, &textureId);
		return ;
	}
	// 绑定帧缓冲并渲染三角形到纹理
	glBindFramebuffer(GL_FRAMEBUFFER, fbo);
	glViewport(0, 0, textureWidth, textureHeight);
	glClear(GL_COLOR_BUFFER_BIT);
	
	glUseProgram(shaderProgramTmp);

	GLuint mvtmp,ptmp;
	glm::mat4 vMatmp = glm::translate(glm::mat4(1.0f), glm::vec3(0, 0, -18));
	glm::mat4 pMatmp = glm::perspective(1.0472f, aspect, 0.1f, 1000.0f);//透视投影矩阵
	ptmp = glGetUniformLocation(shaderProgramTmp, "proj_matrix");
	mvtmp = glGetUniformLocation(shaderProgramTmp, "mv_matrix");
	//vMat = glm::mat4(1.0f);
	glUniformMatrix4fv(mvtmp, 1, GL_FALSE, glm::value_ptr(vMatmp));
	glUniformMatrix4fv(ptmp, 1, GL_FALSE, glm::value_ptr(pMatmp));

	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	// 设置顶点属性指针,包括位置和颜色
	glVertexAttribPointer(0, 3, GL_FLOAT, false, 6 * sizeof(float), 0);
	glEnableVertexAttribArray(0);
	glVertexAttribPointer(1, 3, GL_FLOAT, false, 6 * sizeof(float), (void*)(3 * sizeof(float)));
	glEnableVertexAttribArray(1);
	// 绘制三角形(包括矩形和五个五角星)
	
	glDrawArrays(GL_TRIANGLES, 0, 156);
	
	// 解绑帧缓冲
	glBindFramebuffer(GL_FRAMEBUFFER, 0);
	
	//删除临时顶点着色器、片段着色器和渲染程序
	glDeleteShader(vertexShader);
	glDeleteShader(fragmentShader);
	glDeleteProgram(shaderProgramTmp);

	//return textureId;
}

今天终于验收完成计图的实验啦!

好好复习考试吧