云计算百科
云计算领域专业知识百科平台

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

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

—— 2024-07-30 晚上

bilibili赵新政老师的教程看后笔记

code review!

文章目录

  • OpenGL笔记十七之正交投影变换实验-glm::ortho函数
    • 1.glm::ortho函数
      • 参数详解
      • 返回值
      • 工作原理
      • 正交投影矩阵公式
      • 示例代码
      • 输出结果
      • 解释
    • 2.实验一:使用glm的ortho函数
    • 2.实验二:使用非NDC数据
    • 3.实验三:将顶点向世界坐标系的-z方向推进较大范围(-5)(剪裁)
    • 4.实验四:将可视范围盒子向相机坐标系的+x方向推进1个单位
    • 5.实验五:保持可视范围盒子不动,动相机(1.0,0.0,0.1)
    • 5.实验六:保持可视范围盒子不动,动相机(1.0,0.0,1.0-剪裁)
    • 6.vs
    • 7.fs
    • 8.main.cpp

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 类型的 4×4 正交投影矩阵。

    工作原理

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

  • 缩放变换:

    • 将对象的坐标从视锥体的范围 [left, right] 映射到标准化设备坐标的范围 [-1, 1]。
    • 同理,将对象的坐标从 [bottom, top] 和 [zNear, zFar] 映射到 [-1, 1]。
  • 平移变换:

    • 将对象的中心移到原点。
  • 正交投影矩阵公式

    正交投影矩阵的公式如下: 在这里插入图片描述

    示例代码

    以下是一个实际使用 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[i][j] << " ";
    }
    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,
    };

    运行 在这里插入图片描述

    2.实验二:使用非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[] = {
    1.0f, 0.0f, 0.0f,
    1.0f, 0.0f, 0.0f,
    0.0f, 1.0f, 0.0f,
    };

    运行 在这里插入图片描述

    3.实验三:将顶点向世界坐标系的-z方向推进较大范围(-5)(剪裁)

    float positions[] = {
    1.0f, 0.0f, 5.0f,
    1.0f, 0.0f, 5.0f,
    0.0f, 1.0f, 5.0f,
    };

    运行 在这里插入图片描述

    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,
    };

    运行 在这里插入图片描述

    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,
    };

    运行 在这里插入图片描述

    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,
    };

    运行 在这里插入图片描述

    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;
    }

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » OpenGL笔记十七之正交投影变换实验-glm::ortho函数
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!