OpenGL入门学习笔记(一)——OpenGL使用glMapBuffer或glBufferSubData动态修改EBO

最近在尝试使用OpenGL实现四叉树LOD,一个思路是动态修改Buffer的数据以实现动态绘制。
查找到可以用glMapBuffer或者glBufferSubData来修改数据,在此对使用方式做个记录。

1、使用glMapBuffer
glMapBuffer是获取Buffer的指针地址,注意,在通过指针修改Buffer后需要调用glUnmapBuffer进行提交。

const int N = 128 + 1;
const int layerNum = std::log2(N - 1);

int dynamicDraw();

int dynamicDraw()
{
	auto window = initWindow();

	Ogle::Shader* drawShader = new Ogle::Shader("./01_DynamicDraw.vert", "./01_DynamicDraw.frag");

	float* vertices = new float[N * N * 3];
	float sX = -N / 2.0;
	float sZ = N / 2.0;
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < N; j++)
		{
			vertices[i * N * 3 + j * 3] = sX;
			vertices[i * N * 3 + j * 3 + 1] = 0.0;
			vertices[i * N * 3 + j * 3 + 2] = sZ;

			sX += 1.0;
		}
		sX = -N / 2.0;
		sZ -= 1.0;
	}

	int layerGrid[8] = { 1,2,4,8,16,32,64,128 };

	//1×1
	int divide = (N - 1) / layerGrid[0];
	unsigned int* layer_1 = new unsigned int[layerGrid[0] * layerGrid[0] * 6];
	for (int i = 0; i < layerGrid[0]; i++)
	{
		for (int j = 0; j < layerGrid[0]; j++)
		{
			layer_1[i * layerGrid[0] * 6 + j * 6] = i * divide * N + j * divide;
			layer_1[i * layerGrid[0] * 6 + j * 6 + 1] = divide + i * divide * N + j * divide;
			layer_1[i * layerGrid[0] * 6 + j * 6 + 2] = divide * N + i * divide * N + j * divide;
			layer_1[i * layerGrid[0] * 6 + j * 6 + 3] = divide + i * divide * N + j * divide;
			layer_1[i * layerGrid[0] * 6 + j * 6 + 4] = divide * N + i * divide * N + j * divide;
			layer_1[i * layerGrid[0] * 6 + j * 6 + 5] = divide * (N + 1) + i * divide * N + j * divide;
		}
	}

	//2×2
	divide = (N - 1) / layerGrid[1];
	unsigned int* layer_2 = new unsigned int[layerGrid[1] * layerGrid[1] * 6];
	for (int i = 0; i < layerGrid[1]; i++)
	{
		for (int j = 0; j < layerGrid[1]; j++)
		{
			layer_2[i * layerGrid[1] * 6 + j * 6] = i * divide * N + j * divide;
			layer_2[i * layerGrid[1] * 6 + j * 6 + 1] = divide + i * divide * N + j * divide;
			layer_2[i * layerGrid[1] * 6 + j * 6 + 2] = divide * N + i * divide * N + j * divide;
			layer_2[i * layerGrid[1] * 6 + j * 6 + 3] = divide + i * divide * N + j * divide;
			layer_2[i * layerGrid[1] * 6 + j * 6 + 4] = divide * N + i * divide * N + j * divide;
			layer_2[i * layerGrid[1] * 6 + j * 6 + 5] = divide * (N + 1) + i * divide * N + j * divide;
		}
	}

	//4×4
	divide = (N - 1) / layerGrid[2];
	unsigned int* layer_3 = new unsigned int[layerGrid[2] * layerGrid[2] * 6];
	for (int i = 0; i < layerGrid[2]; i++)
	{
		for (int j = 0; j < layerGrid[2]; j++)
		{
			layer_3[i * layerGrid[2] * 6 + j * 6] = i * divide * N + j * divide;
			layer_3[i * layerGrid[2] * 6 + j * 6 + 1] = divide + i * divide * N + j * divide;
			layer_3[i * layerGrid[2] * 6 + j * 6 + 2] = divide * N + i * divide * N + j * divide;
			layer_3[i * layerGrid[2] * 6 + j * 6 + 3] = divide + i * divide * N + j * divide;
			layer_3[i * layerGrid[2] * 6 + j * 6 + 4] = divide * N + i * divide * N + j * divide;
			layer_3[i * layerGrid[2] * 6 + j * 6 + 5] = divide * (N + 1) + i * divide * N + j * divide;
		}
	}

	//8×8
	divide = (N - 1) / layerGrid[3];
	unsigned int* layer_4 = new unsigned int[layerGrid[3] * layerGrid[3] * 6];
	for (int i = 0; i < layerGrid[3]; i++)
	{
		for (int j = 0; j < layerGrid[3]; j++)
		{
			layer_4[i * layerGrid[3] * 6 + j * 6] = i * divide * N + j * divide;
			layer_4[i * layerGrid[3] * 6 + j * 6 + 1] = divide + i * divide * N + j * divide;
			layer_4[i * layerGrid[3] * 6 + j * 6 + 2] = divide * N + i * divide * N + j * divide;
			layer_4[i * layerGrid[3] * 6 + j * 6 + 3] = divide + i * divide * N + j * divide;
			layer_4[i * layerGrid[3] * 6 + j * 6 + 4] = divide * N + i * divide * N + j * divide;
			layer_4[i * layerGrid[3] * 6 + j * 6 + 5] = divide * (N + 1) + i * divide * N + j * divide;
		}
	}

	//16×16
	divide = (N - 1) / layerGrid[4];
	unsigned int* layer_5 = new unsigned int[layerGrid[4] * layerGrid[4] * 6];
	for (int i = 0; i < layerGrid[4]; i++)
	{
		for (int j = 0; j < layerGrid[4]; j++)
		{
			layer_5[i * layerGrid[4] * 6 + j * 6] = i * divide * N + j * divide;
			layer_5[i * layerGrid[4] * 6 + j * 6 + 1] = divide + i * divide * N + j * divide;
			layer_5[i * layerGrid[4] * 6 + j * 6 + 2] = divide * N + i * divide * N + j * divide;
			layer_5[i * layerGrid[4] * 6 + j * 6 + 3] = divide + i * divide * N + j * divide;
			layer_5[i * layerGrid[4] * 6 + j * 6 + 4] = divide * N + i * divide * N + j * divide;
			layer_5[i * layerGrid[4] * 6 + j * 6 + 5] = divide * (N + 1) + i * divide * N + j * divide;
		}
	}

	//32×32
	divide = (N - 1) / layerGrid[5];
	unsigned int* layer_6 = new unsigned int[layerGrid[5] * layerGrid[5] * 6];
	for (int i = 0; i < layerGrid[5]; i++)
	{
		for (int j = 0; j < layerGrid[5]; j++)
		{
			layer_6[i * layerGrid[5] * 6 + j * 6] = i * divide * N + j * divide;
			layer_6[i * layerGrid[5] * 6 + j * 6 + 1] = divide + i * divide * N + j * divide;
			layer_6[i * layerGrid[5] * 6 + j * 6 + 2] = divide * N + i * divide * N + j * divide;
			layer_6[i * layerGrid[5] * 6 + j * 6 + 3] = divide + i * divide * N + j * divide;
			layer_6[i * layerGrid[5] * 6 + j * 6 + 4] = divide * N + i * divide * N + j * divide;
			layer_6[i * layerGrid[5] * 6 + j * 6 + 5] = divide * (N + 1) + i * divide * N + j * divide;
		}
	}

	//64×64
	divide = (N - 1) / layerGrid[6];
	unsigned int* layer_7 = new unsigned int[layerGrid[6] * layerGrid[6] * 6];
	for (int i = 0; i < layerGrid[6]; i++)
	{
		for (int j = 0; j < layerGrid[6]; j++)
		{
			layer_7[i * layerGrid[6] * 6 + j * 6] = i * divide * N + j * divide;
			layer_7[i * layerGrid[6] * 6 + j * 6 + 1] = divide + i * divide * N + j * divide;
			layer_7[i * layerGrid[6] * 6 + j * 6 + 2] = divide * N + i * divide * N + j * divide;
			layer_7[i * layerGrid[6] * 6 + j * 6 + 3] = divide + i * divide * N + j * divide;
			layer_7[i * layerGrid[6] * 6 + j * 6 + 4] = divide * N + i * divide * N + j * divide;
			layer_7[i * layerGrid[6] * 6 + j * 6 + 5] = divide * (N + 1) + i * divide * N + j * divide;
		}
	}

	//128×128
	divide = (N - 1) / layerGrid[7];
	unsigned int* layer_8 = new unsigned int[layerGrid[7] * layerGrid[7] * 6];
	for (int i = 0; i < layerGrid[7]; i++)
	{
		for (int j = 0; j < layerGrid[7]; j++)
		{
			layer_8[i * layerGrid[7] * 6 + j * 6] = i * divide * N + j * divide;
			layer_8[i * layerGrid[7] * 6 + j * 6 + 1] = divide + i * divide * N + j * divide;
			layer_8[i * layerGrid[7] * 6 + j * 6 + 2] = divide * N + i * divide * N + j * divide;
			layer_8[i * layerGrid[7] * 6 + j * 6 + 3] = divide + i * divide * N + j * divide;
			layer_8[i * layerGrid[7] * 6 + j * 6 + 4] = divide * N + i * divide * N + j * divide;
			layer_8[i * layerGrid[7] * 6 + j * 6 + 5] = divide * (N + 1) + i * divide * N + j * divide;
		}
	}

	unsigned int VAO;
	glGenVertexArrays(1, &VAO);
	glBindVertexArray(VAO);
	int i = sizeof(&vertices);
	unsigned int VBO;
	glGenBuffers(1, &VBO);
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glBufferData(GL_ARRAY_BUFFER, N * N * 3 * 4, vertices, GL_STATIC_DRAW);

	unsigned int EBO;
	glGenBuffers(1, &EBO);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, (N - 1) * (N - 1) * 6 * 4, layer_8, GL_STATIC_DRAW);

	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(0);

	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glBindVertexArray(0);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

	glEnable(GL_DEPTH_TEST);

	while (!glfwWindowShouldClose(window))
	{
		float currentFrame = static_cast<float>(glfwGetTime());
		deltaTime = currentFrame - lastFrame;
		lastFrame = currentFrame;

		processInput(window);

		glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//同时清楚深度缓冲区

		glUseProgram(drawShader->id);

		glm::mat4 model = glm::mat4(1.0);
		glm::mat4 view = glm::mat4(1.0);
		glm::mat4 projection = glm::mat4(1.0);
		view = camera.GetViewMatrix();
		projection = glm::perspective(glm::radians(camera.Zoom), 800.0f / 600.0f, 0.1f, 100.0f);
		glUniformMatrix4fv(glGetUniformLocation(drawShader->id, "model"), 1, GL_FALSE, glm::value_ptr(model));
		glUniformMatrix4fv(glGetUniformLocation(drawShader->id, "view"), 1, GL_FALSE, glm::value_ptr(view));
		glUniformMatrix4fv(glGetUniformLocation(drawShader->id, "projection"), 1, GL_FALSE, glm::value_ptr(projection));

		glBindVertexArray(VAO);

		int mN = 0;
		if (camera.Position.y < 2)
		{
			auto p = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
			memcpy(p, layer_8, 128 * 128 * 6 * 4);
			bool update = glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
			mN = 128;
		}
		else if (camera.Position.y >= 2 && camera.Position.y < 4)
		{
			auto p = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
			memcpy(p, layer_7, 64 * 64 * 6 * 4);
			bool update = glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
			mN = 64;
		}
		else if (camera.Position.y >= 4 && camera.Position.y < 6)
		{
			auto p = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
			memcpy(p, layer_6, 32 * 32 * 6 * 4);
			bool update = glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
			mN = 32;
		}
		else if (camera.Position.y >= 6 && camera.Position.y < 8)
		{
			auto p = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
			memcpy(p, layer_5, 16 * 16 * 6 * 4);
			bool update = glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
			mN = 16;
		}
		else if (camera.Position.y >= 8 && camera.Position.y < 10)
		{
			auto p = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
			memcpy(p, layer_4, 8 * 8 * 6 * 4);
			bool update = glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
			mN = 8;
		}
		else if (camera.Position.y >= 10 && camera.Position.y < 12)
		{
			auto p = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
			memcpy(p, layer_3, 4 * 4 * 6 * 4);
			bool update = glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
			mN = 4;
		}
		else if (camera.Position.y >= 12 && camera.Position.y < 14)
		{
			auto p = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
			memcpy(p, layer_2, 2 * 2 * 6 * 4);
			bool update = glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
			mN = 2;
		}
		else if (camera.Position.y >= 14 && camera.Position.y < 16)
		{
			auto p = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
			memcpy(p, layer_1, 1 * 1 * 6 * 4);
			bool update = glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
			mN = 1;
		}

		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
		glDrawElements(GL_TRIANGLES, mN * mN * 6, GL_UNSIGNED_INT, (void*)0);

		glfwSwapBuffers(window);
		glfwPollEvents();
	}

	glDeleteVertexArrays(1, &VAO);
	glDeleteBuffers(1, &VBO);
	glDeleteBuffers(1, &EBO);
	glDeleteProgram(drawShader->id);

	glfwTerminate();
	return 0;
}

2、使用glBufferSubData
将上面代码如下面一一做修改。

		else if (camera.Position.y >= 2 && camera.Position.y < 4)
		{
			/*auto p = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
			memcpy(p, layer_7, 64 * 64 * 6 * 4);
			bool update = glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);*/
			glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, 64 * 64 * 6 * 4, layer_7);
			mN = 64;
		}

注意:修改的内容量不可超过Buffer初始化时的大小(初始化时的大小由glBufferData的设置决定),也就是说不可在设置的最大大小的基础上增加数据。

运行效果:
随着视角拉远,网格逐渐减少。

在这里插入图片描述

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值