Unity用相机实现的镜子效果

首先登场

场景中的元素

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了,可以节省一些性能,根据自己情况来。

最后放一个效果图。

镜面清晰,但是算法还是有点问题,比实时反射来的性能好一点。凑合用还行。

相关推荐
天人合一peng2 小时前
unity 生成标记根据背景色标记变色
unity·游戏引擎
天人合一peng6 小时前
unity 生成标记根据背景色变色为明显的颜色
unity·游戏引擎
魔士于安6 小时前
Unity 超市总动员 超市收银台 超市货架 超市购物手推车 超市常见商品
游戏·unity·游戏引擎·贴图·模型
CandyU26 小时前
Unity —— 数据持久化
unity·游戏引擎
zh路西法6 小时前
【Unity实现Oneshot胶卷显形】游戏窗口化与Win32API的使用
游戏·unity·游戏引擎
凡情11 小时前
android隐私合规检测
android·unity
小贺儿开发11 小时前
Unity3D 本地 Stable Diffusion 文生图效果演示
人工智能·unity·stable diffusion·文生图·ai绘画·本地化
mxwin1 天前
Unity Shader 半透明物体为什么不能写入深度缓冲?
unity·游戏引擎·shader
晚枫歌F1 天前
三层时间轮的实现
网络·unity·游戏引擎
咸鱼永不翻身1 天前
Lua脚本事件检查工具
unity·lua·工具