【Unity Shader入门精要 第4章】数学基础(二)

1. Unity中的坐标空间

1.1 五个坐标空间

模型空间

  • 模型自身的3D坐标系空间,左手坐标系
  • 是一个相对空间,坐标轴指向随模型旋转变化
  • 当物体有父节点时,Transform组件中各属性的值表示的即为该物体在其父物体的模型空间中的值
  • 当模型顶点传入顶点着色器时,其中的空间信息均为自身模型空间的信息

世界空间

  • 世界3D坐标系空间,左手坐标系
  • 是一个绝对空间,坐标轴指向不会发生变化
  • 当物体没有父节点时,Transform组件中各属性的值表示的即为该物体在世界空间中的值

观察空间

  • 摄像机的模型空间,也是一个3D坐标系空间
  • 是Unity中唯一的一个右手坐标系空间
  • 以摄像机位置为坐标原点
  • 摄像机面向的方向为Z轴负方向

齐次裁剪空间

  • 左手坐标系
  • 其本质是视锥体包围的空间,或摄像机渲染范围的空间
  • 齐次裁剪空间也被称作投影空间,但实际上这时候并没有进行真正的投影,因为还没有对矢量进行降维,该空间仍然是一个3D空间
  • 齐次空间范围内的部分可见,范围外的部分为不可见,需要从渲染中剔除
  • 在透视投影下:
    • 由近裁截面距离、远裁截面距离、FOV以及横纵比决定空间范围
    • 形状为平头四棱锥
    • FOV决定锥体竖直方向的张开角度
    • 根据近裁截面、远裁截面和FOV可以求出近裁截面和远裁截面的高度,根据横纵比可以求出近裁截面和远裁截面的宽度
  • 在正交投影下:
    • 由近裁截面距离、远裁截面距离、SIZE以及横纵比决定空间范围
    • 形状为立方体
    • SIZE决定立方体竖直方向上高度的一半
    • 根据近裁截面、远裁截面和SIZE可以求出近裁截面和远裁截面的高度,根据横纵比可以求出近裁截面和远裁截面的宽度
  • 齐次空间仍然为一个非归一化的三维空间

屏幕空间

  • 左手坐标系
  • 对应当前显示屏幕的2D像素空间
  • 空间范围为(0, 0 )到(ScreenMaxPixelX, ScreenMaxPixelY)

1.2 四个转换过程

模型变换

  • Model Transform —— M
  • 将顶点从模型空间转换到世界空间

观察变换

  • View Transform —— V
  • 将顶点从世界空间转换到观察空间

投影变换

  • Projection Tranform —— P
  • 将顶点从观察空间转换到投影空间(齐次裁剪空间)
  • 根据摄像机的设置不同,分为透视投影(Perspective Projection)和正交投影(Orthographic Projection)两种投影变换方式
  • 同样,这里所谓的投影变换并不是真正进行降维投影,仍然是3D空间到3D空间的变换
  • 所谓投影变换只是对矢量乘以一个变换矩阵(称为投影矩阵或裁剪矩阵),得到矢量在当前齐次空间中真正的齐次坐标
  • 变换矩阵的推导过程并不重要,变换矩阵长什么样也不重要,重要的是我们知道矢量经过与变换矩阵的计算后,其w分量发生了变化,不再是初始的1和0,而是变成了-Z(点)和1(向量)

屏幕映射

  • 以上MVP三种变换都是在顶点着色器中完成的,回忆第二章中渲染流水线的几何阶段,在顶点着色器和屏幕映射阶段之间还有一个必不可少的裁剪阶段,因此在做真正的屏幕映射之前,还需要先进行一步裁剪
  • 上面我们提到过,齐次裁剪空间是一个非归一化的空间,在不同的摄像机设置下,视锥体的范围是不同的,为了能够对不同的视锥体范围进行统一的裁剪处理,需要先将齐次坐标映射到一个统一的范围之内,这一步通过将齐次坐标的所有分量都除以w分量来完成,称为齐次除法(感觉齐次除法就是一个从四维投影到三维的过程)
  • 经过齐次除法后,我们得到了一个(x/w, y/w, z/w, 1)的坐标,称为归一化设备坐标(NDC),而原来的裁剪空间也被投影到了一个(-1,1)的正立方体空间范围(DX为0到1)
  • 此时就可以对所有的NDC坐标进行统一的裁剪处理,只需要考虑坐标是否超出(-1,1)的范围即可
  • 裁剪结束后,所有剩余的顶点都是在屏幕范围内的点,需要根据其X和Y的值映射到(0, 0)至(MaxScreenPixelX, MaxScreenPixelY)的范围内,可以看到,这时候才真正从3D空间投影到了2D空间
  • 剩余的Z值则表示该顶点到屏幕的距离,即深度值

