GitHub项目地址
平面反射的实现步骤:
1、抓取屏幕图像——渲染纹理RenderTexture+额外摄像机
2、反射矩阵(ReflectMatrix)——获得反射的屏幕图像
3、斜裁剪矩阵(ObliqueMatrix)——裁剪掉反射平面以下的部分
4、高斯模糊——模糊反射的倒影
5、将反射纹理渲染到地面
1、抓取屏幕图像
之前的文章已经提过了,抓取屏幕图像有两种方法:
1、GrabPass
2、渲染纹理RenderTexture+额外摄像机
这里需要使用第二种方法:
private Camera mainCamera, reflectCamera;
private RenderTexture reflectTex;
private Renderer render;
private Material reflectMaterial;
void Start()
{
mainCamera = Camera.main;
GameObject go = new GameObject("ReflectCamera", typeof(Camera));
reflectCamera = go.GetComponent<Camera>();
reflectCamera.fieldOfView = mainCamera.fieldOfView;
reflectCamera.aspect = mainCamera.aspect;
reflectCamera.cullingMask = mainCamera.cullingMask;
//自己控制渲染的层级
//reflectCamera.cullingMask = 1 << LayerMask.NameToLayer("Player");
reflectCamera.enabled = false;
reflectTex = RenderTexture.GetTemporary(1024, 1024, 24);
reflectCamera.targetTexture = reflectTex;
render = GetComponent<Renderer>();
reflectMaterial = render.sharedMaterial;
}
2、反射矩阵(ReflectMatrix)
顶点反射反射矩阵
反射矩阵的推导过程https://zhuanlan.zhihu.com/p/92633614
//计算plane平面的反射矩阵
private void CalculateReflectMatrix(ref Matrix4x4 matrix, Vector4 plane)
{
matrix.m00 = (1F - 2F * plane[0] * plane[0]);
matrix.m01 = (-2F * plane[0] * plane[1]);
matrix.m02 = (-2F * plane[0] * plane[2]);
matrix.m03 = (-2F * plane[3] * plane[0]);
matrix.m10 = (-2F * plane[1] * plane[0]);
matrix.m11 = (1F - 2F * plane[1] * plane[1]);
matrix.m12 = (-2F * plane[1] * plane[2]);
matrix.m13 = (-2F * plane[3] * plane[1]);
matrix.m20 = (-2F * plane[2] * plane[0]);
matrix.m21 = (-2F * plane[2] * plane[1]);
matrix.m22 = (1F - 2F * plane[2] * plane[2]);
matrix.m23 = (-2F * plane[3] * plane[2]);
}
3、斜裁剪矩阵(ObliqueMatrix)
需要裁减红色部分Unity已经为我们提供了获取斜裁减矩阵的方法CalculateObliqueMatrix,我们只需要注意这个方法的参数是视图空间的平面。
//为了反射相机近裁剪平面紧贴我们的反射平面,防止错误渲染
//我们需要重新计算反射相机的投影矩阵,斜裁剪矩阵(ObliqueMatrix)
Vector4 viewPlane = CameraSpacePlane(reflectCamera.worldToCameraMatrix, transform.position, normal);
reflectCamera.projectionMatrix = reflectCamera.CalculateObliqueMatrix(viewPlane);
//计算视图空间的平面
private Vector4 CameraSpacePlane(Matrix4x4 worldToCameraMatrix, Vector3 pos, Vector3 normal)
{
Vector3 viewPos = worldToCameraMatrix.MultiplyPoint3x4(pos);
Vector3 viewNormal = worldToCameraMatrix.MultiplyVector(normal).normalized;
float w = -Vector3.Dot(viewPos, viewNormal);
return new Vector4(viewNormal.x, viewNormal.y, viewNormal.z, w);
}
斜裁剪矩阵的推导过程https://zhuanlan.zhihu.com/p/92633614
4、高斯模糊
高斯模糊我前面的文章已经介绍过了,这里不详细写了。
平面反射+高斯模糊
5、将反射纹理渲染到地面
最后一步,我们需要将获取到的反射纹理渲染到地面。
我们只需要在渲染地面的时候,叠加反射纹理即可。
sampler2D _ReflectTex;
//vert
o.uvReflect = ComputeScreenPos(o.vertex);
//frag
fixed4 reflectCol = tex2Dproj(_ReflectTex, i.uvReflect);
网友评论