Unity | 渡鸦避难所-5 | 角色和摄像机之间的遮挡物半透明

news2024/11/15 18:39:48

1 前言

角色在地图上移动到岩石后面时,完全被岩石遮挡,玩家只能看到岩石。这逻辑看起来没问题,但并不是玩家想要看到的画面,玩家更希望关注角色的状态

为了避免角色被遮挡,可以使用 Cinemachine Collider 功能,虚拟相机会自动避开障碍物,或者将角色和摄像机之间的障碍物做半透明处理,这两种方式的原理都是利用物理射线

这里使用障碍物半透明的方案,利用物理射线,检测角色和摄像机之间指定 Layer 的障碍物,改变其透明度,角色移动后,恢复其原本的透明度

2 设置 Layer

场景中的对象类型多种多样,我们仅希望岩石、树木等环境中的物体遮挡角色时,才改变其透明度。因此需要将对象分为不同的类型,利用 Unity 的 Layer 功能可以轻松实现该需求

Layer 定义哪些游戏对象可以与不同的功能以及彼此交互。它们主要有两种用途:由摄像机用来仅渲染场景的某一部分;由光源用来仅照亮场景的某些部分。但是,层也可以供射线投射用于选择性地忽略碰撞体或创建碰撞。更多信息请参阅文档:「https://docs.unity3d.com/cn/2021.2/Manual/Layers.html」

1 添加 Layer

这里偷个懒,只创建一个 Environment 层,就不再细分了

2 分配 Layer

将 Free_Forest 及其子对象均设置为 Environment 层

3 射线检测

在场景中从角色向摄像机投射一条射线,获取 Environment 层中所有命中的对象

脚本中获取 Environment 层的方式有两种

var layerMask = LayerMask.GetMask("Environment");

或者

var layerMask = 1 << LayerMask.NameToLayer("Environment");

通过角色和摄像机的位置计算出射线投射的方向和距离,利用 Physics.RaycastNonAlloc 来获取射线命中对象,相比 Physics.RaycastAll,此函数不会产生任何垃圾,毕竟在 FixedUpdate 中进行射线检测,应当尽量减少性能损耗

var size = Physics.RaycastNonAlloc(selfPosition, direction, this._raycastHits, rayDistance, layerMask);

获取命中对象中所有子节点的材质集合,和上一次命中的材质集合对比,改变其透明度

private void TransparentObjects()
{
    Vector3 selfPosition = transHead.position;
    Vector3 cameraPosition = _cameraTrans.position;
    var rayDistance = Vector3.Distance(selfPosition, cameraPosition);
    Vector3 direction = Vector3.Normalize(cameraPosition - selfPosition);
    Debug.DrawLine(selfPosition, cameraPosition, Color.red);

    var layerMask = LayerMask.GetMask("Environment");
    var size = Physics.RaycastNonAlloc(selfPosition, direction, this._raycastHits, rayDistance, layerMask);
    List<Material> materials = new List<Material>();
    for (int i = 0; i < size; i++)
    {
        var meshRenderers = this._raycastHits[i].collider.GetComponentsInChildren<MeshRenderer>();
        foreach (var variable in meshRenderers)
        {
            materials.AddRange(variable.materials);
        }
    }

    var transparentList = materials.Except(_materialList).ToList();
    var opaqueList = _materialList.Except(materials).ToList();
    foreach (var variable in transparentList)
    {
        MaterialTransparent.SetMaterialTransparent(true, variable, 0.22f);
    }

    foreach (var variable in opaqueList)
    {
        MaterialTransparent.SetMaterialTransparent(false, variable);
    }

    _materialList = materials;
}

4 更改透明度

由于性能等因素,默认情况下 3D 模型的材质是不支持更改透明度的。需要将材质的 Rendering Mode(对于内置渲染管线)或 Surface Type(对于 URP 或 HDRP)设置为 Transparent,才可以调整透明度相关的属性

