【Unity】当其他物体挡住主角时变透明

参考了这两位的文章:

http://www.xuanyusong.com/archives/1991

https://www.cnblogs.com/shenggege/p/4113316.html

最终效果:树没有挡住主角前、树挡住主角后变透明

 

下面是我的解决方案:

需要注意的设置:需要变透明的物体一定要有碰撞盒(可以被射线检测到),shader的渲染模式一定是Transparent(即可以修改透明度)

在摄像机上绑定下面这个脚本,思路是:从主角的位置向摄像机发射一条射线,射线检测到的所有碰撞体都应该隐藏掉。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraAvoidBlock : MonoBehaviour {
    //摄像机观察目标,即主角
    public Transform Target;
    public Transform LookAt; 
  
    //在摄像机和主角之间的物体
    List<GameObject> lastHitObjs;
    List<GameObject> hitObjs;

    void LateUpdate() {
        if (Target == null || LookAt == null) return;//主角为空,就不作任何操作     
        AvoidViewBlock();//在Update函数中检测是否有物体挡住主角
    }

    void AvoidViewBlock()
    {
        Vector3 ori = Target.position+Vector3.up*0.2f;//射线起点是主角位置偏上一点
       
        Vector3 dir = (transform.position-Target.position).normalized; //射线方向从主角指向摄像机,向量要进行单位化

        Debug.DrawRay(ori,dir);//运行时,在场景中观察射线是否正常

        RaycastHit[] raycastHits=Physics.RaycastAll(ori,dir,1000f);//获取射线的raycast hit数组

        //每一帧射中的物体都要重新计算,清空物体列表
        hitObjs.Clear();

        //把除了主角本身以外碰撞到的物体加入到List中
        if (raycastHits.Length > 1)
        {
            for(int i = 0; i < raycastHits.Length; i++)
            {
                if (raycastHits[i].transform.Equals(Target)) continue;
                GameObject go = raycastHits[i].collider.gameObject;
                if (go.GetComponent<Renderer>()==null)continue;
                hitObjs.Add(go);

                //对这些物体进行操作:如降低材质透明度或禁用Renderer
                //注意:不能禁用该物体碰撞盒,否则下一帧检测不到该物体,也无法复原
                SetMaterialAlpha(raycastHits[i].collider.gameObject,0f);
               
            }
        }

        //这里的思想是:理论上要把lastHitObjs中的所有物体都恢复
        //但是有一些物体这一帧还在遮挡,所以把它们刨去
        for(int i = 0; i < lastHitObjs.Count; i++)
        {
            for(int j = 0; j < hitObjs.Count; j++)
            {
                if (hitObjs[j] != null)
                {
                    if (hitObjs[j] == lastHitObjs[i])
                    {
                        lastHitObjs[i] = null;
                    }
                }
            }
        }
        for(int i = 0; i < lastHitObjs.Count; i++)
        {
            if (lastHitObjs[i] != null)
            {
                SetMaterialAlpha(lastHitObjs[i], 1f);//把他们的材质透明度恢复
            }
        }
        //结束之后,更新lastHitObjs
        for (int i = 0; i < hitObjs.Count; i++)
        {
            lastHitObjs.Add(hitObjs[i]);//这次的物体移到上次被碰到的List当中去
        }

    }

    void SetMaterialAlpha(GameObject go,float alpha)
    {
        Renderer renderer = go.GetComponent<Renderer>();
        int matNum= renderer.sharedMaterials.Length;
         //SharedMaterials和materials的区别在于:
         //改变前者会改变所有用到了这个材质的物体,而后者只改变这个物体
        for (int i=0;i<matNum;i++)
        {
            Color _color = renderer.materials[i].color;
            _color.a = alpha;
            renderer.materials[i].SetColor("_Color", _color);
        }
    }
}

 

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值