1.3 空间转换图示

在这里插入图片描述

2. 坐标空间变换矩阵

对于坐标空间A和坐标空间B,当我们知道了:

  • B空间的原点 O 在A空间的表示为 OriginalB
  • B空间的 X 轴在A空间的表示为 AxisBx
  • B空间的 Y 轴在A空间的表示为 AxisBy
  • B空间的 Z 轴在A空间的表示为 AxisBz

则从坐标空间B到坐标空间A的转换矩阵MB→A(4*4)为:
( ∣ ∣ ∣ ∣ A x i s B   x   A x i s B   y   A x i s B   z   O r i g i n a l B ∣ ∣ ∣ ∣ 0 0 0 1 ) \left( \begin{matrix} | & | & | & |\\ AxisB~x~ & AxisB~y~ & AxisB~z~ & OriginalB\\ | & | & | & |\\ 0 &0&0&1 \end{matrix} \right) AxisB x 0AxisB y 0AxisB z 0OriginalB1
即将X轴、Y轴、Z轴、原点按列组合形成的4 * 4矩阵(推导过程懒得写了)

由于向量不存在空间位置属性,因此对于向量的变换矩阵可以不关心原点,故可以直接截取3 * 3的轴矩阵 MB→A(3*3):
( ∣ ∣ ∣ A x i s B   x   A x i s B   y   A x i s B   z   ∣ ∣ ∣ ) \left( \begin{matrix} | & | & | \\ AxisB~x~ & AxisB~y~ & AxisB~z~ \\ | & | & | \end{matrix} \right) AxisB x AxisB y AxisB z 

根据以上矩阵可以做如下推导:

  • 对于任意B空间内的向量VB,其在A空间的表示 VA = MB→A(3 * 3) * VB
  • 两边同时乘以 MB→A(3 * 3) 的逆矩阵 MB→A(3 * 3)-1
  • 得到等式 MB→A(3 * 3)-1 * VA = VB

即:MA→B(3 * 3) = MB→A(3 * 3)-1

同时,由于 MB→A(3 * 3)是由坐标空间B的三个坐标轴组合得到的矩阵,而坐标轴组合的矩阵一定是正交矩阵,因此 MB→A(3 * 3)的转置矩阵与逆矩阵相同

因此,此时从坐标空间A反向转换到坐标空间B的转换矩阵 MA→B(3 * 3) = MB→A(3 * 3)-1 = MB→A(3 * 3)T,故 MA→B(3 * 3) 为:
( — A x i s B   x   — — A x i s B   y   — — A x i s B   z   — ) \left( \begin{matrix} — & AxisB~x~ & — \\ — & AxisB~y~ & — \\ — & AxisB~z~ & — \end{matrix} \right) AxisB x AxisB y AxisB z 

3.法线变换

普通的转换矩阵适用于在不同的坐标空间之间对点和普通向量进行空间变换,但是如果直接用该矩阵对法线进行变换,就会出错

这是因为法线并不是空间内真实存在的向量,法线只是对空间内某一平面垂直的一个相对向量,或者说是对空间内真实存在的向量虚构出来的相对向量,具有一定的相对性

当进行空间变换后,这种相对性无法保证依然生效,因此可能导致变换后的法线与变换后的平面并不垂直

而切线是由空间内相邻两点确定的,也就是空间中真实存在的向量,因此可以通过普通的转换矩阵进行空间变换,并且我们可以利用切线来推导出使用于法线的转换矩阵

假设T为切线,N为法线,M为切线的转换矩阵,G为法线的转换矩阵
TB = M * TA
NB = G * NA

由切线与法线垂直可得:
TB · NB = (M * TA) · (G * NA) = 0
注意,上式表示的是两个垂直向量的点乘结果为0

