计算机图形学 | 实验六:旋转立方体

news2025/2/23 18:45:11

计算机图形学 | 实验六:旋转立方体

  • 计算机图形学 | 实验六:旋转立方体
    • Z-缓冲
    • GLM函数库
    • PVM矩阵
    • PVM矩阵的使用

华中科技大学《计算机图形学》课程

MOOC地址:计算机图形学(HUST)

计算机图形学 | 实验六:旋转立方体

在正式搭建环境之前,我们先来介绍一下读完下面的部分你会了解些什么。

  • 绘制出旋转立方体需要的新知识
  • 认识一些 OpenGL的新功能

接下来,我们来介绍一下绘制旋转立方体。绘制效果如下:

在这里插入图片描述

Z-缓冲

Z-缓存(Z-Buffer):这是一项处理 3D物体深度信息的技术,它对不同物体和同一物体不同部分的当前 Z坐标进行纪录,也就是在 3D环境中,每个像素会利用一组数据资料来定义像素在显示时的纵深度(即 Z轴坐标值)。在进行着色时,对那些在其他物体背后的结构进行消隐,使它们不被显示出来。

在 OpenGL 中,坐标映射到屏幕屏幕空间后,其 z值即最终 z-缓冲的值,只需记录每个屏幕像素点的 z 值,并与当前绘制的片元的 z值进行比对,即可判断物体是否遮挡或被遮挡。实际应用中,我们只需要开启深度测试即可。

glEnable(GL_DEPTH_TEST);

GLM函数库

GLM是 OpenGL Mathematics的缩写,它是一个只有头文件的库,也就是说我们只需包含对应的头文件就行了,不用链接和编译。GLM可以在它们的网站上下载。把头文件的根目录复制到你的 includes文件夹,就可以使用这个库了。使用这个库,好处就在于我们只需要输入特定参数,就可以生成我们需要的矩阵。

PVM矩阵

PVM矩阵即 P:projection;V:view;M:model。其中,model矩阵对应从局部坐标系到世界坐标系的变换,模型矩阵是一种转换矩阵,它能通过对对象进行平移、缩放、旋转来将它置于它本应该在的位置或方向。

view矩阵对应从世界坐标系到观察坐标系的变换,观察坐标系就是从摄像机的角度观察到的坐标系。而这通常是由一系列的平移和旋转的组合来平移和旋转场景从而使得特定的对象被转换到摄像机前面。

projection 矩阵对应从观察坐标系到剪裁空间的变换,它指定了坐标的范围,例如,每个维度都是从-1000到 1000。投影矩阵接着会将在它指定的范围内的坐标转换到标准化设备坐标系中(-1.0,1.0)。所有在在范围(-1.0,1.0)外的坐标都不会被绘制出来并且会被裁剪。由投影矩阵创建的观察区域被称为平截头体,且每个出现在平截头体范围内的坐标都会最终出现在用户的屏幕上。将一定范围内的坐标转化到标准化设备坐标系的过程(而且它很容易被映射到 2D观察空间坐标)被称之为投影,因为使用投影矩阵能将 3维坐标投影到很容易映射的2D标准化设备坐标系中。

一旦所有顶点被转换到裁剪空间,最终的操作——透视划分将会执行,在这个过程中我们将位置向量的 x,y,z分量分别除以向量的齐次 w分量;透视划分是将 4维裁剪空间坐标转换为 3维标准化设备坐标。这一步会在每一个顶点着色器运行的最后被自动执行。 在这一阶段之后,坐标经过转换的结果将会被映射到屏幕空间(由glViewport设置)且被转换成片段。

PVM矩阵的使用

那么如何在实践中使用 pvm矩阵呢,首先我们需要引入 GLM函数库的头文件,我们所需要用到的功能都在这三个头文件中。

#include <glm/glm.hpp> 
#include <glm/gtc/matrix_transform.hpp> 
#include <glm/gtc/type_ptr.hpp>

然后我们需要设置 view矩阵的相关参数。

glm::vec3 camera_position = glm::vec3(0.0f, 0.0f, 3.0f); // 摄像机位置
=glm::vec3 camera_front = glm::vec3(0.0f, 0.0f, -1.0f); // 摄像机方向 
glm::vec3 camera_up = glm::vec3(0.0f, 1.0f, 0.0f); // 摄像机上向量

然后我们需要设置 projection矩阵的视野 fov:

float fov = 45.0f;

进入主循环之后我们先计算 model矩阵,首先我们需要创建一个 model矩阵,然后 glm:translate函数是进行平移变换的矩阵,将物体平移(0.0,0.0,0.0)位置,然后进行旋转,第二个参数为旋转的角度,第三个参数为旋转轴。最后进行缩放 glm::vec3变量的三个值分别代表 x,y,z方向的缩放比例。

glm::mat4 model(1);//model矩阵,局部坐标变换至世界坐标 
model = glm::translate(model, glm::vec3(0.0,0.0,0.0)); 
model = glm::rotate(model, (float)glfwGetTime(), glm::vec3(0.5f, 1.0f, 0.0f)); 
model = glm::scale(model, glm::vec3(1.0f,1.0f,1.0f));

