【渲染管线-1】坐标变换的理解

2023-11-04

本文将尽可能细致的对坐标变换的过程,用意和一些细节进行剖析,目的是方便自己在遗忘时进行复习,因此可能会有些繁琐。

文章将分成两部分,第一部分包含大量例子,主要用于对变换过程有一个形象的概念,不涉及具体内部计算,第二部分为真实计算逻辑,但隐去了计算的公式,有时间会补充第三部分即计算过程。

1、对坐标变换的形象理解

一个点,从三维空间到最终映射到屏幕上,它经历了一系列的坐标变换以及颜色的计算,这里只说坐标变换。

举例,若你的桌子右上角有一个杯子,以前为z,右为x,上为y,那么它的坐标在(1,0,1),杯子的把手可能在(1,0.5,1)但是,对杯子自己来说,在杯子的认知里,它在(0,0,0)这个点,它的把手在(0,0.5,0)。

现在,移动视线从不同的位置去看这个杯子,它在你的视野里可能位于右下,左上,正中间等等。这时,在你的视野里,杯子的位置坐标将不再是(1,0,1),例如,当视线与桌子齐平,并正视杯子时,那么杯子在你的正前方1个单位处,它的坐标是(0,0,1)。

以上所述即为坐标变换过程,即,给定杯子,桌子与人眼的基向量,并给定杯子在自身模型空间内的坐标点,则可通过坐标变换计算出该点在人眼中的坐标。

实际上,在3D场景内,也有一个代替人眼的对象,叫摄像机,所展现出的画面均以摄像机所“看”为准,因此,在计算机内,也要经历这样的一个坐标变换过程。

然而,为何一定要经历这样的变换来获得最终坐标呢?因为,通常来说,模型中顶点的坐标位置都是基于模型空间的,根本无法不通过变换而直接得知一个点在摄像空间里的坐标,这跟人眼看过去就可以进行直接进行位置判断有本质的区别,因此,在计算机的3维世界内,我们不得不借用数学工具,来对点的最终位置进行计算。

这里具体展开说基向量的变换,因为它是整个坐标变换的核心概念。

基的作用就是赋予点“坐标”,同一个点基于不同的基即有了不同的坐标,因此,进行坐标变换,本质上就是进行基向量的变换。

说的再简单一点,基就像单位,(1,2)即为该点由1个单位的x与2个单位的y组成,且,由1个单位的x,与2个单位的y,在x与y这两个基不变的情况下,可唯一定位一个2维空间内的一个点。为啥要把一个点分成两个单位来描述?因为两个不平行的向量可确定一个唯一的二维空间(二维平面)…

因此,基向量的变换,就可理解为换一组单位去描述这个点。

生活中进行单位的换算,首先就是计算1个单位=多少个新单位,例如1元=10角,那么10元=10*10角。因此,1个单位的x与2个单位的y也是这样进行换算的。

以二维空间为例,如下图所示,将黑色坐标轴与红色坐标轴按原点进行重合,则,红色的1个x单位,等价于 根2/2 个黑色的x+根2/2 个黑色的y。

将y也按照如此进行计算,即可完成单位的转换,即基的变换,再将1个x与2个y的系数1和2乘进去,就可以得出该点在进行了基向量的变换以后的坐标。

但是!要注意,我们在最初是将两个坐标系的原点通过移动进行了重合,因此,最终计算出的坐标需要再移动回去即可。
在这里插入图片描述

2、整个过程在计算机内的逻辑

首先世界坐标是固定不变的,且无法人为设置,一般的引擎都具有add scene之类的api,在这个scene内默认自带一个世界坐标,三根轴的方向通常是右x,上y,以及垂直于屏幕向外是z。

这个默认的坐标就是最初的“单位”,必须拥有最初的单位,才能在后续添加/计算其他的基。

