opengl vbo

opengl vbo
opengl vbo是对顶点进行排序。把相同属性的顶点用同一个索引代替。

// glfwTest.cpp : 定义控制台应用程序的入口点。
//
#include "glew.h"
#include <glfw3.h>
#include "common/loadShader.h"
#include "common/controls.h"
#include "common/objloader.h"
#include "common/vboindexer.h"

#include "glm.hpp"
#include "ext.hpp"
GLFWwindow* window;
int main(void)
{
	//GLFWwindow* window;

	/* Initialize the library */
	if (!glfwInit())
		return -1;

	/* Create a windowed mode window and its OpenGL context */
	window = glfwCreateWindow(480, 320, "Hello World", NULL, NULL);
	if (!window)
	{
		glfwTerminate();
		return -1;
	}

	/* Make the window's context current */
	glfwMakeContextCurrent(window);

	// Needed in core profile
	if( glewInit() != GLEW_OK)
	{
		glfwTerminate();
		return -1;
	}


	glClearColor(0.0f, 0.0f, 0.4f, 0.0f);

	// Enable depth test
	glEnable(GL_DEPTH_TEST);
	// Accept fragment if it closer to the camera than the former one
	glDepthFunc(GL_LESS); 

	glEnable(GL_CULL_FACE);

	GLuint VertexArrayID;
	glGenVertexArrays(1, &VertexArrayID);
	glBindVertexArray(VertexArrayID);

	// Our vertices. Tree consecutive floats give a 3D vertex; Three consecutive vertices give a triangle.
	// A cube has 6 faces with 2 triangles each, so this makes 6*2=12 triangles, and 12*3 vertices
	std::vector<glm::vec3> vertices;
	std::vector<glm::vec2> uvs;
	std::vector<glm::vec3> normals; // Won't be used at the moment.
	bool res = loadOBJ("./resource/suzanne.obj", vertices, uvs, normals);
	

	std::vector<unsigned short>indices;
	std::vector<glm::vec3> indexed_vertices;
	std::vector<glm::vec2> indexed_uvs;
	std::vector<glm::vec3> indexed_normals;
	indexVBO(vertices,uvs,normals,indices,indexed_vertices,indexed_uvs,indexed_normals);

	//This will identify our vertex buffer
	GLuint vertexbuffer;

	
	//Generate 1 buffer,put the resulting identifier in vertexbuffer
	glGenBuffers(1,&vertexbuffer);		

	//The following commands will talk about our 'vertexbuffer' buffer
	glBindBuffer(GL_ARRAY_BUFFER,vertexbuffer);

	//Give our vertices to OpenGL.
 	glBufferData(GL_ARRAY_BUFFER, indexed_vertices.size() * sizeof(glm::vec3), &indexed_vertices[0], GL_STATIC_DRAW);

	GLuint uvbuffer;
	glGenBuffers(1, &uvbuffer);
	glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
	glBufferData(GL_ARRAY_BUFFER, indexed_uvs.size() * sizeof(glm::vec2), &indexed_uvs[0], GL_STATIC_DRAW);

	GLuint normalbuffer;
	glGenBuffers(1, &normalbuffer);
	glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
	glBufferData(GL_ARRAY_BUFFER, indexed_normals.size() * sizeof(glm::vec3), &indexed_normals[0], GL_STATIC_DRAW);
	GLuint Texture = loadDDS("./resource/uvmap.DDS");//loadBMP_custom("./resource/uvtemplate.bmp");
	// One color for each vertex. They were generated randomly.	

	GLuint elementbuffer;
	glGenBuffers(1,&elementbuffer);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,elementbuffer);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER,indices.size() * sizeof(unsigned short),&indices[0],GL_STATIC_DRAW);


	GLuint programID = LoadShaders("./shader/vertex.shader","./shader/fragment.shader");
	
	glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
	/* Loop until the user closes the window */

	// Projection matrix : 45° Field of View, 4:3 ratio, display range : 0.1 unit  100 units
	//glm::mat4 Projection = glm::ortho(-4.0f/3.0f, 4.0f/3.0f, -1.0f, 1.0f, 0.1f, 100.0f);
	
	
		
	
		// Get a handle for our "MVP" uniform.
		// Only at initialisation time.
		GLuint MatrixID = glGetUniformLocation(programID,"MVP");		
		GLuint ViewMatrixID = glGetUniformLocation(programID, "V");
		GLuint ModelMatrixID = glGetUniformLocation(programID, "M");
		GLuint LightID = glGetUniformLocation(programID, "LightPosition_worldspace");
		// Send our transformation to the currently bound shader,
		// in the "MVP" uniform
		// For each model you render, since the MVP will be different (at least the M part)
		

		GLuint TextureID = glGetUniformLocation(programID,"myTextureSampler");
		int width,height;	
		glfwGetWindowSize(window,&width,&height);
		float centerX = width;
		float centerY = height;
		centerX /= 2;
		centerY /= 2;		
		//initMatrices();
		double lastTime = glfwGetTime();
		int nbFrames = 0;


	while (glfwGetKey(window, GLFW_KEY_ESCAPE ) != GLFW_PRESS && !glfwWindowShouldClose(window))
	{
		double currentTime = glfwGetTime();
		nbFrames++;
		if (currentTime - lastTime >= 1.0)
		{
			// printf and reset
			//printf("%f ms/frame\n", 1000.0/double(nbFrames));
			printf("fps %d ", nbFrames);
			nbFrames = 0;
			lastTime += 1.0;
		}

		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		glUseProgram(programID);
		computeMatricesFromInputs();
		glm::mat4 ProjectionMatrix = getProjectionMatrix();
		glm::mat4 ViewMatrix = getViewMatrix();
		glm::mat4 ModelMatrix = glm::mat4(1.0);
		glm::mat4 MVP = ProjectionMatrix * ViewMatrix * ModelMatrix;

		// Send our transformation to the currently bound shader, 
		// in the "MVP" uniform
		glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);
		glUniformMatrix4fv(ModelMatrixID, 1, GL_FALSE, &ModelMatrix[0][0]);
		glUniformMatrix4fv(ViewMatrixID, 1, GL_FALSE, &ViewMatrix[0][0]);

		glm::vec3 lightPos = glm::vec3(4,4,4);
		glUniform3f(LightID, lightPos.x, lightPos.y, lightPos.z);


		glActiveTexture(GL_TEXTURE0);
		glBindTexture(GL_TEXTURE_2D,Texture);
		glUniform1i(TextureID, 0);
		

		glEnableVertexAttribArray(0);
		glBindBuffer(GL_ARRAY_BUFFER,vertexbuffer);
		glVertexAttribPointer(
			0,			// attribute 0. No particular reason for 0, but must match the layout in the shader.
			3,			// size
			GL_FLOAT,	// type
			GL_FALSE,	// normalized?
			0,			// stride
			(void*)0	// array buffer offset
			);

		

		glEnableVertexAttribArray(1);
		glBindBuffer(GL_ARRAY_BUFFER,uvbuffer);	
		glVertexAttribPointer(
			1,			// attribute 0. No particular reason for 0, but must match the layout in the shader.
			2,			// size
			GL_FLOAT,	// type
			GL_FALSE,	// normalized?
			0,			// stride
			(void*)0	// array buffer offset
			);


		glEnableVertexAttribArray(2);
		glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
		glVertexAttribPointer(
			2,                                // attribute
			3,                                // size
			GL_FLOAT,                         // type
			GL_FALSE,                         // normalized?
			0,                                // stride
			(void*)0                          // array buffer offset
			);


		//glDrawArrays(GL_TRIANGLES, 0, vertices.size() );
		
			
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,elementbuffer);
		glDrawElements(GL_TRIANGLES,indices.size(),GL_UNSIGNED_SHORT,(void*)0);
		
		

		
		glDisableVertexAttribArray(0);
		glDisableVertexAttribArray(1);
		glDisableVertexAttribArray(2);
		/* Swap front and back buffers */
		glfwSwapBuffers(window);

		/* Poll for and process events */
		glfwPollEvents();
	}

	glfwTerminate();
	return 0;
}

