宝塔山 发表于 2024-9-22 06:20:25

OpenGL笔记十七之正交投影变更实行-glm::ortho函数

OpenGL笔记十七之正交投影变更实行-glm::ortho函数


—— 2024-07-30 晚上
bilibili赵新政老师的教程看后笔记
code review!


1.glm::ortho函数

glm::ortho 函数是 OpenGL 数学库 GLM (OpenGL Mathematics) 中用于天生正交投影矩阵的函数。正交投影矩阵在渲染2D场景或需要保持对象真实尺寸的3D场景时非常有用。glm::ortho 函数的定义如下:
glm::mat4 glm::ortho(
    float left,
    float right,
    float bottom,
    float top,
    float zNear,
    float zFar
);
参数详解


[*]left: 视锥体的左边界。
[*]right: 视锥体的右边界。
[*]bottom: 视锥体的下边界。
[*]top: 视锥体的上边界。
[*]zNear: 视锥体的近剪裁面。
[*]zFar: 视锥体的远剪裁面。
返回值

glm::ortho 返回一个 glm::mat4 类型的 4x4 正交投影矩阵。
工作原理

正交投影矩阵用于将3D坐标转换为2D屏幕坐标,它不会像透视投影矩阵那样产生间隔缩放效果。正交投影矩阵的天生通过以下步骤实现:

[*] 缩放变更:

[*]将对象的坐标从视锥体的范围 映射到标准扮装备坐标的范围 [-1, 1]。
[*]同理,将对象的坐标从 和 映射到 [-1, 1]。

[*] 平移变更:

[*]将对象的中央移到原点。

正交投影矩阵公式

正交投影矩阵的公式如下:
https://i-blog.csdnimg.cn/direct/1e6203758bea4c8aafb184b48c7bc99c.png
示例代码

以下是一个现实使用 glm::ortho 函数的示例:
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <iostream>

int main() {
    float left = -1.0f;
    float right = 1.0f;
    float bottom = -1.0f;
    float top = 1.0f;
    float zNear = 0.1f;
    float zFar = 100.0f;

    glm::mat4 orthoMatrix = glm::ortho(left, right, bottom, top, zNear, zFar);

    // 打印正交投影矩阵
    for (int i = 0; i < 4; ++i) {
      for (int j = 0; j < 4; ++j) {
            std::cout << orthoMatrix << " ";
      }
      std::cout << std::endl;
    }

    return 0;
}
输出结果

运行上述代码将天生并打印正交投影矩阵,输出如下:
1 0 0 0
0 1 0 0
0 0 -0.0200202 -1.002
0 0 0 1
解释



[*]第一行和第二行: 映射 x 和 y 坐标范围从 [-1, 1] 到 [-1, 1],由于 left = -1, right = 1, bottom = -1, top = 1。
[*]第三行: 映射 z 坐标范围从 0.1 到 100 到 -1 到 1。
[*]第四行: 齐次坐标。
通过明确 glm::ortho 函数的原理和使用方法,可以方便地在 OpenGL 程序中实现正交投影,从而渲染出符合预期的2D或3D场景。
2.实行一:使用glm的ortho函数

NDC坐标
viewMatrix = glm::lookAt(glm::vec3(0.0f,0.0f,1.0f),glm::vec3(0.0f,0.0f,0.0f),glm::vec3(0.0f,1.0f,0.0f));

orthoMatrix = glm::ortho(-2.0f, 2.0f, -2.0f, 2.0f, 2.0f, -2.0f);

float positions[] = {
        -0.5f, -0.5f, 0.0f,
        0.5f, -0.5f, 0.0f,
        0.0f,0.5f, 0.0f,
};
运行
https://i-blog.csdnimg.cn/direct/10dafa43ddde489fa2b317d698736189.png
2.实行二:使用非NDC数据

https://i-blog.csdnimg.cn/direct/4f24c3153e0a4c0a9e547412897d0af4.png
viewMatrix = glm::lookAt(glm::vec3(0.0f,0.0f,1.0f),glm::vec3(0.0f,0.0f,0.0f),glm::vec3(0.0f,1.0f,0.0f));

orthoMatrix = glm::ortho(-2.0f, 2.0f, -2.0f, 2.0f, 2.0f, -2.0f);

float positions[] = {
        -1.0f, 0.0f, 0.0f,
        1.0f, 0.0f, 0.0f,
        0.0f,1.0f, 0.0f,
};
运行
https://i-blog.csdnimg.cn/direct/2c245bbcdae0417a8f103e849f5cd020.png
3.实行三:将顶点向世界坐标系的-z方向推进较大范围(-5)(剪裁)