这里我们需要更改的属性主要为:

  • Surface Type:控制材质是否支持透明度,更多信息,请参阅文档: 「https://docs.unity3d.com/cn/Packages/com.unity.render-pipelines.high-definition@7.4/manual/Surface-Type.html」

    • Opaque:模拟没有光线穿透的全实体材质。

    • Transparent:模拟光线可以穿透的半透明材质,例如透明塑料或玻璃。选择 Transparent 会在 Surface Options 部分中显示更多属性,还会显示一个额外的 Transparency Inputs 部分

  • Blend:确定 GPU 如何将片元着色器的输出与渲染目标进行合并,更多信息请参阅文档: 「https://docs.unity3d.com/cn/current/Manual/SL-Blend.html」

通过脚本更改 Surface Type 和 Blend 属性:

public class MaterialTransparent
{
    private enum SurfaceType
    {
        Opaque,
        Transparent
    }

    private enum BlendMode
    {
        Alpha,
        Premultiply,
        Additive,
        Multiply
    }

    public static void SetMaterialTransparent(bool transparent, Material material, float alpha = 1)
    {
        if (transparent)
        {
            material.SetFloat("_Surface", (float)SurfaceType.Transparent);
            material.SetFloat("_Blend", (float)BlendMode.Alpha);
        }
        else
        {
            material.SetFloat("_Surface", (float)SurfaceType.Opaque);
        }

        SetupMaterialBlendMode(material);
        
        Color color = material.color;
        color.a = alpha;
        material.color = color;
    }

    private static void SetupMaterialBlendMode(Material material)
    {
        if (material == null)
        {
            return;
        }

        bool alphaClip = material.GetFloat("_AlphaClip") == 1;
        if (alphaClip)
        {
            material.EnableKeyword("_ALPHATEST_ON");
        }
        else
        {
            material.DisableKeyword("_ALPHATEST_ON");
        }

        SurfaceType surfaceType = (SurfaceType)material.GetFloat("_Surface");
        if (surfaceType == 0)
        {
            material.SetOverrideTag("RenderType", "");
            material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
            material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
            material.SetInt("_ZWrite", 1);
            material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
            material.renderQueue = -1;
            material.SetShaderPassEnabled("ShadowCaster", true);
        }
        else
        {
            BlendMode blendMode = (BlendMode)material.GetFloat("_Blend");
            switch (blendMode)
            {
                case BlendMode.Alpha:
                    material.SetOverrideTag("RenderType", "Transparent");
                    material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
                    material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
                    material.SetInt("_ZWrite", 0);
                    material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
                    material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent;
                    material.SetShaderPassEnabled("ShadowCaster", false);
                    break;
                case BlendMode.Premultiply:
                    material.SetOverrideTag("RenderType", "Transparent");
                    material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
                    material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
                    material.SetInt("_ZWrite", 0);
                    material.EnableKeyword("_ALPHAPREMULTIPLY_ON");
                    material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent;
                    material.SetShaderPassEnabled("ShadowCaster", false);
                    break;
                case BlendMode.Additive:
                    material.SetOverrideTag("RenderType", "Transparent");
                    material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
                    material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.One);
                    material.SetInt("_ZWrite", 0);
                    material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
                    material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent;
                    material.SetShaderPassEnabled("ShadowCaster", false);
                    break;
                case BlendMode.Multiply:
                    material.SetOverrideTag("RenderType", "Transparent");
                    material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.DstColor);
                    material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
                    material.SetInt("_ZWrite", 0);
                    material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
                    material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent;
                    material.SetShaderPassEnabled("ShadowCaster", false);
                    break;
            }
        }
    }
}

5 透明效果

最终效果如下图所示,角色走到岩石后面时,岩石呈现半透明状态

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1353553.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

多模态——旷视大模型Vary更细粒度的视觉感知实现文档级OCR或图表理解