#include "stdio.h"
#include "vboindexer.h"
#include <map>

struct PackedVertex{
	glm::vec3 position;
	glm::vec2 uv;
	glm::vec3 normal;
	bool operator<(const PackedVertex that) const{
		return memcmp((void*)this, (void*)&that, sizeof(PackedVertex))>0;
	};
};

bool getSimilarVertexIndex_fast(
	PackedVertex & packed,
	std::map<PackedVertex,unsigned short> &VertexToOutIndex,
	unsigned short & result
)
{
	std::map<PackedVertex,unsigned short>::iterator it = VertexToOutIndex.find(packed);
	if ( it == VertexToOutIndex.end() ){
		return false;
	}else{
		result = it->second;
		return true;
	}
}


void indexVBO(
	std::vector<glm::vec3> & in_vertices,
	std::vector<glm::vec2> & in_uvs,
	std::vector<glm::vec3> & in_normals,

	std::vector<unsigned short> & out_indices,
	std::vector<glm::vec3> & out_vertices,
	std::vector<glm::vec2> & out_uvs,
	std::vector<glm::vec3> & out_normals

	)
{

	std::map<PackedVertex,unsigned short> VertexToOutIndex;

	for (unsigned int i = 0; i< in_vertices.size();i++)
	{
		PackedVertex packed = {in_vertices[i],in_uvs[i],in_normals[i]};

		unsigned short index;
		bool found = getSimilarVertexIndex_fast(packed,VertexToOutIndex,index);

		if (found)
		{
			out_indices.push_back(index);
		}
		else
		{
			out_vertices.push_back(in_vertices[i]);
			out_uvs		.push_back(in_uvs[i]);
			out_normals .push_back(in_normals[i]);
			unsigned short newindex = (unsigned short)out_vertices.size() - 1;
			out_indices.push_back(newindex);
			VertexToOutIndex[packed] = newindex;
		}
	}
	
}