在scene内添加一个节点,这个节点也可以理解为是一个新的坐标系,刚添加进去时,节点内储存的该节点的基与世界坐标系的基是一样的,即(1,0,0),(0,1,0),(0,0,1),在这之后,通过移动,旋转该节点,它内部储存的基也会进行相应的变化,此外,因为它的初始基是世界坐标系,所以四舍五入变化也是基于世界坐标。

此时,在该节点内再添加一个新的节点,则这个新的节点又将拥有一个默认的基,这个基也是(1,0,0),(0,1,0),(0,0,1),但此时,这个基是基于它父节点的基进行计算的。

综上,这个父子关系可抽象为 scene–>A节点–>B节点,此时,若B节点内有一个顶点xyz,则该顶点的坐标,在A的基向量下的坐标(即变换到A的坐标系尺度内),其计算方法是乘以B节点内储存的基向量所组成的变换矩阵,因为B节点内储存的基,就是基于A坐标系而计算的。

此外,这里也可以解释为什么节点A内的节点B的默认基也是(1,0,0),(0,1,0),(0,0,1),因为,如果它的默认基是A节点的基,则B的基就也是基于世界坐标系了,那么,B节点内的顶点,通过B储存的基进行变换后,就直接变换到世界坐标系了,而不是变换到它的上一层A节点的坐标系。

上述问题会导致,如果我们希望B节点内的一个顶点,基于A节点的原点进行某些运动,这显然需要我们知道该顶点在A坐标系下的坐标,因此,如果B内的顶点基于B储存的基进行变换后直接变换到了世界坐标系下,那就无法基于A的原点进行运动了,这显然不是我们希望的。

但是!由于在实际运行时,从顶点到世界再到摄像机,这一条的变换是最频繁的,因此,通常一个节点内除了储存模型基以外,还会储存世界基,也就是它的基,基于世界坐标的值,根据不同的需求,就可以挑选不同的基(大部分情况下引擎会贴心的将其组装成变换矩阵进行储存)进行变换计算了。

因此,通过这样的父子关系,并且给每个节点(节点也可理解为坐标系)时刻储存着它基于父节点的基以及原点位置(一般是position这个属性),这样,就可以随时将某个基下的一个顶点坐标,通过层层变换,最终回归到该结构的根坐标系——世界坐标。

当然,因为从A变换到B,与从B变换到A没什么本质上的不同,因此,也可以随时从根变换到其他的坐标系。

因此,显而易见,在将一个包含多个层级的节点内的某个顶点坐标,通过层层变换,得到该顶点在世界坐标系内的坐标后,也可以继续变换到摄像机坐标系内,但是!这里要万分注意一件事,那就是变换到摄像机的坐标系,这里涉及到一个逆变换的问题,如下图:
在这里插入图片描述
如图,从左臂依次往上,每个节点内都储存着该节点的本地坐标系在父节点的坐标系内的表示,也即变换到父节点空间的变换矩阵,因此,左臂x左臂内所存矩阵x躯干矩阵x角色矩阵,即可将左臂的节点变换到世界坐标系,但是,在变换到摄像机空间时,不可直接x摄像机节点内所存的矩阵,因为这个矩阵也是基于世界空间的,而需要x的是世界坐标系在摄像机下的变换矩阵,即摄像机到世界空间的变换矩阵的逆矩阵!