为了得到我们需要的 view矩阵,我们需要先创建一个 mat4 view矩阵,通过 glm中的 rotate函数去计算,第一个是相机的位置,第二个参数是相机所正对的目标的坐标,这里使用 camera_position+camera_front(相机的方向),进行向量的加法之后可以获得相机正对的坐标,第三个参数是相机的上向量。

glm::mat4 view(1);//view矩阵,世界坐标变换至观察坐标系 
view = glm::lookAt(camera_position, camera_position + camera_front, camera_up);

在 GLM中可以这样创建一个透视投影矩阵,它的第一个参数定义了 fov的值,它表示的是视野,并且设置了观察空间的大小。对于一个真实的观察效果,它的值经常设置为 45.0,但想要看到更多结果你可以设置一个更大的值。第二个参数设置了宽高比,由视口的高除以宽。第三和第四个参数设置了平截头体的近和远平面。我们经常设置近距离为 0.1而远距离设为 100.0。所有在近平面和远平面的顶点且处于平截头体内的顶点都会被渲染。

glm::mat4 projection(1);//projection矩阵,投影矩阵 
projection = glm::perspective(glm::radians(fov), (float)screen_width / screen_height, 0.1f, 100.0f);

我们之前的操作都只是得到 model,view和 projection矩阵,但是不能忘记将这三个矩阵传入到着色器,否则着色器是没有办法使用的。

glGetUniformLocation 可以获得某个着色器中参数的位置,第一个参数为着色器 id,第二个参数为该参数的名称。

int model_location = glGetUniformLocation(shader.ID, "model");
// 获取着色器内某个参数的位置

glUniformMatrix4fv是向指定位置传入一个 4X4的矩阵值。通过这两个函数我们将 pvm矩阵传入着色器中。

glUniformMatrix4fv(model_location, 1, GL_FALSE, glm::value_ptr(model));// 写入参数值

最后,在着色器中,对于矩阵的乘法,由于不符合乘法交换律,所以我们应当注意相乘顺序。

gl_Position = projection * view * model * vec4(aPos, 1.0);

整个绘制旋转立方体的程序的新知识点介绍就到此为止,效果如下:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/507187.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

怎么看待QA(软件测试)漏测bug?

先抛出我的2个观点&#xff1a; 1、漏测不一定是测试的锅。但当问题发生时&#xff0c;测试第一时间不要去拒绝推卸责任&#xff0c;而是要先去解决漏测问题。 2、漏测问题的及时处理很重要&#xff0c;但是避免再次漏测更重要。 为了将此问题阐述的更清楚&#xff0c;我将通过…

SSM框架学习-DI依赖注入方式实例

DI依赖注入&#xff1a;依赖注入&#xff08;Dependency Injection, DI&#xff09;是一种设计模式&#xff0c;用于将一个对象所需要的其他对象的引用或依赖关系从代码中解耦出来&#xff0c;将其交由某个第三方来管理&#xff0c;使得对象本身更加独立&#xff0c;便于测试和…

使用读写锁提高并发

我们想要的是&#xff1a;允许多个线程同时读&#xff0c;但只要有一个线程在写&#xff0c;其他线程就必须等待。 ReadWriteLock ReadWriteLock的作用&#xff1a; 只允许一个线程写入&#xff08;其他线程既不能写入也不能读取&#xff09;&#xff1b;没有写入时&#xf…

基于深度学习的三维重建网络PatchMatchNet(三):如何利用patchmatchnet完成自己场景的数据集制作与利用自己的数据完成三维重建工作

目录 1.如何使用本篇博客 1.1 patchmatchnet网络环境配置 1.2 colmap环境配置 2.如何利用colmap制作自己的三维重建数据集 2.1 采集数据 2.2 使用colmap计算位姿 2.3 转换位姿到MVS读取的格式 2.4 剔除离群图片 2.5 运用patchmatchnet进行三维重建 1.如何使用本篇博客 …

【MySQL】简单使用

数据库&#xff1a;文件&#xff0c;管理系统 类别&#xff1a;关系型&#xff0c;非关系型&#xff08;nosql&#xff09; C/S模式&#xff08;客户端服务器&#xff09; mysql登录 用户名&密码 默认管理员&#xff1a;root 登录&#xff1a;Linux管理员身份运行客户…

为什么二极管具有单向导通性

大家都知道二极管具有单向导通性&#xff0c;比如一个双极性的信号通过二极管后会变成一个单极性的信号。 为了弄清这个问题先来看一下二极管的构成。 在纯净的硅晶体中掺入五价元素&#xff0c;比如磷&#xff0c;就形成了N型半导体&#xff0c;掺入的五价元素多余的电子很容…

汉明码简单计算方法

正算 看一张图 其中标绿底色的为汉明码校验位&#xff0c;可以发现&#xff0c;这些位置的2进制里面只有一个1&#xff0c;其他位上都是0。 先说结论&#xff1a;校验位上的1在第几个位上&#xff0c;就会用来保证位置的2进制里面该位上为1的位置上的1的个数为偶数。 比如&…

11_Uboot启动流程_3

