UNITY_MATRIX_IT_MV[Matrix] (转载)-程序员宅基地

转载 http://blog.csdn.net/cubesky/article/details/38682975

 

前面发了一篇关于unity Matrix的文章。

http://blog.csdn.net/cubesky/article/details/38664143

其中对于一般的Matrix可以说应该有一个清晰的了解了。但是对于UNITY_MATRIX_IT_MV这些matrix估计理解起来还是比较有问题。这里再重点描述一下UNITY_MATRIX_IT_MV。

首先,我们看一下unity中Doc中的描述:

 

UNITY_MATRIX_IT_MV float4x4 Inverse transpose of model * view matrix.

然后我们来看一下UNITY_MATRIX_IT_MV实际的变换意义

 

The transpose of World2Object is the transpose of the inverse of the Object2World matrix.

  • MV transforms points from object to eye space
  • IT_MV rotates normals from object to eye space

And similarly:

  • Object2World transforms points from object to world space
  • IT_Object2World (which, as you point out, is the transpose of World2Object) rotates normals from object to world space

If it is orthogonal, the upper-left 3x3 of Object2World will be equal to that of IT_Object2World, and so will also rotate normals from object to world space.

 

上面这里很好的描述了UNITY_MATRIX_IT_MV的使用场景,专门针对法线进行变换。但是为什么法线的变换和定点不一样呢?让我们来看一篇推导的文章。

 

The gl_NormalMatrix is present in many vertex shaders. In here some light is shed on what is this matrix and what is it for. This section was inspired by the excellent book by Eric Lengyel “Mathematics for 3D Game Programming and Computer Graphics”.

Many computations are done in eye space. This has to do with the fact that lighting is commonly performed in this space, otherwise eye position dependent effects, such as specular lights would be harder to implement.

Hence we need a way to transform the normal into eye space. To transform a vertex to eye space we can write:

	vertexEyeSpace = gl_ModelViewMatrix * gl_Vertex;

So why can’t we just do the same with a normal vector? A normal is a vector of 3 floats and the modelview matrix is 4×4. Secondly, since the normal is a vector, we only want to transform its orientation. The region of the modelview matrix that contains the orientation is the top left 3×3 submatrix. So why not multiply the normal by this submatrix?

This could be easily achieved with the following code:

	normalEyeSpace = vec3(gl_ModelViewMatrix * vec4(gl_Normal,0.0));

So, gl_NormalMatrix is just a shortcut to simplify code writing or to optimize it? No, not really. The above line of code will work in some circumstances but not all.

Lets have a look at a potential problem:

;

In the above figure we see a triangle, with a normal and a tangent vectors. The following figure shows what happens when the modelview matrix contains a non-uniform scale.

Note: if the scale was uniform, then the direction of the normal would have been preserved, The length would have been affected but this can be easily fixed with a normalization.

In the above figure the Modelview matrix was applied to all the vertices as well as to the normal and the result is clearly wrong: the transformed normal is no longer perpendicular to the surface.

We know that a vector can be expressed as the difference between two points. Considering the tangent vector, it can be computed as the difference between the two vertices of the triangle’s edge. If P_1 and P_2 are the vertices that define the edge we know that:

T = P_2 - P_1

Considering that a vector can be written as a four component tuple with the last component set to zero, we can multiply both sides of the equality with the Modelview matrix

T * Modelview = (P_2-P_1)* Modelview

This results in

T * Modelview = P_2 * Modelview - P_1 * ModelviewT' = P_2' - P_1'

As P_1' and P_2' are the vertices of the transformed triangle, T' remains tangent to the edge of the triangle. Hence, the Modelview preserves tangents, yet it does not preserve normals.

Considering the same approach used for vector T, we can find two points Q_1 and Q_2 such that

N = Q_2 - Q_1

The main issue is that the a vector defined through the transformed points, Q_2' - Q_1', does not necessarily remain normal, as shown in the figures above. The normal vector is not defined as a difference between two points, as the tangent vector, it is defined as a vector which is perpendicular to a surface.

So now we know that we can’t apply the Modelview in all cases to transform the normal vector. The question is then, what matrix should we apply?

Consider a 3×3 matrix G, and lets see how this matrix could be computed to properly transform the normal vectors.

