首先登场
场景中的元素
mirror是镜子,挂着我们的脚本,Quad是一个面片。Camera是用来生成RenderTexture给面片的。里面的test1是我用来调试位置的球。
镜子size是大小,x是-2,为了反转一下贴图
相机直接可以禁用掉,用脚本来调用。
玩家就是一个胶囊,里面的eye位置把玩家视角的相机放上去,其他没什么特别的。
代码的原理就是把相机拍摄到的图给Quad的Texture,脚本根据人物的位置来改变位置,并计算近裁面,这里因为有旋转,所以镜子后面最好不要有东西,否则相机会拍摄到,或者用层来避免拍摄到的问题。
附上代码:
csharp
using UnityEngine;
//一个用相机当镜子的脚本,相机的FOV可以设置成40
public class MirrorEffect : MonoBehaviour
{
public float disableDis = 20f; //超过一定距离就不计算了
public Transform eye; //玩家的眼睛
public Camera mirrorCamera; //镜子相机
public Transform targetObject; //画布
public Transform test1;
public Transform test2;
RenderTexture txture;
float maxResolution = 1024;//根据宽度计算高度,这个是精度
float maxWidth;
float maxHeight;
void Start()
{
maxWidth = maxResolution;
maxHeight = Mathf.Abs(targetObject.localScale.y / targetObject.localScale.x * maxWidth);
txture = new RenderTexture((int)maxWidth, (int)maxHeight, 24);
Renderer rend = targetObject.GetComponent<Renderer>();
if (rend == null)
{
Debug.LogWarning("MirrorEffect找不到Renderer.");
return;
}
mirrorCamera.enabled = false;
rend.material.mainTexture = txture;
mirrorCamera.targetTexture = txture;
}
private void Update()
{
Comput();
}
private void OnDestroy()
{
DestroyImmediate(txture, true);
}
void Comput()
{
float dis = Vector3.Distance(eye.transform.position, transform.position);
if (dis > disableDis)
{
return;
}
//计算视口高度和宽度
float frustumHeight = targetObject.transform.localScale.y;
//float frustumWidth = frustumHeight * mainCamera.aspect;
//缩放目标面片物体大小
//targetObject.transform.localScale = new Vector3(frustumWidth, frustumHeight, 1f);
float distance = frustumHeight * 0.5f / Mathf.Tan(mirrorCamera.fieldOfView * 0.5f * Mathf.Deg2Rad);
//镜子左右边的位置
float sz = Mathf.Abs(targetObject.transform.localScale.x);
Vector3 v3l = new Vector3(sz * -0.5f, 0f, 0f);
Vector3 v3r = new Vector3(sz * 0.5f, 0f, 0f);
v3l = transform.TransformPoint(v3l);
v3r = transform.TransformPoint(v3r);
//test1.position = v3l;
//test2.position = v3r;
//计算相机在镜子对象的局部坐标
//计算反射位置
Vector3 dir1 = (v3l - eye.transform.position).normalized;
Vector3 dir2 = (v3r - eye.transform.position).normalized;
Vector3 mirDir = -(dir1 + dir2).normalized;
Vector3 dirref2 = Vector3.Reflect(mirDir, -transform.forward);
//Debug.DrawRay(transform.position, dirref, Color.yellow, 1f);
//Debug.DrawRay(transform.position, dirref2, Color.red,1f);
//相机位于镜子正后方,要保持相机所有平移要水平与镜子
Vector3 dirref3 = Vector3.ProjectOnPlane(dirref2, transform.up);
Debug.DrawRay(transform.position, dirref3, Color.green, 1f);
Vector3 cameraPlace = transform.position + dirref3.normalized * distance;
mirrorCamera.transform.position = cameraPlace;// new Vector3(at2.x, 0f, distance);
mirrorCamera.nearClipPlane = distance;
Quaternion q = Quaternion.LookRotation((targetObject.transform.position - mirrorCamera.transform.position).normalized);
mirrorCamera.transform.rotation = q;
mirrorCamera.Render();
}
}
画质可以修改maxResolution ,disableDis 是20米距离就不进入Update了,可以节省一些性能,根据自己情况来。
最后放一个效果图。
镜面清晰,但是算法还是有点问题,比实时反射来的性能好一点。凑合用还行。