OpenGL笔记十七之正交投影变更实行-glm: rtho函数
—— 2024-07-30 晚上
bilibili赵新政老师的教程看后笔记
code review!
1.glm: rtho函数
glm: rtho 函数是 OpenGL 数学库 GLM (OpenGL Mathematics) 中用于天生正交投影矩阵的函数。正交投影矩阵在渲染2D场景或需要保持对象真实尺寸的3D场景时非常有用。glm: rtho 函数的定义如下:
- glm::mat4 glm::ortho(
- float left,
- float right,
- float bottom,
- float top,
- float zNear,
- float zFar
- );
复制代码 参数详解
- left: 视锥体的左边界。
- right: 视锥体的右边界。
- bottom: 视锥体的下边界。
- top: 视锥体的上边界。
- zNear: 视锥体的近剪裁面。
- zFar: 视锥体的远剪裁面。
返回值
glm: rtho 返回一个 glm::mat4 类型的 4x4 正交投影矩阵。
工作原理
正交投影矩阵用于将3D坐标转换为2D屏幕坐标,它不会像透视投影矩阵那样产生间隔缩放效果。正交投影矩阵的天生通过以下步骤实现:
- 缩放变更:
- 将对象的坐标从视锥体的范围 [left, right] 映射到标准扮装备坐标的范围 [-1, 1]。
- 同理,将对象的坐标从 [bottom, top] 和 [zNear, zFar] 映射到 [-1, 1]。
- 平移变更:
正交投影矩阵公式
正交投影矩阵的公式如下:
示例代码
以下是一个现实使用 glm: rtho 函数的示例:
- #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: rtho 函数的原理和使用方法,可以方便地在 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;
- }
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |