Unity镜子效果的制作过程
Create Mirror —— 创建镜子
1. 创建一个 Plane —— 作为镜子
2. 创建一个材质球 Material —— 给到 Plane 上
3. 修改新创建 Material 的 Shader 为 Unlit/Texture
Create Camera —— 创建一个新相机
1. 新建一个 Render Texture(这里重新命名为 Plane 便于区分和理解)
2. 在层次列表Hierarchy 下创建一个新的 Camera
3. 将新建的 Render Texture(Plane)给新 Camera 组件中的 Target Texture
4. 给 Camera相机,添加脚本 MirrorPlane
并将 Plane 拖到 Inspector 面板中对应的属性里
5. 给新 Camera相机,添加脚本 Mirror
并将Main Camera与 Plane 拖至 Inspector 面板中
注意: 一定要修改 Plane 材质的属性为:
两个脚本,具体代码如下 :
1 using UnityEngine; 2 3 /// <summary> 4 /// Plane管理脚本 —— 挂载新建的Camera上 5 /// </summary> 6 [ExecuteInEditMode] //编辑模式中执行 7 public class MirrorPlane : MonoBehaviour 8 { 9 public GameObject mirrorPlane; //镜子Plane 10 public bool estimateViewFrustum = true; 11 public bool setNearClipPlane = true; //是否设置近剪切平面 12 public float nearClipDistanceOffset = -0.01f; //近剪切平面的距离 13 private Camera mirrorCamera; //镜像摄像机 14 private Vector3 vn; //屏幕的法线 15 private float l; //到屏幕左边缘的距离 16 private float r; //到屏幕右边缘的距离 17 private float b; //到屏幕下边缘的距离 18 private float t; //到屏幕上边缘的距离 19 private float d; //从镜像摄像机到屏幕的距离 20 private float n; //镜像摄像机的近剪切面的距离 21 private float f; //镜像摄像机的远剪切面的距离 22 private Vector3 pa; //世界坐标系的左下角 23 private Vector3 pb; //世界坐标系的右下角 24 private Vector3 pc; //世界坐标系的左上角 25 private Vector3 pe; //镜像观察角度的世界坐标位置 26 private Vector3 va; //从镜像摄像机到左下角 27 private Vector3 vb; //从镜像摄像机到右下角 28 private Vector3 vc; //从镜像摄像机到左上角 29 private Vector3 vr; //屏幕的右侧旋转轴 30 private Vector3 vu; //屏幕的上侧旋转轴 31 private Matrix4x4 p = new Matrix4x4(); 32 private Matrix4x4 rm = new Matrix4x4(); 33 private Matrix4x4 tm = new Matrix4x4(); 34 private Quaternion q = new Quaternion(); 35 36 private void Start() 37 { 38 mirrorCamera = GetComponent<Camera>(); 39 } 40 41 private void Update() 42 { 43 if (null == mirrorPlane || null == mirrorCamera) return; 44 pa = mirrorPlane.transform.TransformPoint(new Vector3(-5.0f, 0.0f, -5.0f)); //世界坐标系的左下角 45 pb = mirrorPlane.transform.TransformPoint(new Vector3(5.0f, 0.0f, -5.0f)); //世界坐标系的右下角 46 pc = mirrorPlane.transform.TransformPoint(new Vector3(-5.0f, 0.0f, 5.0f)); //世界坐标系的左上角 47 pe = transform.position; //镜像观察角度的世界坐标位置 48 n = mirrorCamera.nearClipPlane; //镜像摄像机的近剪切面的距离 49 f = mirrorCamera.farClipPlane; //镜像摄像机的远剪切面的距离 50 va = pa - pe; //从镜像摄像机到左下角 51 vb = pb - pe; //从镜像摄像机到右下角 52 vc = pc - pe; //从镜像摄像机到左上角 53 vr = pb - pa; //屏幕的右侧旋转轴 54 vu = pc - pa; //屏幕的上侧旋转轴 55 if (Vector3.Dot(-Vector3.Cross(va, vc), vb) < 0.0f) //如果看向镜子的背面 56 { 57 vu = -vu; 58 pa = pc; 59 pb = pa + vr; 60 pc = pa + vu; 61 va = pa - pe; 62 vb = pb - pe; 63 vc = pc - pe; 64 } 65 vr.Normalize(); 66 vu.Normalize(); 67 vn = -Vector3.Cross(vr, vu); //两个向量的叉乘,最后在取负,因为Unity是使用左手坐标系 68 vn.Normalize(); 69 d = -Vector3.Dot(va, vn); 70 if (setNearClipPlane) 71 { 72 n = d + nearClipDistanceOffset; 73 mirrorCamera.nearClipPlane = n; 74 } 75 l = Vector3.Dot(vr, va) * n / d; 76 r = Vector3.Dot(vr, vb) * n / d; 77 b = Vector3.Dot(vu, va) * n / d; 78 t = Vector3.Dot(vu, vc) * n / d; 79 80 //投影矩阵 81 p[0, 0] = 2.0f * n / (r - l); 82 p[0, 1] = 0.0f; 83 p[0, 2] = (r + l) / (r - l); 84 p[0, 3] = 0.0f; 85 86 p[1, 0] = 0.0f; 87 p[1, 1] = 2.0f * n / (t - b); 88 p[1, 2] = (t + b) / (t - b); 89 p[1, 3] = 0.0f; 90 91 p[2, 0] = 0.0f; 92 p[2, 1] = 0.0f; 93 p[2, 2] = (f + n) / (n - f); 94 p[2, 3] = 2.0f * f * n / (n - f); 95 96 p[3, 0] = 0.0f; 97 p[3, 1] = 0.0f; 98 p[3, 2] = -1.0f; 99 p[3, 3] = 0.0f; 100 101 //旋转矩阵 102 rm[0, 0] = vr.x; 103 rm[0, 1] = vr.y; 104 rm[0, 2] = vr.z; 105 rm[0, 3] = 0.0f; 106 107 rm[1, 0] = vu.x; 108 rm[1, 1] = vu.y; 109 rm[1, 2] = vu.z; 110 rm[1, 3] = 0.0f; 111 112 rm[2, 0] = vn.x; 113 rm[2, 1] = vn.y; 114 rm[2, 2] = vn.z; 115 rm[2, 3] = 0.0f; 116 117 rm[3, 0] = 0.0f; 118 rm[3, 1] = 0.0f; 119 rm[3, 2] = 0.0f; 120 rm[3, 3] = 1.0f; 121 122 tm[0, 0] = 1.0f; 123 tm[0, 1] = 0.0f; 124 tm[0, 2] = 0.0f; 125 tm[0, 3] = -pe.x; 126 127 tm[1, 0] = 0.0f; 128 tm[1, 1] = 1.0f; 129 tm[1, 2] = 0.0f; 130 tm[1, 3] = -pe.y; 131 132 tm[2, 0] = 0.0f; 133 tm[2, 1] = 0.0f; 134 tm[2, 2] = 1.0f; 135 tm[2, 3] = -pe.z; 136 137 tm[3, 0] = 0.0f; 138 tm[3, 1] = 0.0f; 139 tm[3, 2] = 0.0f; 140 tm[3, 3] = 1.0f; 141 142 mirrorCamera.projectionMatrix = p; //矩阵组 143 mirrorCamera.worldToCameraMatrix = rm * tm; 144 if (!estimateViewFrustum) return; 145 q.SetLookRotation((0.5f * (pb + pc) - pe), vu); //旋转摄像机 146 mirrorCamera.transform.rotation = q; //聚焦到屏幕的中心点 147 148 //估值 —— 三目简写 149 mirrorCamera.fieldOfView = mirrorCamera.aspect >= 1.0 ? Mathf.Rad2Deg * 150 Mathf.Atan(((pb - pa).magnitude + (pc - pa).magnitude) / va.magnitude) : 151 Mathf.Rad2Deg / mirrorCamera.aspect * 152 Mathf.Atan(((pb - pa).magnitude + (pc - pa).magnitude) / va.magnitude); 153 //在摄像机角度考虑,保证视锥足够宽 154 } 155 }
1 using UnityEngine; 2 3 /// <summary> 4 /// 镜子管理脚本 —— 挂在新建的Camera上 5 /// </summary> 6 [ExecuteInEditMode] 7 public class Mirror : MonoBehaviour 8 { 9 public GameObject mirrorPlane; //镜子 10 public Camera mainCamera; //主摄像机 11 private Camera mirrorCamera; //镜像摄像机 12 13 private void Start() 14 { 15 mirrorCamera = GetComponent<Camera>(); 16 } 17 18 private void Update() 19 { 20 if (null == mirrorPlane || null == mirrorCamera || null == mainCamera) return; 21 //将主摄像机的世界坐标位置转换为镜子的局部坐标位置 22 Vector3 postionInMirrorSpace = mirrorPlane.transform. 23 InverseTransformPoint(mainCamera.transform.position); 24 //一般y为镜面的法线方向 25 postionInMirrorSpace.y = -postionInMirrorSpace.y; 26 //转回到世界坐标系的位置 27 mirrorCamera.transform.position = mirrorPlane.transform.TransformPoint(postionInMirrorSpace); 28 } 29 }
Create Cube —— 创建一个立方体
为了看镜子的效果,在场景中创建一个 Cube —— 用来作为参照对象,然后点击运行后,即可看到镜子效果已经完成
Indistinct —— 显示效果不清晰
如果发现,镜子的显示效果并不清晰,这是因为我们创建的 Render Texture 时使用的是默认的分辨率 256*256,修改成较高的分辨率即可,这里我修改为:1024*1024 (可视情况自己设定)
注意:分辨率设置越高,是越耗性能的
镜面显示效果
END
原文: https://www.cnblogs.com/chinarbolg/p/9601388.html