徐州市制作网站的公司,互联网营销有哪些,纺织品公司网站建设,如何建设网站和app1 前言
角色在地图上移动到岩石后面时#xff0c;完全被岩石遮挡#xff0c;玩家只能看到岩石。这逻辑看起来没问题#xff0c;但并不是玩家想要看到的画面#xff0c;玩家更希望关注角色的状态 为了避免角色被遮挡#xff0c;可以使用 Cinemachine Collider 功能#x… 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);ListMaterial materials new ListMaterial();for (int i 0; i size; i){var meshRenderers this._raycastHits[i].collider.GetComponentsInChildrenMeshRenderer();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-definition7.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 透明效果
最终效果如下图所示角色走到岩石后面时岩石呈现半透明状态