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

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.hqwc.cn/news/318839.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI:110-基于深度学习的药物分子结构生成与预测

🚀点击这里跳转到本专栏,可查阅专栏顶置最新的指南宝典~ 🎉🎊🎉 你的技术旅程将在这里启航! 从基础到实践,深入学习。无论你是初学者还是经验丰富的老手,对于本专栏案例和项目实践都有参考学习意义。 ✨✨✨ 每一个案例都附带有在本地跑过的关键代码,详细讲解供…

C++面向对象语法总结(二)

目录 《C面向对象语法总结(一&#xff09;》 十一、继承 继承&#xff0c;可以让子类拥有父类的多有成员&#xff08;变量、函数&#xff09;如下面的代码&#xff1a;Student是子类&#xff08;subclass,派生类&#xff09;&#xff0c;Person是父类&#xff08;superclass…

echarts点击柱子、线节点、横坐标标签

echarts点击柱子、线节点、横坐标标签 x轴标签要为标签文字添加点击事件&#xff0c;必须先在xAxis里设置响应事件 xAxis: {triggerEvent: true, },然后直接监听 thisChart.on("click" ,function (params) {console.log(params) });通过params.componentSubType来…

互联网分布式应用之SpringCloud

SpringCloud Java 是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应用服务。如今全球有数百万开发人员运行着超过 51 亿个 Java 虚拟机&#xff0c;Java 仍是企业和开发人员的首选开发平台。 课程内容的介绍 1. 微服务项目介绍 2. Eure…

深度学习:大规模模型分布式训练框架DeepSpeed

深度学习&#xff1a;大规模模型分布式训练框架DeepSpeed DeepSpeed简介DeepSpeed核心特点DeepSpeed如何工作&#xff1f;DeepSpeed如何使用&#xff1f;参考文献 DeepSpeed简介 随着机器学习模型变得越来越复杂和庞大&#xff0c;训练这些模型所需的计算资源也在不断增加。特别…

开源CalDAV和CardDav网页客户端InfCloud

本文应网友 畅天 的要求折腾。他遇到了跨域问题&#xff0c;所以老苏找了个二合一的镜像来规避。其中使用的 Baikal 和 InfCloud 都是最新的版本&#xff1b; 什么是 Baikal &#xff1f; Baikal 是一个免费的开源自托管 CalDAV 和 CardDAV 服务器&#xff0c;适用于想要管理其…

智能化校园:深入探讨云端管理系统设计与实现(二)

系列文章目录 智能化校园&#xff1a;深入探讨云端管理系统设计与实现&#xff08;一&#xff09; 文章目录 系列文章目录功能开发登录功能分析验证码功能实现登录校验功能登录后跳转功能 系统管理器实现验证码响应图片功能实现异步图片上传头像功能实现全局修改密码功能实现 …

PAM认证

介绍 PAM&#xff08;Pluggable Authentication Modules &#xff09;是由Sun提出的一种认证机制。它通过提供一些 动态链接库和一套统一的API&#xff0c;将系统提供的服务 和该服务的认证方式分开&#xff0c;使得系统管理 员可以灵活地根据需要给不同的服务配置不同的认证…

【Spring】19 AOP介绍及实例详解

文章目录 1. 定义1&#xff09;什么意思呢&#xff1f;2&#xff09;如何解决呢&#xff1f; 2. 基本概念1&#xff09;切面&#xff08;Aspect&#xff09;2&#xff09;切点&#xff08;Pointcut&#xff09;3&#xff09;通知&#xff08;Advice&#xff09;4&#xff09;连…

mysql生成数据库字典文档

项目交付离不开项目数据库字典文档。下面用python轻松生成交付文档字典。 一 生成doc文档数据库字典效果&#xff1a; 1 生成doc文件&#xff0c;如下图&#xff1a; 2 打开文件字典格式内容 &#xff0c;如下图&#xff1a; 二 python生成doc字典文档代码 生成doc数据库字典…

我的创作纪念日三年收获和感悟

机缘 我刚开始接触创作也是最近几年开始&#xff0c;当初就是希望自己的收获分享给大家&#xff0c;不仅使自己成长&#xff0c;也可以带着大家一起成长&#xff0c;独乐乐不如众乐乐&#xff0c;人都是自私的以前我都是看到好的知识文章都是自己藏起来&#xff0c;发现收获的…