有点绕哈,其实很好理解,如下图,我们需要顺着箭头走到摄像机节点,但是根节点到摄像机的箭头是反着的,于是需要对矩阵取逆,就这么简单…
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【渲染管线-1】坐标变换的理解 的相关文章

  • 编写每个三角形/面具有纯色的 GLSL 片段着色器的方法

    我有顶点和三角形数据 其中包含每个数据的颜色triangle 面 不是每个顶点 即单个顶点由多个面共享 每个面可能具有不同的颜色 我应该如何在 GLSL 中解决这个问题以获得每个的纯色分配face正在渲染 通过平均顶点相邻多边形的颜色来计算
  • 给定 3D 空间中的一条线,如何找到从它到一点的角度?

    我在 3D 空间中有两组点 我想画一条穿过两组点的中心的线 然后找到从该线到每个点的角度 从那里开始 我将根据两个角度的接近程度来确定两组中的匹配点 我知道如何找到每组点的中心 只需将它们平均在一起 并且我知道如何将它们匹配 甚至考虑到它们
  • 提取给定 2D 图像点、深度图和相机校准矩阵的 3D 坐标

    我有一套2D image输出的关键点OpenCV FAST角点检测功能 使用Asus Xtion I还有一个时间同步的深度图 其中所有相机校准参数都是已知的 使用这些信息我想提取一组3D坐标 点云 在OpenCV 任何人都可以给我任何有关如
  • 如何在 OpenCV 中绘制图像的 3D 直方图

    更新 我找到更多例子 我现在可以做到 我可以在 3d 中绘制多个直方图吗 https stackoverflow com questions 35210337 can i plot several histograms in 3d 我知道这
  • Direct3D 中的矩阵多阶

    关于在 Direct3D 中乘法矩阵以获得结果 我收到了两个相互矛盾的答案 教程确实规定从左到右相乘 这很好 但这不是我想象的方式 这是一个例子 OpenGL 从上到下阅读 GLRotatef 90 0f GLTranslatef 20 0
  • 从 NumPy 数组中的数据绘制 3D 图像

    我有一个 NumPy 数组中的数据文件 我想查看 3D 图像 我正在分享一个示例 我可以在其中查看大小为 100 100 的 2D 图像 这是 xy 平面上 z 0 处的切片 import numpy as np from matplotl
  • OpenGL Z 偏置(多边形偏移)限制

    我有两个共面的多边形 我尝试做 glEnable GL POLYGON OFFSET FILL glPolygonOffset 0 1 并期望其中一个明显 位于 另一个之上 这种情况直到大约 70 75 个单位之外 近剪裁平面为 1 远剪裁
  • 使用 ThreeJS 获取球体纹理上的点击位置

    目前 我有一个带有纹理的球体 它绕 y 轴旋转 我还有在 3D 空间中单击的位置 以及球体上的旋转位置 我认为 目标 获取纹理上的位置 例如 我想获取我点击的图像的哪个方块 参见示例球体和下图 在实践中 我不会使用此图像 但我觉得这将是一个
  • 颜色重新映射 - 使用 3D 网格匹配目标调色板?

    假设我有颜色 FOO 它以 RGB 格式存储 我需要重新着色 FOO 以便它与颜色列表中最接近的颜色匹配 即时执行此操作 我是否无法将每种颜色的 RGB 值视为 3D 网格上的点 r x g y b z 并计算点 FOO 与每个颜色点之间的
  • 如何知道一个点是否在复杂的 3D 形状内(.ply 文件)

    我正在研究一个Java女巫项目真是要了我的命 经过几天在不同论坛上的研究 寻找我真正需要的东西 我来寻求你的帮助 我的数据 ply 文件 包含由许多三角形组成的 3D 形状 一个点 3D坐标 我想知道这个点是否包含在复杂的 3D 形状内 我
  • 我应该如何格式化 .dat 文件以便制作 3D 矢量图?

    我正在为大学做这个编程任务 我们必须写一个c 计算 3D 空间中某些线圈的磁场矢量的程序 我已经成功编写了这个程序 并且我认为它运行得很好 不过 我想添加一个特殊的东西 这是我的试卷 所以它必须特别好 我想绘制出向量 我习惯打电话gnupl
  • 使用 Scipy/Numpy 在浊点的二维插值中仅获取“有效”点

    我有一个通过人的背部摄影测量获得的浊点 我正在尝试对其进行插值以获得规则网格 为此我正在使用scipy interpolate到目前为止取得了良好的成果 问题是 我正在使用的函数 scipy interpolate griddata 使用平
  • IE9-11 检测变换样式:preserve-3d

    我为一个项目制作了一个 3d 类型的菜单 自然 IE 会引起问题 因为 IE10 即使 3d 变换工作 也不支持变换样式 preserve 3d 我尝试了解决方法 通过对 3d 菜单容器的每个子元素应用变换 但至少可以说 动画看起来很糟糕
  • 更改 3D 图形颜色 (matplotlib)

    我使用以下代码在 matplotlib 中绘制了 3D 图形 Previously defines lists of data to plot fig plt figure ax fig add subplot 111 projection
  • 改变for循环的顺序?

    我遇到一种情况 我需要根据用户输入以不同的顺序循环遍历 xyz 坐标 所以我是 3D 空间中的一个区域 然后是一组像这样的 for 循环 for int x 0 x lt build getWidth x for int y 0 y lt
  • 如何将平面上的 3D 点转换为 UV 坐标?

    我有一个 3d 点 定义为 x0 y0 z0 该点属于一个平面 定义为 a b c d normal a b c and ax by cz d 0 如何将 3d 点转换或映射为一对 u v 坐标 这一定是非常简单的事情 但我无法弄清楚 首先
  • XNA中窗口系统的渲染策略(RenderTarget性能)

    我目前正在从头开始为 XNA 游戏创建一个窗口系统 我主要针对 Windows 进行开发 但谁知道我将来可能支持哪些平台 如果您知道本机 Direct3D 的这一点 请随意回答 因为性能语义应该类似 如果可能 请考虑如果目标平台是 X Bo
  • DirectX::SpriteFont/SpriteBatch 阻止 3D 场景绘制

    我使用时遇到问题DirectX SpriteFont DirectX SpriteBatch 来自 DirectXTK 与此处讨论的问题完全相同 使用 SpriteFont 类绘制文本时出现问题 https stackoverflow co
  • 在 Unity 中平滑动态生成的网格?

    给定 Unity 和 C 中的网格 其本身是通过合并更简单的基础网格实时创建的 我们如何在运行时 将其变成平滑的 几乎像包裹在布中的网格版本一样 不是完全凸出的版本 而是更圆润 软化锋利的边缘 桥接深间隙等 理想情况下 表面也将像 平滑角度
  • Java 的 3D 场景图库?

    我正在寻找一个可靠的 Java 3D 场景图 API 它具有良好的文档 活跃的社区和允许商业使用的许可证 我排除了com sun scenegraph https scenegraph dev java net 因为它是 GPL 而且看起来

