知识点概括
M(model_matrix)模型空间转世界空间矩阵 worldToCameraMatrix
R(reflac_matrix)反射矩阵 平面的法线向量及平面上的一个点可求得
V(view_matrix)世界空间转摄像机空间矩阵 CameraToworldMatrix
P(project_matrix)摄像机矩阵转剪裁空间矩阵 斜视椎体投影与剪裁面求得
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MirrorReflaction : MonoBehaviour {
private Camera RefCamera;
private Material RefMat;
private RenderTexture ReflTex;
private Transform Panel;
private string ReflectTextureName = "_ReflectTex";
public float clipPlaneOffset = 0;
// Use this for initialization
void Start () {
if (null == RefCamera)
{
GameObject go = new GameObject();
go.name = "reflCamera";
RefCamera = go.AddComponent<Camera>();
RefCamera.CopyFrom(Camera.main);
//RefCamera.fieldOfView *= 1.1f;
RefCamera.enabled = false;
RefCamera.clearFlags = CameraClearFlags.SolidColor;
RefCamera.backgroundColor = new Color(0, 0, 0, 0);
RefCamera.cullingMask = ~(1 << LayerMask.NameToLayer("Water"));//去除该层
}
if (null == RefMat)
{
RefMat = this.GetComponent<Renderer>().sharedMaterial;
}
if (null == ReflTex)
ReflTex = new RenderTexture(Mathf.FloorToInt(Camera.main.pixelWidth * 0.5f),
Mathf.FloorToInt(Camera.main.pixelHeight * 0.5f), 24);
ReflTex.hideFlags = HideFlags.DontSave;//保留对象到新场景
RefCamera.targetTexture = ReflTex;
if (null == Panel)
{
Panel = transform;
}
}
public void OnWillRenderObject()//当渲染物体之前
{
RenderRefection();
}
void RenderRefection()
{
Vector3 normal = Panel.up;
float d = -Vector3.Dot(normal, Panel.position);
//反射矩阵
Matrix4x4 refMatrix = new Matrix4x4();
refMatrix.m00 = 1 - 2 * normal.x * normal.x;
refMatrix.m01 = -2 * normal.x * normal.y;
refMatrix.m02 = -2 * normal.x * normal.z;
refMatrix.m03 = -2 * d * normal.x;
refMatrix.m10 = -2 * normal.x * normal.y;
refMatrix.m11 = 1 - 2 * normal.y * normal.y;
refMatrix.m12 = -2 * normal.y * normal.z;
refMatrix.m13 = -2 * d * normal.y;
refMatrix.m20 = -2 * normal.x * normal.z;
refMatrix.m21 = -2 * normal.y * normal.z;
refMatrix.m22 = 1 - 2 * normal.z * normal.z;
refMatrix.m23 = -2 * d * normal.z;
refMatrix.m30 = 0;
refMatrix.m31 = 0;
refMatrix.m32 = 0;
refMatrix.m33 = 1;
//1.M(model_matrix)将点从物体坐标系转换到世界坐标系
//2.进行世界坐标系下将顶点转换到反射点的反射矩阵(在世界坐标系下平面的法线向量和d(d可以通过平面上任意一点求得))
//3.V(view_matrix)表示将点从世界坐标系变换到视点坐标系(摄像机坐标系)
//4.P(project_matrix)表示将点从视点坐标系转换到裁剪坐标系
//从世界空间转为摄像机空间
RefCamera.worldToCameraMatrix = Camera.main.worldToCameraMatrix * refMatrix;
RefCamera.transform.position = refMatrix.MultiplyPoint(Camera.main.transform.position);
Vector3 forward = Camera.main.transform.forward;
// Vector3 up = Camera.main.transform.up;
forward = refMatrix.MultiplyVector(forward);
// up = refMatrix.MultiplyVector (up);
// Quaternion refQ = Quaternion.LookRotation (forward, up);
// RefCamera.transform.rotation = refQ;
RefCamera.transform.forward = forward;
//
Matrix4x4 projM = RefCamera.projectionMatrix;
//裁剪面
Vector4 clipPlane = CameraSpacePlane(RefCamera, Panel.position, Panel.up, 1);
//裁剪空间矩阵
RefCamera.projectionMatrix = CalculateObliqueMatrix(projM, clipPlane);
GL.invertCulling = true;
RefCamera.Render();
GL.invertCulling = false;
RefCamera.targetTexture.wrapMode = TextureWrapMode.Repeat;
RefMat.SetTexture(ReflectTextureName, RefCamera.targetTexture);
}
//摄像机视空间剪裁面
Vector4 CameraSpacePlane(Camera cam, Vector3 pos, Vector3 normal, float sideSign)
{
Vector3 offsetPos = pos + normal * clipPlaneOffset;
Matrix4x4 m = cam.worldToCameraMatrix;
Vector3 cpos = m.MultiplyPoint(offsetPos);
Vector3 cnormal = m.MultiplyVector(normal).normalized * sideSign;
return new Vector4(cnormal.x, cnormal.y, cnormal.z, -Vector3.Dot(cpos, cnormal));
}
public static float Sgn(float a)
{
if (a > 0.0F)
{
return 1.0F;
}
if (a < 0.0F)
{
return -1.0F;
}
return 0.0F;
}
//斜视椎体投影与剪裁面
public static Matrix4x4 CalculateObliqueMatrix(Matrix4x4 projection, Vector4 clipPlane)
{
Vector4 q = projection.inverse * new Vector4(
Sgn(clipPlane.x),
Sgn(clipPlane.y),
1.0F,
1.0F
);
Vector4 c = clipPlane * (2.0F / (Vector4.Dot(clipPlane, q)));
// third row = clip plane - fourth row
projection[2] = c.x - projection[3];
projection[6] = c.y - projection[7];
projection[10] = c.z - projection[11];
projection[14] = c.w - projection[15];
return projection;
}
// Update is called once per frame
void Update () {
}
}
网友评论