如果将上式改成矩阵乘法来表示,就需要将TB 转置成列矩阵后再与行矩阵 NB 相乘
于是得到:
(M * TAT · (G * NA) = TAT * MT * G * NA = TAT * (MT * G) * NA = 0

由于TAT * NA = 0,因此要使上式成立,只要 MT * G = I,即G = (MT)-1 = (M-1)T

于是问题转化为求普通转换矩阵 M 的逆矩阵 M-1

  • 如果只存在旋转变换,由于旋转矩阵为正交矩阵,M-1 = MT,因此 G = (M-1)T = (MT)T = M
  • 如果只存在旋转变换和统一缩放变换,假设统一缩放系数为K,则G = 1/k * M(这里一直没明白,为什么不是1/k2 * M,有没有大佬给解释一下??)
  • 如果存在非统一缩放变换或平移变换,就只能求逆矩阵了

4. Unity内置变换矩阵

Unity内置了一些变量,可以轻松的获取对应的转换矩阵,这里提供的都是4*4的矩阵

变量作用
_Object2World模型空间到世界空间
_World2Object世界空间到模型空间
变量作用
UNITY_MATRIX_MVP模型空间到齐次裁剪空间
UNITY_MATRIX_V世界空间到观察空间
UNITY_MATRIX_P观察空间到齐次裁剪空间
UNITY_MATRIX_VP世界空间到齐次裁剪空间
变量作用
UNITY_MATRIX_MV模型空间到观察空间
UNITY_MATRIX_T_MV模型空间到观察空间的转置
UNITY_MATRIX_IT_MV模型空间到观察空间的逆转置

5. Unity内置摄像机参数

Unity内置了部分变量可以用来获取对应摄像机参数

变量类型作用
_WorldSpaceCameraPosfloat3摄像机世界坐标
变量类型作用
_ScreenParamsfloat4(width, height, 1 + 1/w, 1 + 1/h)
_ZBufferParamsfloat4(1 - F/N, F/N, x/F, y/F)
_ProjectinParamsfloat4(1/-1, N, F, 1 + 1/F),首位为-1时表示使用的是翻转的投影矩阵
Unity_OrthoParamsfloat4(w, h, _, 0/1) 最后位为0时为透视相机,为1时为正交相机
变量类型作用
Unity_CameraProjectionfloat4x4摄像机投影矩阵
Unity_CameraInvProjectionfloat4x4摄像机投影矩阵的逆矩阵
Unity_CameraWorldClipPlanes[6]float4左右上下远近

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

初始数据类型

注释补充 在我们编写任何代码的时候,都有一个叫做注释的功能 在golang中有两种 单行注释 // 如下图所示 加入了注释的话,代码在执行的时候会自动忽视这段内容 //fmt.Println("天上") //fmt.Println("天下") //fmt.Println("唯…

golang学习笔记(协程的基础知识)

golang的协程 协程是一种轻量级的线程,它可以实现并发执行的并行操作。协程是Go语言中的一个核心特性,它使得程序能够以并发的方式运行,并且非常高效。与传统的线程相比,协程的创建和销毁成本非常低,可以方便地启动大…

PS 2018

软件安装 文件太大,分批上传了,后续下载下来文件目录是这样的, 三个文件夹.7z 分批上传,exe也压缩分批上传, 其中products文件夹太大,里面子目录继续压缩分批上传 都下好了,就exe执行安装就行…

4.3 JavaScript变量

4.3.1 变量的声明 JavaScript是一种弱类型的脚本语言,无论是数字、文本还是其他内容,统一使用关键词var加上变量名称进行声明,其中关键词var来源于英文单词variable(变量)的前三个字母。 可以在声明变量的同时对其指定…

使用Python实现二维码生成工具

二维码的本质是什么? 二维码本质上,就是一段字符串。 我们可以把任意的字符串,制作成一个二维码图片。 生活中使用的二维码,更多的是一个 URL 网址。 需要用到的模块 先看一下Python标准库,貌似没有实现这个功能的…

Python实现获取网页内容及自动填表单与登录功能

这篇文章主要为大家详细介绍了如何利用Python实现模拟浏览器启动,获取网页内容、自动填表单、自动登录、自动过验证码等功能,需要的可以参考一下 库 源码 知识点补充 食用前准备 python 3.10.10 #二维码的库ddddocr 需要 库 import time import d…

VMware虚拟机安装Linux(CentOS)【超详细】

参考大佬文章:VMware虚拟机安装Linux教程(超详细)_vmware安装linux虚拟机-CSDN博客 目录 一、获取映射文件 二、新建虚拟机 三、安装操作系统 四、切换系统用户 一、获取映射文件 参考大佬文章获取映射文件,以及对应修改后缀名的方法 二、新建虚拟…

python项目==一个web项目,配置模板指定文件清洗规则,调用模板规则清洗文件

代码地址 一个小工具。 一个web项目,配置模板指定文件清洗规则,调用模板规则清洗文件 https://github.com/hebian1994/csv-transfer-all 技术栈: SQLite python flask vue3 elementplus 功能介绍: A WEB tool for cleaning…

C#图像:1.图像区域分割与提取

(1)创建一个名为SplitImage的窗体的应用程序,将窗体改名为FormSplitImage。 (2)创建一个名为ImageProcessingLibrary的类库程序,为该工程添加名为ImageProcessing的静态类 (3)为Imag…

leetcode-滑动窗口的最大值-95

题目要求 思路 1.这个题是可以暴力求解的,但是时间复杂度比较高,因此,这里说一个时间复杂度为O(n)的方法 2.因为这个代码是优化后的结果,第一次写如果直接写成这样着实不容易,因此,我直接讲每一行的含义。…

光伏光热一体化技术PVT

1、PVT集热器简介 太阳能光伏光热一体化组件主要由光伏与光热两个部分组成。光伏部分采用技术成熟的太阳能光伏面板,通过控制系统为建筑提供所需电能,主要包括光伏电池、蓄电池、逆变器和控制器等构件。光热部分主要为集热器,将太阳能转换为热…

手写一个uart协议——rs232

先了解一下关于uart和rs232的基础知识 文章目录 一、RS232的回环测试1.1模块整体架构1.2 rx模块设计1.2.1 波形设计1.2.2代码实现与tb1.2.4 仿真 1.3 tx模块设计1.3.1 波形设计1.3.2 代码实现与tb1.3.4 顶层设计1.3.3 仿真 本篇内容: 一、RS232的回环测试 上位机…

记录:git上传自己的本地项目

📚博客主页:knighthood2001 ✨公众号:认知up吧 (目前正在带领大家一起提升认知,感兴趣可以来围观一下) 🎃知识星球:【认知up吧|成长|副业】介绍 ❤️感谢大家点赞👍&…

顺序循环队列--c语言实现

#include <stdio.h> #include <stdlib.h> #include <stdbool.h>#define MAX_SIZE 100 // 假设队列的最大长度为100// 队列结构体 typedef struct {int data[MAX_SIZE]; // 存储队列元素的数组int front; // 队头指针int rear; // 队尾指针 } SeqQueue;// 初…

Python爬虫--爬取糗事百科段子

爬取糗事百科段子&#xff1a; 段子在 <div class"content"> 里面的 <span> 标签里面 不过这里有个坑&#xff0c;div 标签跟 span 标签 之间有很多空行 普通 .*? 是匹配不了的&#xff0c;需要使用模式修饰符 S S 的意思 让 .(点) 匹配&#xff0c…

C语言零基础快速入门视频教程

C语言零基础快速入门视频教程 介绍C语言C语言零基础视频教程领取教程下期更新预报 介绍C语言 C语言零基础快速入门&#xff1a;探索C语言的起源、特性与魅力 在编程世界中&#xff0c;C语言犹如一座古老而坚实的桥梁&#xff0c;连接着计算机科学的过去与现在。作为一门历史悠…

项目管理【环境】过程

系列文章目录 【引论一】项目管理的意义 【引论二】项目管理的逻辑 【环境】概述 【环境】原则 【环境】过程 一、规划和管理项目的合规性 1.1 规划和管理项目的合规性 1.2 确认合规要求 1.3 审计&#xff1a;衡量合规的程度 二、项目管理计划和项目文件 2.1 项目管理计划和…

中华科技控股集团:人工智能标准化引领者与数字化服务新航程的启航者

4月30日, 矗立于时代科技潮头的中华科技控股集团&#xff0c;自2010年在香港这片国际金融沃土上诞生以来&#xff0c;便以其独特的国资背景与全球化视野&#xff0c;肩负起推动中国科技进步与产业升级的重任。作为国资委麾下的重要一员&#xff0c;中华科技始终坚持创新驱动发展…

[C++初阶]string类

1. 为什么要学习string类 1.1 C语言中的字符串 C语言中&#xff0c;字符串是以\0结尾的一些字符的集合&#xff0c;为了操作方便&#xff0c;C标准库中提供了一些str系列的库函数&#xff0c; 但是这些库函数与字符串是分离开的&#xff0c;不太符合OOP(面向对象)的思想&…

基于HSI模型的水下图像增强算法,Matlab实现

博主简介&#xff1a; 专注、专一于Matlab图像处理学习、交流&#xff0c;matlab图像代码代做/项目合作可以联系&#xff08;QQ:3249726188&#xff09; 个人主页&#xff1a;Matlab_ImagePro-CSDN博客 原则&#xff1a;代码均由本人编写完成&#xff0c;非中介&#xff0c;提供…
最新文章