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


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());
        }

    }
}


猜你喜欢

转载自blog.csdn.net/u012149999/article/details/78673536