float positions[] = {
        -1.0f, 0.0f, -5.0f,
        1.0f, 0.0f, -5.0f,
        0.0f,1.0f, -5.0f,
};
运行
https://i-blog.csdnimg.cn/direct/f11a6fdc55b64aa3a1d9d6dc4c5b7b10.png
4.实行四:将可视范围盒子向相机坐标系的+x方向推进1个单元

orthoMatrix = glm::ortho(-1.0f, 3.0f, -2.0f, 2.0f, 2.0f, -2.0f);float positions[] = {
        -1.0f, 0.0f, -5.0f,
        1.0f, 0.0f, -5.0f,
        0.0f,1.0f, -5.0f,
};
运行
https://i-blog.csdnimg.cn/direct/5fff5b64d74a463ca6b0955c85019dbd.png
5.实行五:保持可视范围盒子不动,动相机(1.0,0.0,0.1)

viewMatrix = glm::lookAt(glm::vec3(1.0f,0.0f,0.1f),glm::vec3(0.0f,0.0f,0.0f),glm::vec3(0.0f,1.0f,0.0f));

orthoMatrix = glm::ortho(-2.0f, 2.0f, -2.0f, 2.0f, 2.0f, -2.0f);

float positions[] = {
        -1.0f, 0.0f, 0.0f,
        1.0f, 0.0f, 0.0f,
        0.0f,1.0f, 0.0f,
};
运行
https://i-blog.csdnimg.cn/direct/5cbd021576e14585a80bfee4e2dd949a.png
5.实行六:保持可视范围盒子不动,动相机(1.0,0.0,1.0-剪裁)

viewMatrix = glm::lookAt(glm::vec3(1.0f,0.0f,1.0f),glm::vec3(0.0f,0.0f,0.0f),glm::vec3(0.0f,1.0f,0.0f));

orthoMatrix = glm::ortho(-2.0f, 2.0f, -2.0f, 2.0f, 2.0f, -2.0f);

float positions[] = {
        -1.0f, 0.0f, 0.0f,
        1.0f, 0.0f, 0.0f,
        0.0f,1.0f, 0.0f,
};
运行
https://i-blog.csdnimg.cn/direct/67c0940034a54deabd3468bd5c29f406.png
6.vs

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aUV;

out vec3 color;
out vec2 uv;

uniform mat4 transform;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;

//aPos作为attribute(属性)传入shader
//不允许更改的
void main()
{
        vec4 position = vec4(aPos, 1.0);
        position = projectionMatrix * viewMatrix * transform * position;
        gl_Position = position;
        color = aColor;
        uv = aUV;
}
7.fs

#version 330 core
out vec4 FragColor;

in vec3 color;
in vec2 uv;

uniform sampler2D sampler;

void main()
{
FragColor = texture(sampler, uv);
}
8.main.cpp

#include <iostream>

#include "glframework/core.h"
#include "glframework/shader.h"
#include <string>
#include <assert.h>//断言
#include "wrapper/checkError.h"
#include "application/Application.h"
#include "glframework/texture.h"

/*
*┌────────────────────────────────────────────────┐
*│ 目           标: 学习使用正交投影矩阵
*│ 讲    师: 赵新政(Carma Zhao)
*│ 拆分目标:
*                                -1 学会使用glm的ortho函数 (orthographic)
                                        ***ortho的数据是摄像机坐标系下***
                                        1.1 使用glm的ortho函数,生成了一个正交投影矩阵       
                                                此矩阵的作用是:生成一个投影盒子,将内部顶点转化到NDC坐标系
                                        1.2 在vertexShader当中,添加了projectionMatrix的uniform变量       
                                        1.3 在每一帧渲染之前,更新projectionMatrix这个uniform
                                       
*                                -2 学习使用非NDC数据
*                                        1 按照标准案例进行构建(ppt上)
*                                        2 将顶点向世界坐标系的-z方向推进较大范围(-5)(剪裁)
*                                        3 将可视范围盒子向相机坐标系的+x方向推进1个单位
*                                        4 保持可视范围盒子不动,动相机(1.0,0.0,0.1)(1.0,0.0,1.0-剪裁)
*
*                                -3 理解剪裁
*└────────────────────────────────────────────────┘
*/

GLuint vao;
Shader* shader = nullptr;
Texture* texture = nullptr;
glm::mat4 transform(1.0f);
glm::mat4 viewMatrix(1.0f);
glm::mat4 orthoMatrix(1.0f);

void OnResize(int width, int height) {
        GL_CALL(glViewport(0, 0, width, height));
        std::cout << "OnResize" << std::endl;
}

void OnKey(int key, int action, int mods) {
        std::cout << key << std::endl;
}

