您的位置:首页 > 移动开发 > Unity3D

Unity3d 空间变换中齐次矩阵的w小秘密

2017-11-30 11:03 1511 查看
1.使用变换齐次矩阵与某个齐次坐标相乘得到的结果.

2.使用结果中的w分量,进行齐次除法得到归一化后的齐次坐标.

3.用变换齐次矩阵的逆矩阵与归一化后的齐次坐标相乘(注意我们是用归一化后的齐次坐标,不是上面第一步变换后的齐次坐标),的到还原后的齐次矩阵,其w分量将会有一个特殊的值.

4.如果将还原后的齐次矩阵使用其w分量进行齐次除法,将得到我们最开始用于变换的齐次坐标,彻底还原还原

代数式表示为:

M*V=>V/V.w=V"

M逆*V"=V"/V".w=V

具体为何会有如此结果,尚不清楚,但是Unity中广泛的应用了次齐次矩阵此种特性,特别是在Fragment的空间还原方法上

测试代码如下

public class NDC_Position : MonoBehaviour {

bool m_isShow = false;
// Use this for initialization
void Start () {

}

// Update is called once per frame
void Update () {

if (!m_isShow)
{
m_isShow = true;

//直接使用世界坐标,这样可以方便测试
//建立世界空间到clip空间的变换矩阵
Matrix4x4 _vp = Camera.main.projectionMatrix * Camera.main.worldToCameraMatrix;
//建立clip空间到世界空间的逆矩阵
Matrix4x4 _vpInverse = _vp.inverse;

Debug.Log("Camera.main.worldToCameraMatrix----\r\n" + _vp.ToString() + "\r\n-------------------------");

Debug.Log("Camera.main.projectionMatrix----\r\n" + Camera.main.projectionMatrix.ToString()+"\r\n-------------------------");

Debug.Log("_vp----\r\n" + _vp.ToString() + "\r\n-------------------------");

Debug.Log("_vpInverse----\r\n" + _vpInverse.ToString() + "\r\n-------------------------");

//手动使用齐次坐标来变换,已查看变换后的w分量
Vector4 _ClipPos = _vp*(new Vector4(transform.position.x, transform.position.y, transform.position.z,1));
Debug.Log("齐次 _ClipPos4=" + _ClipPos.x.ToString() + "," + _ClipPos.y.ToString() + "," + _ClipPos.z.ToString()+","+ _ClipPos.w.ToString() + "=>" + _ClipPos.ToString());

//直接使用非齐次坐标,这样unity3d会自动帮你转换成齐次坐标,变换后自动帮你做齐次除法,最终得到NDC坐标
Vector3 _NDCPos = _vp.MultiplyPoint(transform.position); //因为只返回前三个坐标,所以已经做了齐次除法处理,结果是直接返回了NDC坐标
Debug.Log("齐次除后 _ClipPos=" + _NDCPos.x.ToString()+","+ _NDCPos.y.ToString()+","+ _NDCPos.z.ToString()+"=>"+ _NDCPos.ToString());

//使用clip空间齐次坐标还原
Vector4 _worldPos4 = _vpInverse * (new Vector4(_ClipPos.x, _ClipPos.y, _ClipPos.z, _ClipPos.w));
Debug.Log("齐次还原 _worldPos4=[" + _ClipPos.x.ToString() + ", " + _ClipPos.y.ToString() + ", " + _ClipPos.z.ToString() +", "+ _ClipPos.w.ToString()+ ", 1]=>" + _worldPos4.x.ToString() + ", " + _worldPos4.y.ToString() + ", " + _worldPos4.z.ToString() + ", " + _worldPos4.w.ToString()+"=>"+ _worldPos4.ToString());

//直接使用NDC齐次坐标还原,已查看变换后的w分量
Vector4 _worldPos3 = _vpInverse * (new Vector4(_NDCPos.x, _NDCPos.y, _NDCPos.z,1));
Debug.Log("非齐次还原 _worldPos3=[" + _NDCPos.x.ToString() + ", "+ _NDCPos.y.ToString() + ", "+ _NDCPos.z.ToString()+", 1]=>" + _worldPos3.x.ToString() + ", " + _worldPos3.y.ToString() + ", " + _worldPos3.z.ToString() + ", " + _worldPos3.w.ToString() + "=>" + _worldPos3.ToString());

//Unity3d自动使用NDC齐次坐标还原,返回已经进行了齐次除法后的结果
Vector3 _worldPos = _vpInverse.MultiplyPoint(_NDCPos);
Debug.Log("非齐次还原 _worldPos=" + _worldPos.x.ToString() + ", " + _worldPos.y.ToString() + ", " + _worldPos.z.ToString()+"=>" + _worldPos.ToString());
}

}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息