最新大型开源项目-云游戏,云桌面系统,欢迎关注
本项目代码仓库
1.顶点坐标的一点问题
之前我们定义的顶点坐标,都是在OpenGL的默认坐标系下从[-1, 1]的区间内,但是如果我们想要精确且方便的控制一个物体的坐标,比如(100,200),(50,100)等,将变得麻烦一些,因为要进行转化,转化到[-1,1]之间。
如果我们绘制的物体是在2D平面内的,我们可以用正交投影来解决这个问题。
2.正交投影
-
2.1 什么是正交投影 简单来讲,正交投影就是定义了一个空间,在这个空间内的物体都会被显示,其之外的,将被裁剪掉。如下图所示:
我们可以看到这个空间之内的场景。 但是看到的场景是没有3D信息的,Z轴会被挤压到XY平面上,丢失Z轴信息,就像从前面看到的正视图一样 :
这个画面就与一般的2D游戏非常相似了。 -
2.2 定义要投影的坐标系 我们的目的是要简单的定义物体的坐标,比如按照屏幕分辨率来定义。 定义成下图这样,将非常简单,符合我们经常使用的习惯:
此时我们所有的坐标,便可以从左下角为原点的坐标系中定义。
- 2.3 在C++中定义一个投影矩阵
float window_width = 800;
float window_height = 800;
glm::mat4 projection = glm::ortho(0.0f, window_width, 0.0f, window_height, 0.0f, 1.0f);
3.更改坐标并绘制
- 3.1 修改顶点坐标,适应上图紫色的坐标系
float image_width = 200;
float image_height = 200;
float vertices[] = {
0, 0, 0, 1.0, 0.0, 0.0, 0.0f, 0.0f,
image_width, 0, 0, 0.0, 1.0, 0.0, 1.0f, 0.0f,
image_width, image_height, 0, 0.0, 0.0, 1.0, 1.0f, 1.0f,
0, image_height, 0, 0.9, 0.6, 0.8, 0.0f, 1.0f
};
在上面的修改中可以看到,左下角的坐标为(0,0),右上角的坐标为(image_width, image_height)即(200,200).
- 3.2 因为添加了一个正交投影,所以要修改一下顶点着色器。这是因为需要将每个顶点都做投影。
只需要添加一个
uniform mat4 projection;
,并将它左乘在model上即可。
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aTex;
uniform mat4 projection;
uniform mat4 model;
out vec3 outColor;
out vec2 outTex;
void main()
{
gl_Position = projection * model * vec4(aPos, 1.0);
outColor = aColor;
outTex = aTex;
}
- 3.3 绘制之前设置projection的值
shader->SetUniformMatrix("projection", projection);
如此,便能按我们的坐标绘制出来:
- 3.4 由于坐标系带来的便利,我们可以轻松的按照位置摆放图片。首先将绘制部分更改如下: 循环绘制四组图片,并稍微改变了两张图的混合比例。
float translate_step = 200;
for (int i = 0; i < 4; i++) {
auto rotate = (float)glm::radians(glfwGetTime()) * 10;
glm::mat4 model(1.0);
model = glm::translate(model, glm::vec3(i*translate_step, i*translate_step, 0));
//model = glm::rotate(model, rotate, glm::vec3(0, 0, 1));
glBindVertexArray(VAO);
shader->Use();
shader->SetUniformMatrix("projection", projection);
shader->SetUniformMatrix("model", model);
float red_value = (float)glm::sin(glfwGetTime());
glm::vec3 color(red_value, red_value/2, red_value/2);
shader->SetUniform3fv("color", color);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
shader->SetUniform1i("image", 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture_logo);
shader->SetUniform1i("image2", 1);
float mix_factor = (i+1) * 0.2;
shader->SetUniform1f("mix_factor", mix_factor);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
}
结果如下: 如此,引入正交投影后,绘制2D物体,便增加了一些便利性。