概述 现代大型视觉语言模型&#xff08;LVLMs&#xff09;&#xff0c;例如CLIP&#xff0c;使用一个共同的视觉词汇&#xff0c;以适应多样的视觉任务。然而&#xff0c;在处理一些需要更精细和密集视觉感知的特殊任务时&#xff0c;例如文档级OCR或图表理解&#xff0c;尤其…

Java多线程详解

进程 进程是程序的执行实例&#xff0c;而在进程的执行过程中&#xff0c;它需要操作和管理一系列的数据。这个数据集合通常包括程序的代码、程序计数器、寄存器、堆栈、数据段和其他与程序执行相关的信息。这些数据共同构成了一个进程的上下文&#xff08;context&#xff09…

案例088:基于微信小程序的校车购票平台设计与实现

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;SSM JDK版本&#xff1a;JDK1.8 数据库&#xff1a;mysql 5.7 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.5.4 小程序框架&#xff1a;uniapp 小程序开发软件&#xff1a;HBuilder X 小程序…

【深入浅出Docker原理及实战】「原理实战体系」零基础+全方位带你学习探索Docker容器开发实战指南(Docker-compose使用全解 一)

Docker-compose使用全解 Compose介绍Compose的作用和职能 Compose和Docker兼容性安装docker-compose添加可执行权限 Docker Compose常用配置imagebuildcontext上下文指定镜像名args构建环境变量 commanddepends_onports特殊映射关系 volumesenvironment Docker Compose命令详解…

适合 C++ 新手学习的开源项目——在 GitHub 学编程

作者&#xff1a;HelloGitHub-小鱼干 俗话说&#xff1a;万事开头难&#xff0c;学习编程也是一样。在 HelloGitHub 的群里&#xff0c;经常遇到有小伙伴询问编程语言如何入门方面的问题&#xff0c;如&#xff1a; 我要学习某一门编程语言&#xff0c;有什么开源项目可以推荐…

juniper EX系列交换机 包过滤(Packet Filtering)配置

Juniper EX交换机支持基于物理端口、VLAN和三层VLAN接口的包过滤技术&#xff1a; 在二层过滤下支持&#xff1a; ■ Ingress port firewall filter ■ Ingress VLAN firewall filter ■ Egress VLAN firewall filter 在三层过滤下支持&#xff1a; ■ Ingress port firew…

项目经理面试10问

今天我们来说说项目经理专业面试的十条经验总结。如果你认真阅读并思考&#xff0c;相信对在屏幕前的你会有所帮助和启发。 1、请做一下自我介绍 自我介绍很重要。无论面试什么岗位&#xff0c;面试官通常都会问你一个最常见的问题&#xff1a;“请做一下自我介绍。” 在准备…

搜维尔科技:【简报】第九届元宇宙数字人设计大赛,报名已经进入白热化阶段!

随着元宇宙时代的来临&#xff0c;数字人设计成为了创新前沿领域之一。为了提高大学生元宇宙虚拟人角色策划与美术设计的专业核心能力&#xff0c;我们特别举办了这场元宇宙数字人设计赛道&#xff0c;赛道主题为「AI人工智能科技」 &#xff0c;只要与「AI人工智能科技」相关的…

三菱plc的点动控制循环(小灯闪烁,单控气缸循环)

以为前一段时间小编做了一个气缸定时循环的程序&#xff0c;根据程序有不足之处&#xff0c;所以小编写下这篇文章&#xff0c;将网络上的plc小灯控制进行总结&#xff01;如果对你有帮助&#xff0c;不要忘了点赞收藏&#xff01;如果有更加好的梯形图&#xff0c;欢迎评论&am…

搭建FTP服务器

目录 一、FTP 1.1 FTP简介 1.2 FTP服务器搭建 1.2.1 前提 1.2.2 创建组 1.2.3 创建用户 1.2.4 安装FTP服务器 1.2.5 配置FTP服务器 1.2.6 配置FTP的文件夹权限 1.2.7 连接测试 1.2.8 允许外部访问 二、计算机端口介绍 2.1 端口简介 2.2 开启端口 2.3 端口相关 2…