<think> 嗯,用户需要详细了解OpenGL中的VBO(顶点缓冲对象)及其使用方法。用户提供了三篇站内引用资料,这些资料解释了VBO的基本概念、使用流程以及与其他组件的关系。 根据引用内容,我需要重点解释VBO的核心作用:它是存储顶点数据的缓冲区对象,用于解决CPU向GPU重复传输数据导致的性能瓶颈。引用中还提到了VBO与VAO(顶点数组对象)、EBO(索引缓冲对象)的协同关系。 准备详细介绍VBO的使用流程: 第一步是创建VBO对象,使用glGenBuffers函数生成缓冲区ID 第二步绑定对象,通过glBindBuffer将VBO绑定到GL_ARRAY_BUFFER目标 第三步传输数据,用glBufferData将顶点数据从内存复制到显存 还要强调VBO的使用注意事项: 数据使用模式的选择(静态/动态/流式) 绑定状态的管理,特别是多VBO切换时的正确绑定顺序 与VAO的配合使用,VAO能保存顶点属性指针配置 考虑设计代码示例来展示完整流程: 定义三角形顶点数据数组 演示VBO创建、绑定、数据传输的代码链条 最后展示解绑和清理操作 准备补充相关知识延伸: 说明VBO在现代渲染管线中的位置 解释为什么能提升性能(减少数据传输开销) 关联顶点属性指针(glVertexAttribPointer)的配置方法 根据用户提供的参考资料特点,会特别突出两点: 1. VBO与VAO的协作关系(引用[1]和[3]强调这点) 2. 数据传输后CPU端数据可释放的特性(引用[3]提及) 计划在回答末尾设计三个进阶问题: 优化方向(实例化渲染/缓冲区映射) 常见错误排查(绑定状态问题) 与其他缓冲对象的对比(如EBO) 需要确保所有OpenGL函数名和常量名用代码块标记,数学公式用LaTeX规范呈现。回答将保持技术准确性,同时避免直接复制引用段落原文,通过整合多源信息形成系统讲解。 </think> 以下是关于OpenGL VBO(顶点缓冲对象)的详细介绍及使用方法的系统解析,结合站内引用内容整理: ### 一、VBO核心原理 1. **作用本质** VBO用于在GPU显存中存储顶点数据(位置、颜色、法线等),解决CPU到GPU重复传输数据的性能瓶颈。与传统即时模式(`glBegin/glEnd`)相比,**数据传输效率提升10倍以上**(实测数据)[^3]。 2. **性能优势** - 单次批量传输替代逐顶点传输 - 数据常驻显存减少CPU-GPU通信 - 支持**DMA(直接内存访问)** 加速数据传输[^1] --- ### 二、VBO使用流程(四步法) ```cpp // 1. 创建VBO对象 GLuint VBO; glGenBuffers(1, &VBO); // 参数1: 生成数量, 参数2: 返回ID[^2] // 2. 绑定缓冲类型 glBindBuffer(GL_ARRAY_BUFFER, VBO); // 目标类型必须是GL_ARRAY_BUFFER[^3] // 3. 复制顶点数据到显存 float vertices[] = {...}; // 顶点数据数组 glBufferData( GL_ARRAY_BUFFER, // 目标缓冲类型 sizeof(vertices), // 数据字节大小 vertices, // 源数据指针 GL_STATIC_DRAW // 数据使用模式 ); // 4. 配置顶点属性指针 glVertexAttribPointer( 0, // 顶点属性位置索引(对应shader中的layout location) 3, // 属性分量数(如vec3则为3) GL_FLOAT, // 数据类型 GL_FALSE, // 是否标准化 3 * sizeof(float), // 步长(连续顶点间的字节偏移) (void*)0 // 起始偏移量 ); glEnableVertexAttribArray(0); // 启用属性通道[^2] ``` > **关键参数说明**: > - `GL_STATIC_DRAW`:数据不会或很少改变(最佳性能) > - `GL_DYNAMIC_DRAW`:数据可能频繁更新 > - 步长计算公式:$\text{stride} = \text{属性分量数} \times \text{sizeof(数据类型)}$ --- ### 三、VBO与其他组件关系 1. **VAO(顶点数组对象)** VAO封装VBO配置状态,避免每次渲染重复绑定: ```cpp GLuint VAO; glGenVertexArrays(1, &VAO); glBindVertexArray(VAO); // 激活VAO // 此时配置的VBO和属性指针会被记录 glBindVertexArray(0); // 解绑 ``` 2. **EBO(索引缓冲对象)** 与VBO协同实现顶点复用: ```cpp GLuint EBO; glGenBuffers(1, &EBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); // 绘制时改用glDrawElements ``` --- ### 四、进阶技术方向 1. **实例化渲染(Instancing)** 通过`glDrawArraysInstanced`单次绘制多个相同对象,结合`glVertexAttribDivisor`控制属性更新频率[^1]。 2. **缓冲区映射(Mapping)** 直接映射显存地址提升动态数据更新效率: ```cpp void* ptr = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); memcpy(ptr, newData, dataSize); glUnmapBuffer(GL_ARRAY_BUFFER); ``` --- ### 五、最佳实践建议 - **数据布局优化**:使用交错存储(Interleaved)提升缓存命中率 ```cpp struct Vertex { vec3 pos; vec2 tex; vec3 normal; }; ``` - **内存管理**:数据上传后及时释放CPU端内存 - **错误排查**:`glGetError()`检查绑定状态一致性
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值