We know that, prior to the matrix transformation T.N = 0, since the vectors are by definition perpendicular. We also know that after the transformation N’.T’ must remain equal to zero, since they must remain perpendicular to each other. T can be multiplied safely by the upper left 3×3 submatrix of the modelview (T is a vector, hence the w component is zero), let’s call this submatrix M.

Let’s assume that the matrix G is the correct matrix to transform the normal vector. T. Hence the following equation:

N' . T' = (GN) . (MT) = 0

The dot product can be transformed into a product of vectors, therefore:

(GN).(MT) = (GN)^T * (MT)

Note that the transpose of the first vector must be considered since this is required to multiply the vectors. We also know that the transpose of a multiplication is the multiplication of the transposes, hence:

(GN)^T  (MT) = N^TG^TMT

We started by stating that the dot product between N and T was zero, so if

G^TM = I

then we have

N'.T' = N.T = 0

Which is exactly what we want. So we can compute G based on M.

G^TM = I \Longleftrightarrow G = (M^{-1})^T

Therefore the correct matrix to transform the normal is the transpose of the inverse of the M matrix. OpenGL computes this for us in the gl_NormalMatrix.

In the beginning of this section it was stated that using the Modelview matrix would work in some cases. Whenever the 3×3 upper left submatrix of the Modelview is orthogonal we have:

M^{-1} = M^T \Longrightarrow G = M

This is because with an orthogonal matrix, the transpose is the same as the inverse. So what is an orthogonal matrix? An orthogonal matrix is a matrix where all columns/rows are unit length, and are mutually perpendicular. This implies that when two vectors are multiplied by such a matrix, the angle between them after transformation by an orthogonal matrix is the same as prior to that transformation. Simply put the transformation preserves the angle relation between vectors, hence transformed normals remain perpendicular to tangents! Furthermore it preserves the length of the vectors as well.

So when can we be sure that M is orthogonal? When we limit our geometric operations to rotations and translations, i.e. when in the OpenGL application we only use glRotate and glTranslate and not glScale. These operations guarantee that M is orthogonal. Note: gluLookAt also creates an orthogonal matrix!

注:之所以法线不能直接使用UNITY_MATRIX_MV进行变换,是因为法线是向量,具有方向,在进行空间变换的时候,如果发生非等比缩放,方向会发生偏移。为什么呢?拿上面的例子来说,我们可以简单的把法线和切线当成三角形的两条边,显然,三角形在空间变换的时候,不管是平移,还是旋转,或者是等比缩放,都不会变形,但是如果非等比缩放,就会发生拉伸。所以法线和切线的夹角也就会发生变化。(而切线在变换前后,方向总是正确的,所以法线方向就不正确了)。

参考:

http://www.lighthouse3d.com/tutorials/glsl-tutorial/the-normal-matrix/

http://forum.unity3d.com/threads/_object2world-or-unity_matrix_it_mv.112446/

http://www.cnblogs.com/kesalin/archive/2012/12/06/3D_math.html

转载于:https://www.cnblogs.com/chongxin/p/4519112.html

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_33871366/article/details/94520532

智能推荐

hdu5444(2015长春网络赛H题)-程序员宅基地

题意:给出一棵树的描述,这棵树构造出来,满足从右到左数值递增,根在最下面,然后有一些询问x,我们要输出从根走到x的路径,w:向左、e:向右。思路:建树的时候,首先第一个点一定是根,然后比根小的建在根的右边,反之建在左边,就可以了。代码:#include #include #include #include using namespace std;co

mongo服务器修改密码,mongoDB 修改密码-程序员宅基地

mongodb修改密码方法一,利用db.addUser>db.addUser('tank2','111'){"_id":ObjectId("529e6f1c8d95afd190add450"),"user":"tank2","readOnly":false,"pwd":"6b4334d2c97c526e6a11b2f9ce1996e0"}有人会问,这个不是添加用户的方法吗。..._修改mongo密码

2020-08-29 Flume采集日志数据到kafka_配置flume采集方案,采集目录下(将question_4.txt)文件kafka中作为生产者-程序员宅基地

一、Flume安装Flume的安装使用可以说非常简单,直接进官网:http://flume.apache.org/最新是1.9.0版本,我们选择1.8.0版本下载。然后在Linux下解压:配置用户环境变量:(如果有root权限可以配置在/etc/profile)vim ~/.bashrc1在末尾添加路径:FLUME_HOME=/home/dev/flume/flume-1.8.0PATH=$PATH:$FLUME_HOME/bin1 2source使其生效:_配置flume采集方案,采集目录下(将question_4.txt)文件kafka中作为生产者