随机推荐

  • golang中关于channel中的for range遍历操作

    note channel中若要使用for range进行遍历操作 channel必须首先要进行关闭操作的 例一 func main wg Add 2 write make chan int 5 read make chan int 5 go
  • canvas 动态背景粒子特效 直接拿走

  • 五子棋c++代码_C++大作业赏析

    清小C C 大作业赏析 如何完成一篇优秀的C 大作业 苦恼C 大作业的同学快点进来看看 小声 五子棋设计 五子棋是大家最为熟悉双人对弈的棋类游戏之一 只要任意行 列 斜线连成五子即可获胜 上个学期中 陈昊柯同学的大作业实现了五子棋 不但能够
  • 循环进度可视化tqdm

    Python的tqdm库是循环进度条可视化 可以在 Python 循环中添加一个进度提示信息 用户只需要封装任意的迭代器 tqdm iterator 这里我们分3个部分展示 介绍 使用 实例 安装用pip即可 1 介绍 首先先来看一下如何创
  • express中间件详解

    Express中间件是一个函数 它可以访问请求对象 req 响应对象 res 和next函数 中间件的主要作用是在处理请求之前或之后执行一些操作 例如验证用户身份 记录日志 解析请求体等 使用Express中间件有两种方式 应用级别和路由级
  • STM32CUBEMX_日志系统_RTT和串口(重映射浮点数打印)

    STM32CUBEMX 日志系统 RTT和串口 重映射浮点数打印 前言 嵌入式系统开发过程中日志的打印至关重要 他在系统架构搭建和开发过程中包括后期调试定位问题都非常重要 所以在此记录两种日志打印的方式 第一种是移植J link中自带的RT
  • 生成数字与字母组合随机的字符串

    package kmt test cn import java util Random public class StringRandom 生成随机数字和字母 public String getStringRandom int length
  • Springboot中Eureka的使用方法

    在微服务架构中 注册中心是核心的基础服务 它主要记录各个微服务和微服务地址的映射关系 各个微服务都将自己注册到这个注册中心上面 当微服务之间需要互相调用时 就可以从注册中心上面去发现微服务和进行调用 Spring Cloud是一个开箱即用的
  • Linux基础及Linux环境搭建(保姆级别)

    详细 第一章 Linux基础及Linux环境搭建 保姆级别 Kali BugChen的博客 CSDN博客 第一章 Linux基础及Linux环境的搭建 保姆级别 一 Linux简介 1 什么是Linux 一款免费开源流行的操作系统 2 Li
  • 被车撞了!

    买了新车之后 因为是新手司机上路 开了不到4个月 车身已经被划伤好多处了 有的是我自己不小心划的 有的是车在停车场 不知道被谁划伤的 找不到肇事者了 不过好在都是小小的划伤 不影响车的颜值 也不影响驾驶体验 一开始我还很心疼 后来也释然了
  • 【Linux】进程间通信1-匿名管道1

    文章目录 管道符 创建匿名管道的pipe函数 从内核角度深入理解管道 代码验证pipe函数 管道和子进程的先后创建顺序 代码实现父子进程的通信 管道的特性 前言 为什么需要进程间通信呢 每一个进程的数据都是存储在物理内存当中的 进程通过各自
  • 【JMeter】beanshell 获取/修改请求头信息

    在使用jmeter做接口测试的时候 相信大家一定遇到过以下场景 使用HTTP信息头管理器设置全局请求头信息 如 content type application json 但并非所有的接口的content type都是application
  • osal_start_timerEx 函数分析

    经常用到osal start timerEx函数来周期性产生某一事件 本文就来分析一下该函数 fn osal start timerEx brief This function is called to start a timer to e
  • 同一台电脑安装多个版本的idea

    同一台电脑安装多个版本的idea 需求 当前 电脑上已经安装了idea2019 3 exe版本 发现此版本太旧了 无法体验新版idea2023 1的很多功能及优化 新出的好多idea插件都不支持idea2019 3版本了 比如 支持Chat
  • C/C++浮点数的存储方式 IEEE-754标准,以及实现一个ftoa函数将浮点数转换为字符串

    浮点数的存储格式 转载自 http www cnblogs com dolphin0520 archive 2011 10 02 2198280 html C C 浮点数在内存中的存储方式 任何数据在内存中都是以二进制的形式存储的 例如一个
  • 遍历Map的四种方法

    遍历map的4种方式的比较 public static void main String args Map
  • 机器学习(第一章)—— 特征工程

    目录 一 特征归一化 二 类别型特征 三 高维组合特征的处理 四 组合特征 五 文本表示模型 六 Word2Vec 七 图像数据不足时的处理方法 为什么需要对数值类型的特征做归一化 怎样处理类别型特征 什么是组合特征 如何处理高维组合特征
  • SpringRetry重试机制(3秒上手)

    目录 前言 一 SpringRetry的使用 1 1 引入依赖 1 2 开启重新机制 1 3 3 在方法上添加 Retryable 1 3 4 编写重试失败后的执行的方法 测试 前言 SpringRetry重试机制在实际工作中的场景 比如
  • PTA输出指定范围内的完数

    1 include
  • 【渲染管线-1】坐标变换的理解

    渲染管线 1 坐标变换的理解 1 对坐标变换的形象理解 2 整个过程在计算机内的逻辑 本文将尽可能细致的对坐标变换的过程 用意和一些细节进行剖析 目的是方便自己在遗忘时进行复习 因此可能会有些繁琐 文章将分成两部分 第一部分包含大量例子 主