【C++ OpenGL入门-8】引入正交投影

27 阅读3分钟

最新大型开源项目-云游戏,云桌面系统,欢迎关注

GammaRay源码地址

本项目代码仓库

点击这里

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物体,便增加了一些便利性。