第一至四批专精特新“小巨人”企业信息库

第一至四批专精特新“小巨人”企业信息库 1、指标&#xff1a;专精特新公示批次、企业名称、登记状态、法定代表人、注册资本、实缴资本、成立日期、核准日期、营业期限、所属省份、所属城市、所属区县、电话、更多电话、邮箱、更多邮箱、统一社会信用代码、纳税人识别号 注册…

Java后端开发——Spring实验

文章目录 Java后端开发——Spring实验一、Spring入门1.创建项目&#xff0c;Spring依赖包。2.创建JavaBean&#xff1a;HelloSpring3.编写applicationContext.xml配置文件4.测试&#xff1a;启动Spring&#xff0c;获取Hello示例。 二、Spring基于XML装配实验1.创建JavaBean类&…

业务中台-UAT测试用例示例

今天我来和大家分享一下我们在业务中台UAT测试用例的案例&#xff0c;这个案例的编写方式是参考了其他项目来编写的。这个测试用例主要分为两个部分&#xff1a;用例目录和测试具体内容。 对于UAT测试用例&#xff0c;我们理解应该存在两种不同的编写方式&#xff0c;一种是功…

c语言-浮点型数据在内存中的存储

目录 前言一、浮点数存储例子二、浮点数在内存的存储格式2.1 32位浮点数存储格式2.2 64位浮点数存储格式 三、IEEE 754对有效数字M和指数E的规定3.1 对存储有效数字M的规定3.2 对存储指数E的规定3.2.1 E在32位浮点数的存储格式3.2.2 E在64位浮点数的存储格式 3.3 对读取有效数M…

Python 箱线图的绘制(Matplotlib篇-13)

Python 箱线图的绘制(Matplotlib篇-13)         🍹博主 侯小啾 感谢您的支持与信赖。☀️ 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ�…

Python贪吃蛇小游戏(PyGame)

文章目录 写在前面PyGame入门贪吃蛇注意事项写在后面 写在前面 本期内容&#xff1a;基于pygame的贪吃蛇小游戏 实验环境 python3.11及以上pycharmpygame 安装pygame的命令&#xff1a; pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pygamePyGame入门 pygam…

UI5与后端的文件交互(二)

文章目录 前言一、开发Action1. 创建Structure2. BEDF添加Action3. class中实现Action 二、修改UI5 项目1. 添加一个按钮2. 定义事件函数 三、测试及解析1. 测试2. js中提取到的excel流数据3. 后端解析 前言 这系列文章详细记录在Fiori应用中如何在前端和后端之间使用文件进行…

windows系统安装docker(Hyper-V方式)

文章目录 1 环境准备2 下载3 安装4 替换国内镜像源5 修改镜像存储路径&#xff08;Hyepe-V方式&#xff09; 1 环境准备 ctrlshiftesc查看CPU的虚拟化是否启动 左键单击电脑左下角开始按钮—>点击“设置”—>搜索“Windows功能”—>启用或关闭Windows功能—>勾选H…

阿里云服务器云盘ESSD Entry、SSD、高效云盘性能测评

阿里云服务器系统盘或数据盘支持多种云盘类型&#xff0c;如高效云盘、ESSD Entry云盘、SSD云盘、ESSD云盘、ESSD PL-X云盘及ESSD AutoPL云盘等&#xff0c;阿里云百科aliyunbaike.com详细介绍不同云盘说明及单盘容量、最大/最小IOPS、最大/最小吞吐量、单路随机写平均时延等性…

ElasticSearch数据同步

文章目录 ElasticSearch数据同步1. 同步调用2. 异步通知3. 监听binlog4. 工作中处理同步的问题 ElasticSearch数据同步 ElasticSearch中酒店数据来自于mysql数据库&#xff0c;因此MySQL数据发生改变时&#xff0c;ElasticSearch也必须跟着改变&#xff0c;这个就是ElasticSear…