OpenGL笔记十七之正交投影变换实验-glm::ortho函数
创始人
2024-09-26 16:27:02
0

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

参数详解

  1. left: 视锥体的左边界。
  2. right: 视锥体的右边界。
  3. bottom: 视锥体的下边界。
  4. top: 视锥体的上边界。
  5. zNear: 视锥体的近剪裁面。
  6. zFar: 视锥体的远剪裁面。

返回值

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

工作原理

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

  1. 缩放变换

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

    • 将对象的中心移到原点。

正交投影矩阵公式

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

示例代码

以下是一个实际使用 glm::ortho 函数的示例:

#include  #include  #include   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.1100-11
  • 第四行: 齐次坐标。

通过理解 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   #include "glframework/core.h" #include "glframework/shader.h" #include  #include //断言 #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; } 

相关内容

热门资讯

技术分享!(Wepoke黑科技... 技术分享!(Wepoke黑科技)外挂透明挂辅助插件(辅助透视)软件透明挂(2024已更新)(哔哩哔哩...
一分钟了解!(Ruuner)外... 一分钟了解!(Ruuner)外挂透明挂辅助安装(透视)详细教程(2023已更新)(哔哩哔哩);Ruu...
玩家必看分享!((WPK插件)... 您好,WPK插件这款游戏可以开挂的,确实是有挂的,需要了解加微【136704302】很多玩家在这款游...
分辨真假!(WEPOKE)外挂... 【福星临门,好运相随】;分辨真假!(WEPOKE)外挂透明挂辅助助手(辅助透视)软件透明挂(2025...
重大通报!(大厅wpk)外挂透... 重大通报!(大厅wpk)外挂透明挂辅助透视(透视)详细教程(2023已更新)(哔哩哔哩);大厅wpk...
5分钟了解!((wpk微扑克)... 自定义新版wpk微扑克系统规律,只需要输入自己想要的开挂功能,一键便可以生成出wpk微扑克专用辅助器...
玩家必备教程!(Wepoke技... 玩家必备教程!(Wepoke技巧)外挂透明挂辅助插件(透视辅助)软件透明挂(2022已更新)(哔哩哔...
每日必看教程!(wpk安卓版本... 每日必看教程!(wpk安卓版本)外挂透明挂辅助透视(透视)详细教程(2022已更新)(哔哩哔哩);超...
总算了解!((wepoKE))... 总算了解!((wepoKE))有挂确实有辅助挂,太离谱了原来是有挂(2021已更新)(哔哩哔哩);详...
每日必看!(网易棋牌)外挂透明... 每日必看!(网易棋牌)外挂透明挂辅助神器(辅助透视)软件透明挂(2021已更新)(哔哩哔哩);相信小...