void prepareVAO() {
        //1 准备positions colors
        // float positions[] = {
        //         -0.5f, -0.5f, 0.0f,
        //         0.5f, -0.5f, 0.0f,
        //         0.0f,0.5f, 0.0f,
        // };
        float positions[] = {
                -1.0f, 0.0f, 0.0f,
                1.0f, 0.0f, 0.0f,
                0.0f,1.0f, 0.0f,
        };


        float colors[] = {
                1.0f, 0.0f,0.0f,
                0.0f, 1.0f,0.0f,
                0.0f, 0.0f,1.0f,
        };

        float uvs[] = {
                0.0f, 0.0f,
                1.0f, 0.0f,
                0.5f, 1.0f,
        };

        unsigned int indices[] = {
                0, 1, 2,
        };

        //2 VBO创建
        GLuint posVbo, colorVbo, uvVbo;
        glGenBuffers(1, &posVbo);
        glBindBuffer(GL_ARRAY_BUFFER, posVbo);
        glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);

        glGenBuffers(1, &colorVbo);
        glBindBuffer(GL_ARRAY_BUFFER, colorVbo);
        glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);

        glGenBuffers(1, &uvVbo);
        glBindBuffer(GL_ARRAY_BUFFER, uvVbo);
        glBufferData(GL_ARRAY_BUFFER, sizeof(uvs), uvs, GL_STATIC_DRAW);

        //3 EBO创建
        GLuint ebo;
        glGenBuffers(1, &ebo);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

        //4 VAO创建
        glGenVertexArrays(1, &vao);
        glBindVertexArray(vao);

        //5 绑定vbo ebo 加入属性描述信息
        //5.1 加入位置属性描述信息
        glBindBuffer(GL_ARRAY_BUFFER, posVbo);
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 3, (void*)0);

        //5.2 加入颜色属性描述数据
        glBindBuffer(GL_ARRAY_BUFFER, colorVbo);
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 3, (void*)0);

        //5.3 加入uv属性描述数据
        glBindBuffer(GL_ARRAY_BUFFER, uvVbo);
        glEnableVertexAttribArray(2);
        glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, (void*)0);

        //5.4 加入ebo到当前的vao
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);

        glBindVertexArray(0);
}

void prepareShader() {
        shader = new Shader("assets/shaders/vertex.glsl","assets/shaders/fragment.glsl");
}

void prepareTexture() {
        texture = new Texture("assets/textures/goku.jpg", 0);
}

void prepareCamera() {
        //lookat:生成一个viewMatrix
        //eye:当前摄像机所在的位置
        //center:当前摄像机看向的那个点
        //up:穹顶向量
        viewMatrix = glm::lookAt(glm::vec3(1.0f,0.0f,1.0f),glm::vec3(0.0f,0.0f,0.0f),glm::vec3(0.0f,1.0f,0.0f));
        // viewMatrix = glm::lookAt(glm::vec3(1.0f,0.0f,0.1f),glm::vec3(0.0f,0.0f,0.0f),glm::vec3(0.0f,1.0f,0.0f));
        // viewMatrix = glm::lookAt(glm::vec3(0.0f,0.0f,1.0f),glm::vec3(0.0f,0.0f,0.0f),glm::vec3(0.0f,1.0f,0.0f));
}

void prepareOrtho() {
        orthoMatrix = glm::ortho(-2.0f, 2.0f, -2.0f, 2.0f, 2.0f, -2.0f);
}

void render() {
        //执行opengl画布清理操作
        GL_CALL(glClear(GL_COLOR_BUFFER_BIT));

        //绑定当前的program
        shader->begin();
        shader->setInt("sampler", 0);
        shader->setMatrix4x4("transform", transform);
        shader->setMatrix4x4("viewMatrix", viewMatrix);
        shader->setMatrix4x4("projectionMatrix", orthoMatrix);

        //绑定当前的vao
        GL_CALL(glBindVertexArray(vao));

        //发出绘制指令
        GL_CALL(glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0));
        GL_CALL(glBindVertexArray(0));

        shader->end();
}


int main() {
        if (!app->init(800, 600)) {
                return -1;
        }

        app->setResizeCallback(OnResize);
        app->setKeyBoardCallback(OnKey);

        //设置opengl视口以及清理颜色
        GL_CALL(glViewport(0, 0, 800, 600));
        GL_CALL(glClearColor(0.2f, 0.3f, 0.3f, 1.0f));

        prepareShader();
        prepareVAO();
        prepareTexture();
        prepareCamera();
        prepareOrtho();

        while (app->update()) {
                render();
        }

        app->destroy();

        return 0;
}

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: OpenGL笔记十七之正交投影变更实行-glm::ortho函数