OpenGL学习笔记9——坐标系统

OpenGL学习笔记9——坐标系统

  • 1 简单概念
  • 2 代码
    • 2.1 简单的应用
    • 2.2 显示立方体
    • 2.3 深度测试
    • 2.4 更多立方体

1 简单概念

现在就引入了坐标系统的概念。先前我们算是直接在裁剪空间上绘制物体(裁剪空间到屏幕空间的转换OpenGL自动帮我们处理)。

  • 局部空间(Local Space,或者称为物体空间(Object Space))
  • 世界空间(World Space)
  • 观察空间(View Space,或者称为视觉空间(Eye Space))
  • 裁剪空间(Clip Space)
  • 屏幕空间(Screen Space)

LearnOpenGL的图
OpenGL学习笔记9——坐标系统_第1张图片
其中比较有意思的就是在裁剪空间中,会存在一个叫作透视除法的东西。

透视除法(Perspective Division)将会执行,在这个过程中我们将位置向量的x,y,z分量分别除以向量的齐次w分量;透视除法是将4D裁剪空间坐标变换为3D标准化设备坐标的过程。这一步会在每一个顶点着色器运行的最后被自动执行。

碰巧看到了Sebastian Lague大神制作传送门的视频。其中4:35-5:50这一段很形象的展示了w分量的作用,以及从观察空间到裁剪空间的效果。视频:Youtube、BiliBili

为上述的每一个步骤创建了一个变换矩阵:模型矩阵、观察矩阵和投影矩阵。一个顶点坐标将会根据以下过程被变换到裁剪坐标:

Vclip = Mprojection ⋅ Mview ⋅ Mmodel ⋅ Vlocal

注意矩阵运算的顺序是相反的(记住我们需要从右往左阅读矩阵的乘法)。最后的顶点应该被赋值到顶点着色器中的gl_Position,OpenGL将会自动进行透视除法和裁剪

2 代码

2.1 简单的应用

我们需要在顶点着色器中传出裁剪空间的坐标。根据公式我们还需要三个矩阵,如下。

	glm::mat4 model; // 模型矩阵
	model = glm::rotate(model, glm::radians(-55.0f), glm::vec3(1.0f, 0.0f, 0.0f)); // 在x上旋转-55度
	glm::mat4 view; // 观察矩阵
	view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f)); // 摄像机在(0,0,3),即物体相反移动 为移动(0,0,-3)
	glm::mat4 projection; // 投影矩阵
	projection = glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f); // Fov是45度,屏幕的宽高比是800/600,近的裁剪面距离是0.1,远面距离100

然后在顶点着色器里面写一下uniform,乘起来(注意顺序)。

#version 330 core

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

layout(location = 0) in vec3 aPos;
layout(location = 1) in vec3 aColor;
layout(location = 2) in vec2 aTexCoord;

out vec3 Color;
out vec2 TexCoord;

void main() {
  gl_Position = projection * view * model * vec4(aPos, 1.0);
  Color = aColor;
  TexCoord = aTexCoord;
}

在渲染循环中传入三个矩阵就完成了(用的我之前封装的Shader类的函数)。

		/*Uniform*/
		myShader.setMat4("model", model);
		myShader.setMat4("view", view);
		myShader.setMat4("projection", projection);

OpenGL学习笔记9——坐标系统_第2张图片

2.2 显示立方体

教程给了个立方体的36个顶点(吐槽:怎么突然就不用EBO了,本来就8个顶点完事)。改成要用
glDrawArrays的方式,就要改很多地方了。首先EBO都没用了,删掉。然后glDrawElements改成Arrays。顶点数据换一下。运行???
OpenGL学习笔记9——坐标系统_第3张图片
这是什么鬼畜情况。

仔细想了想原来是新的顶点数据里面少了颜色的数据,VAO的设置也要改。(原教程就给个顶点,其他啥都不说,(。・∀・)ノ゙害)
OpenGL学习笔记9——坐标系统_第4张图片
好了,可以“正常”显示了。现在就是不能正确的判断哪些像素在前哪些在后。

	// 顶点数据
	float vertices[] = {
	-0.5f, -0.5f, -0.5f,  0.0f, 0.0f,
	 0.5f, -0.5f, -0.5f,  1.0f, 0.0f,
	 0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
	 0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
	-0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
	-0.5f, -0.5f, -0.5f,  0.0f, 0.0f,

	-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
	 0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
	 0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
	 0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
	-0.5f,  0.5f,  0.5f,  0.0f, 1.0f,
	-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,

	-0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
	-0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
	-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
	-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
	-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
	-0.5f,  0.5f,  0.5f,  1.0f, 0.0f,

	 0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
	 0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
	 0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
	 0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
	 0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
	 0.5f,  0.5f,  0.5f,  1.0f, 0.0f,

	-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
	 0.5f, -0.5f, -0.5f,  1.0f, 1.0f,
	 0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
	 0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
	-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
	-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,

	-0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
	 0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
	 0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
	 0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
	-0.5f,  0.5f,  0.5f,  0.0f, 0.0f,
	-0.5f,  0.5f, -0.5f,  0.0f, 1.0f
	};

2.3 深度测试

解决刚才的问题就需要用到深度测试,在同一个位置的像素通过比较z缓存上的数值就可以知道哪个在前哪个在后,从而舍弃掉不会显示的像素。
在渲染循环前开启即可。

	glEnable(GL_DEPTH_TEST);

然后我们还要清除色彩和深度缓存,要在渲染循环中交换颜色缓存后清空。我之前放在交换颜色缓冲前清空画面就会变黑。 重新更正一下,其实之前变黑不是在交换颜色缓前清空的原因。是因为我在绘制之后清空了((。・∀・)ノ゙害)。所以应该是在绘制之前清空,清空颜色缓存之前写过了,现在加上一个清空深度缓冲就可以了。
至此看到这个位运算符我终于明白,原来他是用二进制位来表示的意思。

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

然后可以让他不停旋转。

model = glm::rotate(model, 0.002f * glm::radians(50.0f), glm::vec3(0.5f, 1.0f, 0.0f));

OpenGL学习笔记9——坐标系统_第5张图片
终于进入3D世界了。
源码:github

2.4 更多立方体

定义十个位置的向量。

	glm::vec3 cubePositions[] = {
		glm::vec3(0.0f,  0.0f,  0.0f),
		glm::vec3(2.0f,  5.0f, -15.0f),
		glm::vec3(-1.5f, -2.2f, -2.5f),
		glm::vec3(-3.8f, -2.0f, -12.3f),
		glm::vec3(2.4f, -0.4f, -3.5f),
		glm::vec3(-1.7f,  3.0f, -7.5f),
		glm::vec3(1.3f, -2.0f, -2.5f),
		glm::vec3(1.5f,  2.0f, -2.5f),
		glm::vec3(1.5f,  0.2f, -1.5f),
		glm::vec3(-1.3f,  1.0f, -1.5f)
	};

在渲染循环中改成渲染十次。

		glBindVertexArray(VAO);
		myShader.use();

		for (unsigned int i = 0; i < 10; i++)
		{
			glm::mat4 model;
			model = glm::translate(model, cubePositions[i]);
			float angle = 20.0f * i;
			model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));
			myShader.setMat4("model", model);

			glDrawArrays(GL_TRIANGLES, 0, 36);
		}

OpenGL学习笔记9——坐标系统_第6张图片

你可能感兴趣的:(#,OpenGL)