• 1. 线性变换
  • 2. 切线空间(坐标系)
    • 2.1 切线空间的构成
    • 2.2 切线空间中光照计算及其弊端
  • Reference

1. 线性变换

在掌握切线空间之前我们先来简单了解线性变换与向量空间、矩阵的关系。
什么是线性变换?
简单来说,线性变换就是一种映射关系,我们来看看线性代数对线性方程组的描述——线性方程组是由一个或者几个包含相同变量 x1,x2,x3,...,xnx1,x2,x3,...,xnx_1,x_2,x_3,...,x_n 的线性方程组成的,如:

a11x1+a12x2+...+a1nxn=b1.a21x1+a22x2+...+a2nxn=b2....(1)(1)a11x1+a12x2+...+a1nxn=b1.a21x1+a22x2+...+a2nxn=b2....

a_{11}x_1 + a_{12}x_2 + ... + a_{1n}x_n = b_1. \\ a_{21}x_1 + a_{22}x_2 + ... + a_{2n}x_n = b_2. \\ ...\tag{1}
假设我们有 mmm (本文假设 m=n" role="presentation" style="position: relative;">m=nm=nm=n) 个方程组,以矩阵形式表达该方程组如下:

Ax=b.(2)(2)Ax=b.

Ax = b.\tag{2}
AAA 是一个 m∗n" role="presentation" style="position: relative;">m∗nm∗nm * n 的方块矩阵( m=nm=nm=n), x=(x1,x2,...,xn)x=(x1,x2,...,xn)x = (x_1, x_2, ...,x_n) 是一个 nnn 维向量,b=(b1,b2,...,bn)" role="presentation" style="position: relative;">b=(b1,b2,...,bn)b=(b1,b2,...,bn)b = (b_1,b_2,...,b_n) 是一个 mmm 维向量。那么如何理解线性方程组的矩阵表达式(2)" role="presentation" style="position: relative;">(2)(2)(2)呢?
首先,我们将 AAA 看成是由 n" role="presentation" style="position: relative;">nnn 个列向量组成的:

A=(a1,a2,...,an).A=(a1,a2,...,an).

A = {(a_1,a_2,...,a_n)}.
那么公式 (2)(2)(2)可以表示为:

a1x1+a2x2+,...,+anxn=b.(3)(3)a1x1+a2x2+,...,+anxn=b.

a_1x_1 + a_2x_2 + ,..., + a_nx_n = b.\tag{3}
列向量的线性组合是 RmRmR^m 向量空间的子空间,称为矩阵的列空间(矩阵行向量的线性组合生成在 RnRnR^n 向量空间的子空间,称为矩阵的行空间)。 如果我们把 AAA 看成是看成是 Rn" role="presentation" style="position: relative;">RnRnR^n 到 RmRmR^m 的线性变换,则矩阵列空间是线性变换的 ,向量 xxx 是该线性变换的原像,我们把向量 x" role="presentation" style="position: relative;">xxx 看成是 原坐标系(以矩阵 AAA 列向量的最大线性无关组为一组基底的坐标系)下描述的一个向量,那么向量 b" role="presentation" style="position: relative;">bbb 则是 目标坐标系(以矩阵行向量最大线性无关组为一组基底的坐标系)下描述的一个向量,向量 bbb 的每个分量值都可以看成是向量 b" role="presentation" style="position: relative;">bbb 在目标坐标系对于每一个坐标基的投影长度([ Wiki——行空间与列空间]),因此,向量 xxx 和 b" role="presentation" style="position: relative;">bbb 是同一个向量在不同坐标系下的不同描述。 怎么理解向量 bbb 的分量是相对目标坐标系坐标基的投影长度呢?
我们来看看两个向量 v1" role="presentation" style="position: relative;">v1v1v_1 和 v2v2v_2,现在求 v1v1v_1 在 v2v2v_2 上的投影,看下图((;′⌒`)):

向量 v1=v1proj+v1perpv1=v1proj+v1perpv_1 = v_{1_{proj}} + v_{1_{perp}},v1projv1projv_{1_{proj}} 表示向量 v1v1v_1 平行于 v2v2v_2 的投影向量,从上图中可以看出,如果向量 v2v2v_2 是一个单位向量,那么向量 v1v1v_1 关于 v2v2v_2 的投影长度刚好等于两者点积 dot(v1,v2)dot(v1,v2)dot(v_1,v_2),由此结合公式 (1)(1)(1) 的线性方程组表达式,向量 bbb 的分量的值也恰好等于矩阵 A" role="presentation" style="position: relative;">AAA 行向量与向量 xxx 的点积,假设 A" role="presentation" style="position: relative;">AAA 行向量为单位向量,那么 xxx 的每一个分量则表示其相对于以矩阵 A" role="presentation" style="position: relative;">AAA 行向量构造的坐标系的每一个坐标基的投影长度。

2. 切线空间(坐标系)

切线空间有时也称为纹理空间,切线空间最常见的应用场景是使用法线纹理进行光照计算,而法线纹理其内容有两种表达形式,一种是基于模型空间的,另一种就是基于切线空间的;此外,纹理映射的基本技术(计算纹理坐标)正是基于纹理空间定义的纹理函数[10],它将 2D 图片投影到 3D 模型的表面。(计算机图形学中一般没有区分切线空间和纹理空间。)

2.1 切线空间的构成

切线空间(切线坐标系)通常简称为 TBN 坐标系(Tangent——切线,Binormal——副法线或者Bitangent,Norma——法线),通过上一节“线性变换”我们知道一个 n 维度“坐标系”的构成实际上需要 n 个正交基(也就是 n 个线性无关向量组),下面详细分析 TBN 坐标系,如何计算这三个基向量。
TBN 坐标系建立在模型表面(Surface)之上,N 表示模型表面的法线,T 则是与该法线垂直的切线(理论上我们可以选择任意一条与 N 垂直的切线),B 是与 T、B 都垂直的副法线。假设现在有一个三角形,其顶点分别是 P0、P1、P2P0、P1、P2P_0、P_1、P_2,假设表面法线向量为 NNN,现在要求取 T" role="presentation" style="position: relative;">TTT、BBB,


(引自德克萨斯大学 计算机图形学课件)

如上图使用顶点位置坐标随纹理坐标(UV)的变化定义 T" role="presentation" style="position: relative;">TTT 和 BBB,它们的计算如下:


(引自德克萨斯大学 计算机图形学课件)

计算出来的 T" role="presentation" style="position: relative;">TTT、BBB、N" role="presentation" style="position: relative;">NNN 有可能不是正交的,因此,还需要对这三个向量正交化处理(施密特正交化):

N=Normalize(N).T′=TNperp=T−TNproj.(TNproj=dot(T,N)|N|2N)=dot(T,N)NB′=B−dot(B,T′)T′−dot(B,N)NN=Normalize(N).T′=TNperp=T−TNproj.(TNproj=dot(T,N)|N|2N)=dot(T,N)NB′=B−dot(B,T′)T′−dot(B,N)N

N = Normalize(N).\\ T^{'} = T_{N_{perp}} = T - T_{N_{proj}}. \\ (T_{N_{proj}} = \frac{dot(T,N)}{|N|^2}N) = {dot(T,N)}N \\ B^{'} = B - {dot(B,T^{'})}T^{'} - {dot(B,N)}N

最终得到的 NNN、T′" role="presentation" style="position: relative;">T′T′T^{'}、B′B′B^{'} 就是切线空间的三个基向量。
模型空间(Object Space)转换切线做空间的矩阵表示:

M=⎡⎣⎢⎢T′xB′xNxT′yB′yNyT′zB′zNZ⎤⎦⎥⎥M=[Tx′Ty′Tz′Bx′By′Bz′NxNyNZ]

M = \left[ \begin{matrix} T^{'}_x & T^{'}_y & T^{'}_z \\ B^{'}_x & B^{'}_y & B^{'}_z \\ N_x & N_y & N_Z \end{matrix} \right]

切线空间转到模型空间(Object Space)的矩阵表示:

M−1=⎡⎣⎢T′xT′yT′zB′xB′yB′zNxNyNZ⎤⎦⎥M−1=[Tx′Bx′NxTy′By′NyTz′Bz′NZ]

M^{-1} = \left[ \begin{matrix} T^{'}_x & B^{'}_x & N_x \\ T^{'}_y & B^{'}_y & N_y \\ T^{'}_z & B^{'}_z & N_Z \end{matrix} \right]

2.2 切线空间中光照计算及其弊端

  • 切线空间光照计算。
    如果在 WorldSpace 计算光照,那么表面法向量需要变换到世界坐标空间,而每一个表面的法向量都有可能不同,导致矩阵变换计算消耗较大,相对而言,在切线空间中计算光照,只需要把光源方向(和视线方向)变换到切线空间,矩阵计算相对较少。(这里顺便提一句,理论上我们可以认为 GPU 是一个一个像素进行处理的,而实际上 GPU 执行的最小单位并不是单个像素,GPU 以像素为单位将其执行指令转换成 Thread,而且为方便硬件吞吐,若干 Thread 又组合成 Thread 块——称为CTA,它便对应了硬件可执行的最小处理单位。)
  • 弊端

Reference

[1] 线性代数及其应用.
[2] Wiki——行空间与列空间.
[3] 切线空间
[4] Messing With Tangent Space
[5] CryEngine——Tangent Space And Normal Mapping
[6] Texture Mapping
[7] UVMapping
[8] Wiki——法线贴图
[9] 计算机图形学 OpenGL 第三版 P365
[10] 为什么要有切线空间

切线空间(Tangent Space)相关推荐

  1. [图形学]切向空间(Tangent Space)

    2009年3月17日 阅读评论 发表评论     这个应该算是补遗漏,去年在MSN Space上写过一篇关于凹凸贴图的,当时写了半天其实写的一点也不明白,呵呵,因为有很多细节其实我也没搞太清楚,现在这 ...

  2. 冯乐乐 unity_Unity常用矩阵运算的推导补遗——切线空间

    在上一篇文章中,我写了一些关于Unity中各个坐标空间及其转换矩阵是如何得到的,说实在的,我是那种"记忆需要依靠外部装置存储"类.如同<攻壳机动队>的电子脑一样的人,每 ...

  3. OpenGL 法线贴图 切线空间 整理

    1. What`s Bump Mapping? Bump Mapping通过改变几何体表面各点的法线,使本来是平的东西看起来有凹凸的效果,是一种欺骗眼睛的技术:). 我们知道,如果几何体表面有高低不平 ...

  4. OpenGL基础46:切线空间

    到这里,关于OpenGL基础的了解要接近尾声了,上一个节点是<OpenGL基础25:多光源>.在此章之后,学习openGL的各种教程的同时,可以转战想要了解的渲染引擎,也可以去github ...

  5. Unity Shader - 切线空间的法线贴图应用(T2W W2T)

    法线贴图 法线贴图(或是法线纹理)其实就是一张图片中的RGB通道分别存储着法线方向的纹理(有些为了数据压缩将X,Y存储在RG通道,Z是通过1-dot(xy,xy)来近似计算). 它的由来是因为高模运行 ...

  6. 切线空间以及TBN矩阵

    参考书籍:UnityShader入门精要 参考文章:为什么要有切线空间(Tangent Space),它的作用是什么? 切线空间 首先需要了解一个前提,在图形学中我们会用到很多的坐标空间,而切线空间只 ...

  7. 切线空间、法线贴图、TBN矩阵

    目录 1 法线贴图 1.1 为什么需要? 1.2 怎么做法线映射? 2 切线空间 2.1 为什么需要切线空间? 2.2 切线空间是什么? 2.3 TBN矩阵 2.4 TBN矩阵计算 3 光照计算是在` ...

  8. Unity3D 法线转换与切线空间总结

    在Shader编程中经常会使用一些矩阵变换函数接口,其实它就是把固定流水线中的矩阵变换转移到了可编程流水线或者说GPU中,先看下面的函数语句: // Transform the normal from ...

  9. OpenGL核心技术之切线空间

    笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者;已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D实战核心技术详解 ...

最新文章

  1. 【TensorFlow系列】【五】利用inception v3 pb模型文件做预测
  2. 401 - 未授权: 由于凭据无效,访问被拒绝。
  3. u盘启动 联想一体机_联想Y430pAT-ISE(H)U盘安装Win7系统教程
  4. android studio创建文件,如何在Android Studio中创建File Templates
  5. linux下修改max_user_processes和open_file的最大值
  6. 动态规划 —— 概率 DP 与期望 DP
  7. python如何把数字转化成字符_python 定义一个dictpython如何将数字转化为字符串
  8. php json_encode小数精度丢失的问题
  9. c语言流感,维生素C能防流感?专家:或减轻普通感冒引起不适症状
  10. Python基本操作(五) 标准数据类型(不可变类型)
  11. 使用C#中的反射从字符串获取属性值
  12. 解决NSTimer循环引用
  13. 计算字符串的相似度-两种解法
  14. C语言的32个基本关键字
  15. python使用有道智云翻译API
  16. 焊接入门——基础知识整理
  17. App 界的一股清流 音视频应有尽有 完全按照 Material design 规范设计的 App
  18. [易飞]付款条件-账期之理解
  19. Android 开源OS
  20. 芯片测试算法及时间复杂度分析

热门文章

  1. 无人驾驶感知篇之激光雷达
  2. flask中的html模板及调用
  3. Unity5网络模块UNet介绍
  4. 世界上最伟大的推销员-羊皮卷之九
  5. 机器学习数据分析之-轮廓系数(评估聚类结果)
  6. .net core 视图文件乱码问题
  7. 使用3DEXPERIENCE云平台建模《冰雪奇缘》雪宝
  8. js删除字符串最后一个字符方法总汇
  9. 【Python】这个列表TTT熟悉
  10. 端到端图像编码和VVC的结合