es like and or_广东生态所孙蔚旻团队ES&T发表利用稳定同位素示踪宏基因组分箱联用技术揭示砷污染土壤中的厌氧砷氧化微生物及其代谢途径...-程序员宅基地

广东省生态环境技术研究所孙蔚旻团队ES&T发表:利用稳定同位素示踪-宏基因组分箱联用技术揭示砷污染土壤中的厌氧砷氧化微生物及其代谢途径第一作者:张苗苗通讯作者:孙蔚旻通讯单位:广东省生态环境技术研究所论文DOI:10.1021/acs.est.0c01601图文摘要成果简介近日,广东省生态环境技术研究所孙蔚旻研究员课题组在环境领域顶级期刊Environmental Science..._张苗苗 广州生态所

PyQT5之QInputDialog(十四)_pyqt qinputdialog setstylesheet_伊伊_f的博客-程序员宅基地

import sysfrom PyQt5.QtWidgets import QApplication,QWidget,QInputDialog,QPushButton,QLineEdit,QFormLayoutclass inputDialogDemo(QWidget): def __init__(self): super(inputDialogDemo, self).__init__() #create buttons self.butto._pyqt qinputdialog setstylesheet

随便推点

MongoDB复制集全量同步改进_mongodb全量同步-程序员宅基地

MongoDB副本集数据同步方式intial sync,可以理解为全量同步。replication,追同步源的oplog,可以理解为增量同步。下面会详细介绍MongoDB数据同步的实现原理。initial syncSecondary节点当出现如下状况时,需要先进行全量同步。oplog为空。local.replset.minvalid集合里_initialSyncFlag..._mongodb全量同步

Makefile -- 使用函数_makefile 写函数-程序员宅基地

转载http://blog.csdn.net/haoel/article/details/2886 在Makefile中可以使用函数来处理变量,从而让我们的命令或是规则更为的灵活和具有智能。make所支持的函数也不算很多,不过已经足够我们的操作了。函数调用后,函数的返回值可以当做变量来使用。函数的调用语法函数调用,很像变量的使用,也是以“$”来标识的,其语法如下:_makefile 写函数

python安装心得_python安装心得体会-程序员宅基地

python的安装,每个版本有每个版本所对应的工具库,为了使python能安装上对应的工具库,必须慎重考虑安装python的版本。1.python的版本有如下类别:2.7版本,3.4版本,3.5版本,3.6版本32位和64位在安装某一个工具库的时候一定要提前看那个工具库的适用版本,然后选择安装的python的版本。2.在同一个电脑上可以安装不同版本的python,注意事项如下:_python安装心得体会

思科设备DHCP服务器option 82选项与DHCP中继代理的问题-程序员宅基地

思科设备DHCP服务器option 82选项与DHCP中继代理的问题  实验目的:  1.无中继代理时,DHCP向客户端发送地址段和接收接口地址相同的网段,如果不存在相同网段,就会丢弃请求数据包.  2.有中继代理时,服务器能够发送正确IP地址给客户端,是因为有一个被称为option 82的选项,这个选项只要DHCP请求数据包被中继后便会自动添加,此...

FFmpeg 获取h264裸码流_嵌入式ffmpeg硬编码获取h264流-程序员宅基地

原帖链接如下:http://blog.csdn.net/ren65432/article/details/43449391有时候我们需要获取h264裸码流进行分析。本文介绍如何通过FFmpeg 获取h264 码流。获取到的h264码流文件 可以直接通过vlc 等播放器直接播放。一、 .h264文件数据流如下图 是通过WinHex工具 分析的一个.h264文件数据:_嵌入式ffmpeg硬编码获取h264流

求最长公共子序列和最长公共子串-程序员宅基地

题目:有两个字符串(可能包含空格),找出其中最长的公共连续子串,并输出其长度。 输入描述:输入为两行字符串(可能包含空格),长度均小于等于50。输出描述: 输出为一个整数,表示最长公共连续子串的长度。输入例子:abcdeabgde输出例子:2两种参考思路如下:(1)假设两个字符串str1和str2的长度分别为m和n,构建一个矩阵(即二维数组)M[m][n],初始值都设为0,如果字符串str1中第...

推荐文章

热门文章

相关标签