目录 run_main_loop函数详解 cli_loop函数详解 cmd_process函数详解 run_main_loop函数详解 uboot启动以后会进入3秒倒计时,如果在3秒倒计时结束之前按下按下回车键,那么就,会进入uboot的命令模式,如果倒计时结束以后都没有按下回车键,那么就会自动启动Linux内核,这个功能…

MySQ ---- 函数

函数 函数是指一段可以直接被另一段程序调用的程序或代码。MySQL 内置了很多函数&#xff0c;开发人员只需要调用使用即可。查询语句中已经使用过了一些聚合函数。下面还有些常用的函数需要掌握。 函数应用场景举例 函数的分类 ① 字符串函数 ② 数值函数 ③ 日期函数 ④ 流程…

chap和ppp认证配置+MGRE实验

题目要求 1.R2为ISP&#xff0c;其上只能配置IP地址 2.R1-R2之间为HDLC封装 3.R2-R3之间为ppp封装&#xff0c;pap认证&#xff0c;R2为主认证方 4.R2-R4之间为ppp封装&#xff0c;chap认证&#xff0c;R2为主认证方 5.R1,R2,R3构建MGRE环境&#xff0c;仅R1的IP地址固定 6.内…

OpenPCDet系列 | 4.KITTI数据集数据加载流程代码解析

文章目录 数据加载流程0. create_kitti_infos1. __getitem__函数2. prepare_data函数3. collate_batch函数数据加载流程 这里记录一下具体用到的那些数据形式,整个kitti数据集的处理框架图如下所示: 在数据集处理到获取一个batch数据的整个流程的入口如下: # 开始迭代每…

STL常用容器

目录 一、string容器 1、基本概念 2、构造函数 3、赋值操作 4、字符串拼接 5、查找和替换 6、字符串比较 7、字符存取 8、插入与删除 9、获取字串 二、vector容器 1、基本概念 2、构造函数 3、赋值操作 4、容量和大小 5、插入和删除 6、数据存取 7、互换容器…

hadoop shell操作HDFS文件

一.常用的 hadoop shell 文件路径需要自己有才行&#xff0c;示例中的文件路径是本人自己的文件路径&#xff0c;不是公共文件路径&#xff0c;如何建立自己的数仓&#xff0c;查看本人 大数据单机学习环境搭建 相关文章 1.1查看 创建 删除 # 列出当前hdfs所存贮的文件 hado…

模式串匹配算法(朴素模式匹配与KMP)的机算与手算。

一.朴素模式匹配 1.机算 其实就是暴力匹配。 使用双指针 i (指向主串) j (指向模式串) 从主串 S 第一字符起,与模式串 T, 第一个字符比较&#xff0c;   ①若相同&#xff0c;则 i 与 j 统一向后移   ②若遇到 i 与 j 指向字符不同&#xff0c;回溯 i j 指针。继续如此&a…

经验分享|如何搭建产品帮助文档

作为一款优秀的产品&#xff0c;除了功能强大、易于使用等特点外&#xff0c;相应的使用说明和帮助文档也是至关重要的&#xff0c;这些说明和文档可以帮助用户更好地使用这款产品&#xff0c;并解决在使用过程中的问题。本篇文章将为大家详细介绍如何搭建一份优秀的产品帮助文…

12-Vue技术栈之Vuex的使用

目录 1、理解 vue1.1 vuex 是什么1.2 什么时候使用 Vue1.3 图解两种方式实现数据共享 2、搭建vuex环境2.1 下载vuex2.2 配置文件 3、基本使用3.1 求和案例纯vue写法3.2 求和案例vuex写法 4、getters的使用5、四个map方法的使用5.1 求和案例 6、 模块化命名空间6.1求和案例改造 …

C++“static“成员使用

1.static 成员概念 声明为static的类成员称为类的静态成员&#xff0c;用static修饰的成员变量&#xff0c;称之为静态成员变量&#xff1b;用static修饰的成员函数&#xff0c;称之为静态成员函数。静态成员变量一定要在类外进行初始化。 1.2 static特性 静态成员为所有类对…

JVM学习(十):方法区

目录 一、栈、堆和方法区的交互关系 二、对方法区的理解 2.1 方法区在哪里 2.2 方法区的基本概念 2.3 Hotspot中方法区的演进 三、方法区的大小 3.1 设置参数 3.1.1 jdk7及以前 3.1.2 jdk8以后&#xff1a; 3.2 配置参数演示OOM 四、方法区的内部结构 4.1 方法区里…

【Java虚拟机】JVM调优和分析案例综合实战

1.什么是JVM性能优化 jvm性能优化涉及到两个很重要的概念&#xff1a;吞吐量和响应时间。jvm调优主要是针对他们进行调整优化&#xff0c;达到一个理想的目标&#xff0c;根据业务确定目标是吞吐量优先还是响应时间优先。 吞吐量&#xff1a;用户代码执行时间/(用户代码执行时…

C语言学习分享(第六次)------数组

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:C语言学习分享⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习更多C语言知识   &#x1f51d;&#x1f51d; 数组详解 1. 前言&#x1f536;2. …