unity3dunity matrix mvp4x4中最后一行表示什么

Converting Matrix4x4 to Quaternion & Vector3 - Unity Answers
Navigation
Unity account
You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio.
Converting Matrix4x4 to Quaternion & Vector3
I'm attempting to convert a Matrix4x4 which is being currently being applied to a camera using camera.worldToCameraMatrix and works fine.
I'm able to get the position out with:
Vector4 newCameraPos = matrix.GetColumn(3);
Camera.main.transform.position = Vector3(newCameraPos.x,newCameraPos.y,newCameraPos.z);
But at the moment can't get the quaternion to come out. I've pulled some code from a
I stumbled across and have partially implemented, but at the moment its not behaving.
Quaternion matrixToQuaternionx(Matrix4x4 m1){ float T = 1 + m1[0] + m1[5] + m1[10];
Quaternion q = Quaternion.
if ( T & 0.f ){
float S = Mathf.Sqrt(T) * 2;
q.x = ( m1[9] - m1[6] ) / S;
q.y = ( m1[2] - m1[8] ) / S;
q.z = ( m1[4] - m1[1] ) / S;
q.w = 0.25f * S;
Debug.Log(&more to calculate here&);
If I turn off the camera.worldToCameraMatrix, and rely on the Vector and Quaternion I get out (ignoring cases where it gets to the 'more to calculate here') the position of the camera looks fine, but its rotation is way off.
Best Answer
For getting a quaternion from a Matrix4x4, this function works:
public static Quaternion QuaternionFromMatrix(Matrix4x4 m) {
// Adapted from: /maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
Quaternion q = new Quaternion();
q.w = Mathf.Sqrt( Mathf.Max( 0, 1 + m[0,0] + m[1,1] + m[2,2] ) ) / 2;
q.x = Mathf.Sqrt( Mathf.Max( 0, 1 + m[0,0] - m[1,1] - m[2,2] ) ) / 2;
q.y = Mathf.Sqrt( Mathf.Max( 0, 1 - m[0,0] + m[1,1] - m[2,2] ) ) / 2;
q.z = Mathf.Sqrt( Mathf.Max( 0, 1 - m[0,0] - m[1,1] + m[2,2] ) ) / 2;
q.x *= Mathf.Sign( q.x * ( m[2,1] - m[1,2] ) );
q.y *= Mathf.Sign( q.y * ( m[0,2] - m[2,0] ) );
q.z *= Mathf.Sign( q.z * ( m[1,0] - m[0,1] ) );
For getting the position, GetColumn(3) works fine.
Here's a faster and easier solution:
public static Quaternion QuaternionFromMatrix(Matrix4x4 m) { return Quaternion.LookRotation(m.GetColumn(2), m.GetColumn(1)); }
Actually I can confirm that the
&For getting a quaternion from a Matrix4x4, this function works: ...&
Doesn't work, and the
&Here's a faster and easier solution: ...&
I'm making a voxel engine that performs all sorts of transforms and the first method produces:
While the second funci&n produces
And the control test uses Graphics.DrawMesh() with the matrix transform as a parameter
Hint: You can notify a user about this post by typing @username
Attachments: Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.
4 People are following this question.&&国之画&&&& &&&&&&
&& &&&&&&&&&&&&&&&&&&
鲁ICP备号-4
打开技术之扣,分享程序人生!Unity3D(11)
public Vector3&MultiplyPoint3x4(Vector3&v);
通过指定的矩阵来变换向量v
下面的代码是通过矩阵m来变换v
void Start () {
Matrix4x4 m = Matrix4x4.
Vector3 v = Vector3.
Vector3 v2 = m.MultiplyPoint3x4(v);
public Vector3&MultiplyVector(Vector3&v);
通过指定的矩阵来变换向量v,只改变向量的方向
public void SetTRS(Vector3 pos, Quaternion q, Vector3 s);
功能:用来重设Matrix4*4矩阵
参数:pos 位置向量
& &q 旋转角度
& &s 缩放向量
我们可以这么写代码
Matrix4x4 m1 = Matrix4x4.
m1.SetTRS(pos, q, s);
Vector3 v2 =&m1.MultiplyPoint3x4(v1);
下面看看如何把向量v1沿y轴增加5个单位,绕y轴旋转45度,缩放2倍
public class SetTRS : MonoBehaviour
// Use this for initialization
Vector3 v1 = Vector3.
Vector3 v2 = Vector3.
void Start()
Matrix4x4 m1 = Matrix4x4.
//Position沿y轴增加5个单位,绕y轴旋转45度,缩放2倍
m1.SetTRS(Vector3.up * 5, Quaternion.Euler(Vector3.up * 45.0f), Vector3.one * 2.0f);
//也可以使用如下静态方法设置m1变换
//m1=Matrix4x4.TRS(Vector3.up * 5, Quaternion.Euler(Vector3.up * 45.0f),Vector3.one*2.0f);
v2 = m1.MultiplyPoint3x4(v1);
void FixedUpdate()
Debug.DrawLine(Vector3.zero, v1, Color.green);
Debug.DrawLine(Vector3.zero, v2, Color.red);
其中绿色线是v1,红色线是v1沿y轴增加5个单位,绕y轴旋转45度,缩放2倍的效果
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:6924次
排名:千里之外
原创:61篇
文章:10篇
阅读:2519
(12)(2)(4)(10)(5)(6)(9)(14)转载地址:&
在Unity开发中时常会用到Matrix4x4矩阵来变换场景中对象的位置、旋转和缩放。但是很多人都不太理解这儿Matrix4x4变换矩阵。通过DX中的变换矩阵我来讲一讲在unity中这个变换矩阵是怎么变换的。
在三维图形程序中,我们可以用几何变换来达到以下目的:
表示一个对象相对于另一个对象的位置。
旋转和安排对象的大小。
改变视维、方向和透视方法。
  你可以使用一个4×4的矩阵将任何点变换到另一个点。下面的例子中,我们用一个矩阵对点(x, y, z)进行变化,产生了一个新的点(x', y', z'):
  对点(x, y, z)进行一下运算,会得到一个新点(x', y', z'):
  最常用的变换包括:平移(translation),旋转(rotation)和缩放(scaling)。你可以将这些变换合并起来,组成一个矩阵,同时进行几种变换。
矩阵以行列号的形式来描述。
沿每个坐标轴同时进行缩放时(我们称为统一缩放uniform scaling),矩阵如下所示:
下面的变化将一个点(x, y, z)平移到另一个点(x', y', z'):
下面的变换将一个点(x, y, z)沿x-轴进行旋转,得到了一个新的点(x', y', z'):
  下面的变化沿y-轴进行旋转:
  下面的变换沿z-轴进行旋转:
  这里要注意一点,希腊字母θ代表旋转的角度,用弧度来表示。从旋转轴向原点看,这个角度按顺时针方向来度量。
我们使用矩阵的一个最大好处就是可以通过矩阵相乘来将几个矩阵变换的效果合并起来。这就是说,当我们对一个模型进行旋转和平移时,不再需要用到两个矩阵。我们可以通过将旋转矩阵与平移矩阵相乘来得到一个合并的矩阵。这一过程就被称为矩阵级联,可以用下面的公式来表示:
  共识中,C指组合之后产生的新矩阵,M1到Mn表示要组合在一起的每一个矩阵。一般情况下,我们指将两或三个矩阵组合起来,但实际上是没有限制的。  中有一个.operator
*&辅助函数来进行矩阵级联运算。  在进行矩阵级联时,我们应该注意级联时的顺序。上面公式&中反映的是一种从右到左的矩阵级联规则。也就是说,我们用来创建一个合并的矩阵的每个矩阵的实际效果是从右到左依次出现的。下面我们举一个例子来说明这一&情况。在这个例子中,我们要通过世界变换矩阵来创建一个“飞碟”。我们想要这个UFO沿中心(模型空间的y-轴)来旋转,同时要在场景中平移。为了达到这样的效果,你可以首先创建一个平移矩阵,然后用它和旋转矩阵相乘,如下所示:W=Tw·Ry  公式中,Tw表示平移矩阵,Ry表示旋转矩阵。  两个矩阵相乘的顺序是很重要的,与标量的相乘不同,矩阵相乘的顺序是不能交换的。如果我们将两个矩阵的顺序交换的话,得到的结果就会是,先对飞碟进行平移,然后将它绕世界原点进行旋转。  无论我们创建什么类型的矩阵,都要按照从右到左的顺序,这样才能达到我们预期的结果。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:407次
排名:千里之外
(1)(1)(2)(4)(2)Unity里有两种动态加载机制:一是Resources.Load,一是通过AssetBundle,其实两者本质上我理解没有什么区别。Resources.Load就是从一个缺省打进程序包里的AssetBundle里加载资源,而一般AssetBundle文件需要你自己创建,运行时动态加载,可以指定路径和来源的。
其实场景里所有静态的对象也有这么一个加载过程,只是Unity后台替你自动完成了。
详细说一下细节概念:
AssetBundle运行时加载:
来自文件就用CreateFromFile(注意这种方法只能用于standalone程序)这是最快的加载方法
也可以来自Memory,用CreateFromMemory(byte[]),这个byte[]可以来自文件读取的缓冲,www的下载或者其他可能的方式。
其实WWW的assetBundle就是内部数据读取完后自动创建了一个assetBundle而已
Create完以后,等于把硬盘或者网络的一个文件读到内存一个区域,这时候只是个AssetBundle内存镜像数据块,还没有Assets的概念。
Assets加载:
用AssetBundle.Load(同Resources.Load) 这才会从AssetBundle的内存镜像里读取并创建一个Asset对象,创建Asset对象同时也会分配相应内存用于存放(反序列化)
异步读取用AssetBundle.LoadAsync
也可以一次读取多个用AssetBundle.LoadAll
AssetBundle的释放:
AssetBundle.Unload(flase)是释放AssetBundle文件的内存镜像,不包含Load创建的Asset内存对象。
AssetBundle.Unload(true)是释放那个AssetBundle文件内存镜像和并销毁所有用Load创建的Asset内存对象。
一个Prefab从assetBundle里Load出来 里面可能包括:Gameobject transform mesh texture material shader script和各种其他Assets。
你Instantiate一个Prefab,是一个对Assets进行Clone(复制)+引用结合的过程,GameObject transform 是Clone是新生成的。其他mesh / texture / material / shader 等,这其中些是纯引用的关系的,包括:Texture和TerrainData,还有引用和复制同时存在的,包括:Mesh/material/PhysicMaterial。引用的Asset对象不会被复制,只是一个简单的指针指向已经Load的Asset对象。这种含糊的引用加克隆的混合,大概是搞糊涂大多数人的主要原因。
专门要提一下的是一个特殊的东西:Script Asset,看起来很奇怪,Unity里每个Script都是一个封闭的Class定义而已,并没有写调用代码,光Class的定义脚本是不会工作的。其实Unity引擎就是那个调用代码,Clone一个script asset等于new一个class实例,实例才会完成工作。把他挂到Unity主线程的调用链里去,Class实例里的OnUpdate OnStart等才会被执行。多个物体挂同一个脚本,其实就是在多个物体上挂了那个脚本类的多个实例而已,这样就好理解了。在new class这个过程中,数据区是复制的,代码区是共享的,算是一种特殊的复制+引用关系。
你可以再Instantiate一个同样的Prefab,还是这套mesh/texture/material/shader...,这时候会有新的GameObject等,但是不会创建新的引用对象比如Texture.
所以你Load出来的Assets其实就是个数据源,用于生成新对象或者被引用,生成的过程可能是复制(clone)也可能是引用(指针)
当你Destroy一个实例时,只是释放那些Clone对象,并不会释放引用对象和Clone的数据源对象,Destroy并不知道是否还有别的object在引用那些对象。
等到没有任何游戏场景物体在用这些Assets以后,这些assets就成了没有引用的游离数据块了,是UnusedAssets了,这时候就可以通过Resources.UnloadUnusedAssets来释放,Destroy不能完成这个任务,AssetBundle.Unload(false)也不行,AssetBundle.Unload(true)可以但不安全,除非你很清楚没有任何对象在用这些Assets了。
虽然都叫Asset,但复制的和引用的是不一样的,这点被Unity的暗黑技术细节掩盖了,需要自己去理解。
关于内存管理
按照传统的编程思维,最好的方法是:自己维护所有对象,用一个Queue来保存所有object,不用时该Destory的,该Unload的自己处理。
但这样在C# .net框架底下有点没必要,而且很麻烦。
稳妥起见你可以这样管理
先建立一个AssetBundle,无论是从www还是文件还是memory
用AssetBundle.load加载需要的asset
加载完后立即AssetBundle.Unload(false),释放AssetBundle文件本身的内存镜像,但不销毁加载的Asset对象。(这样你不用保存AssetBundle的引用并且可以立即释放一部分内存)
如果有Instantiate的对象,用Destroy进行销毁
在合适的地方调用Resources.UnloadUnusedAssets,释放已经没有引用的Asset.
如果需要立即释放内存加上GC.Collect(),否则内存未必会立即被释放,有时候可能导致内存占用过多而引发异常。
这样可以保证内存始终被及时释放,占用量最少。也不需要对每个加载的对象进行引用。
当然这并不是唯一的方法,只要遵循加载和释放的原理,任何做法都是可以的。
系统在加载新场景时,所有的内存对象都会被自动销毁,包括你用AssetBundle.Load加载的对象和Instaniate克隆的。但是不包括AssetBundle文件自身的内存镜像,那个必须要用Unload来释放,用.net的术语,这种数据缓存是非托管的。
总结一下各种加载和初始化的用法:
AssetBundle.CreateFrom.....:创建一个AssetBundle内存镜像,注意同一个assetBundle文件在没有Unload之前不能再次被使用
WWW.AssetBundle:同上,当然要先new一个再 yield return 然后才能使用
AssetBundle.Load(name):从AssetBundle读取一个指定名称的Asset并生成Asset内存对象,如果多次Load同名对象,除第一次外都只会返回已经生成的Asset对象,也就是说多次Load一个Asset并不会生成多个副本(singleton)。
Resources.Load(path&name):同上,只是从默认的位置加载。
Instantiate(object):Clone一个object的完整结构,包括其所有Component和子物体(详见官方文档),浅Copy,并不复制所有引用类型。有个特别用法,虽然很少这样用,其实可以用Instantiate来完整的拷贝一个引用类型的Asset,比如Texture等,要拷贝的Texture必须类型设置为Read/Write able。
总结一下各种释放
Destroy:主要用于销毁克隆对象,也可以用于场景内的静态物体,不会自动释放该对象的所有引用。虽然也可以用于Asset,但是概念不一样要小心,如果用于销毁从文件加载的Asset对象会销毁相应的资源文件!但是如果销毁的Asset是Copy的或者用脚本动态生成的,只会销毁内存对象。
AssetBundle.Unload(false):释放AssetBundle文件内存镜像
AssetBundle.Unload(true):释放AssetBundle文件内存镜像同时销毁所有已经Load的Assets内存对象
Reources.UnloadAsset(Object):显式的释放已加载的Asset对象,只能卸载磁盘文件加载的Asset对象
Resources.UnloadUnusedAssets:用于释放所有没有引用的Asset对象
GC.Collect()强制垃圾收集器立即释放内存 Unity的GC功能不算好,没把握的时候就强制调用一下
在3.5.2之前好像Unity不能显式的释放Asset
举两个例子帮助理解
一个常见的错误:你从某个AssetBundle里Load了一个prefab并克隆之:obj = Instantiate(AssetBundle1.Load('MyPrefab”);
这个prefab比如是个npc
然后你不需要他的时候你用了:Destroy(obj);你以为就释放干净了
其实这时候只是释放了Clone对象,通过Load加载的所有引用、非引用Assets对象全都静静静的躺在内存里。
这种情况应该在Destroy以后用:AssetBundle1.Unload(true),彻底释放干净。
如果这个AssetBundle1是要反复读取的 不方便Unload,那可以在Destroy以后用:Resources.UnloadUnusedAssets()把所有和这个npc有关的Asset都销毁。
当然如果这个NPC也是要频繁创建 销毁的 那就应该让那些Assets呆在内存里以加速游戏体验。
由此可以解释另一个之前有人提过的话题:为什么第一次Instantiate一个Prefab的时候都会卡一下,因为在你第一次Instantiate之前,相应的Asset对象还没有被创建,要加载系统内置的AssetBundle并创建Assets,第一次以后你虽然Destroy了,但Prefab的Assets对象都还在内存里,所以就很快了。
从磁盘读取一个1.unity3d文件到内存并建立一个AssetBundle1对象
AssetBundle AssetBundle1 = AssetBundle.CreateFromFile(&1.unity3d&);
从AssetBundle1里读取并创建一个Texture Asset,把obj1的主贴图指向它
obj1.renderer.material.mainTexture = AssetBundle1.Load(&wall&) as T
把obj2的主贴图也指向同一个Texture Asset
obj2.renderer.material.mainTexture =obj1.renderer.material.mainT
Texture是引用对象,永远不会有自动复制的情况出现(除非你真需要,用代码自己实现copy),只会是创建和添加引用
如果继续:
AssetBundle1.Unload(true) 那obj1和obj2都变成黑的了,因为指向的Texture Asset没了
AssetBundle1.Unload(false) 那obj1和obj2不变,只是AssetBundle1的内存镜像释放了
Destroy(obj1),//obj1被释放,但并不会释放刚才Load的Texture
如果这时候:
Resources.UnloadUnusedAssets();
不会有任何内存释放 因为Texture asset还被obj2用着
Destroy(obj2)
obj2被释放,但也不会释放刚才Load的Texture
Resources.UnloadUnusedAssets();
这时候刚才load的Texture Asset释放了,因为没有任何引用了
最后CG.Collect();
强制立即释放内存
由此可以引申出论坛里另一个被提了几次的问题,如何加载一堆大图片轮流显示又不爆掉
不考虑AssetBundle,直接用www读图片文件的话等于是直接创建了一个Texture Asset
假设文件保存在一个List里
TLlist&string& fileL
IEnumerator OnClick()
WWW image = new www(fileList[n++]);
obj.mainTexture = image.
n = (n&=fileList.Length-1)?0:n;
Resources.UnloadUnusedAssets();
这样可以保证内存里始终只有一个巨型Texture Asset资源,也不用代码追踪上一个加载的Texture Asset,但是速度比较慢
IEnumerator OnClick()
WWW image = new www(fileList[n++]);
Texture tex = obj.mainT
obj.mainTexture = image.
n = (n&=fileList.Length-1)?0:n;
Resources.UnloadAsset(tex);
这样卸载比较快
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:17721次
排名:千里之外
转载:14篇

我要回帖

更多关于 qmatrix4x4 的文章

 

随机推荐