http://richbabe.top/2018/06/27/%E7%94%A8Unity%E5%AE%9E%E7%8E%B0Shadow-Map/
https://blog.csdn.net/liuwumiyuhuiping/article/details/52524317
实验1:
proj = GL.GetGPUProjectionMatrix(proj2, true);
分别作了,不用gl;
用,第二个参数为true;
用,第一个参数为false;
结果如下:
第二个bug的解决:使用commandbuffer的时候,每帧设置rt,清除rt的颜色,绘制,清除命令四个步骤
这样在帧调试器下,就可以进行调试了,否则点不到正常绘制的物体。
具体如下:
m_cb.SetRenderTarget(m_selfShadowRT);
m_cb.ClearRenderTarget(true, true, Color.clear, 1.0f);
Graphics.ExecuteCommandBuffer(m_cb);
m_cb.Clear();
终于搞懂了这个函数的意思:
using UnityEngine;
public class GetGPUProjectionMatrix : MonoBehaviour
{
private int w = 2;
private int h = 2;
private int n = 4;
private int f = 60;
private float z = -10;
void Start()
{
Matrix4x4 m = Matrix4x4.Ortho(-w, w, -h, h, n, f);
Debug.LogError(m);
Vector3 p = m.MultiplyPoint3x4(new Vector3(0, 0, z));
Debug.LogError(p);
Matrix4x4 mm = GL.GetGPUProjectionMatrix(m, true);
Debug.LogError(m.inverse * mm);
}
}
那个GL.GetGPUProjectionMatrix函数,是对原始的opengl的p矩阵,做了红色矩阵的操作,然后转换到1到0的范围。
推导全靠猜测,用转换后的矩阵,然后得到其逆矩阵,最后加上拍脑袋,果然最后构建出了这个红色矩阵。经过验证是正确的。
并且是如果传入false的话,只是y不反转。传入true,则对y进行翻转操作。
我的验算过程:
下面我们再来验证下这个结论是否正确。
此时的宽高比为2:1,这里的size=2,表示view视口的高度一半为2,所以宽度一半为4。
摄像机是正交投影,按照opengl的透视矩阵公式得到的透视矩阵应该为:
这个计算处理的矩阵为:
此时,程序构建的正交矩阵为:
public class VerifyGL : MonoBehaviour
{
private void Start()
{
int w = 4;
int h = 2;
int n = 1;
int f = 100;
Matrix4x4 m = Matrix4x4.Ortho(-w, w, -h, h, n, f);
Debug.LogError(m);
}
}
可见我们的推测是正确的。
我们在看看view矩阵是多少:
Matrix4x4 m2 = Camera.main.worldToCameraMatrix;
Debug.LogError(m2);
这个为啥是这样呢?因为摄像机的right=(1,0,0) up=(0,1,0),而forward是z的负方向,所以是(0,0,-1)。
我们自己尝试构建vp矩阵为:
我们看看这个和unity中的矩阵是否相同呢?
很遗憾,不相同,那么我们用之前的那个红色矩阵乘下之后呢?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class VerifyGL : MonoBehaviour
{
private void Start()
{
int w = 4;
int h = 2;
int n = 1;
int f = 100;
Matrix4x4 m = Matrix4x4.Ortho(-w, w, -h, h, n, f);
Debug.LogError(m);
Matrix4x4 m2 = Camera.main.worldToCameraMatrix;
Debug.LogError(m2);
Matrix4x4 m3 = m * m2;
Debug.LogError(m3);
Matrix4x4 m4 = Matrix4x4.identity;
m4[1, 1] = -1;
m4[2, 2] = -0.5f;
m4[2, 3] = -100 - 0.5f * 1; //-f-0.5n
Matrix4x4 m5 = (m * m4) * m2; //m为原始透视矩阵,m4为红色矩阵,m2为view矩阵
Debug.LogError(m5);
}
}
可以看到,这个y是相反的,我们记得,使用GL.GetGPUProjectionMatrix(m, false);
第二个参数为false,则y不进行反转,所以此时红色的矩阵m[1,1]=1,不用等于-1即可。
即:
Matrix4x4 m4 = Matrix4x4.identity;
//m4[1, 1] = -1;
m4[2, 2] = -0.5f;
m4[2, 3] = -100 - 0.5f * 1; //-f-0.5n
Matrix4x4 m5 = (m * m4) * m2; //m为原始透视矩阵,m4为红色矩阵,m2为view矩阵
Debug.LogError(m5);
综上:
1、当 GL.GetGPUProjectionMatrix(m, false);则是相当于对m矩阵乘以下面矩阵的操作:
2、当 GL.GetGPUProjectionMatrix(m, true);则是相当于对m矩阵乘以下面矩阵的操作:
3、unity默认是GL.GetGPUProjectionMatrix(m, false);即,y不反正,但是z映射到了1到0范围。
这个红色矩阵就是将视空间的z,映射到屏幕空间的1到0范围。
如果不进行这个GetGPUProjectionMatrix操作,则对于opengl来说视空间的z映射到了-1到1之间。
下面讨论的一个问题是:片元着色器是否需要透视除法的操作。
// Tranforms position from object to homogenous space
inline float4 UnityObjectToClipPos(in float3 pos)
{
#if defined(STEREO_CUBEMAP_RENDER_ON)
return UnityObjectToClipPosODS(pos);
#else
// More efficient than computing M*VP matrix product
return mul(UNITY_MATRIX_VP, mul(unity_ObjectToWorld, float4(pos, 1.0)));
#endif
}
由此可以看出UnityObjectToClipPos,之后,返回的坐标其w分量还是z,即在view空间的z值。
那么需要透视除法,之后才能得到NDC坐标。