Unity中如何基于主体对象可见性控制眼睛渲染器的更新?
我用了一个挂载眼睛对象的Rig,后续模型会有大量移动操作,比如头部会碰到地面,眼睛也会跟着移动。现在遇到个问题:对象原点在绑定姿态的头部位置,当模型头部下移、拉近视角观察眼睛,直到原点移出视野时,眼睛就会消失,只有把视角转回原点位置才会重新显示。这个问题在Scene视图和Game视图里都出现。
我考虑过开启updateWhenOffscreen,但担心影响性能,所以想基于更容易保持在视野里的主体对象来决定更新剔除规则。但Unity 2021.3.5f1里这个选项只有复选框,没有可修改的字段,而且我不太会添加自定义字段。
我试着写了下面的脚本,挂载到主体上并关联眼睛的SkinnedMeshRenderer,但没达到预期效果:就算主体在视野里,眼睛还是会在两个视图中消失。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class UpdateRendererOverrideManager : MonoBehaviour { public SkinnedMeshRenderer eye; private void OnBecomeVisible() { eye.updateWhenOffscreen = true; } private void OnBecomeInvisible() { eye.updateWhenOffscreen = false; } }
(附脚本组件截图及Game视图眼睛未渲染截图)
问题根源
你的脚本没生效,是因为OnBecomeVisible/OnBecomeInvisible只有在挂载脚本的对象自身带有渲染组件(比如MeshRenderer、SkinnedMeshRenderer)时才会触发。如果主体对象本身没有渲染器,这两个方法根本不会被调用,自然没法控制眼睛的updateWhenOffscreen属性。
修复方案
方案1:给主体添加不可见渲染器触发事件
在主体对象上添加MeshRenderer和MeshFilter组件,使用一个极小的平面Mesh或者空Mesh,然后将材质的Alpha值设为0,同时勾选ShadowCastingMode为Off、取消勾选Receive Shadows,确保它不会影响画面显示。这样OnBecomeVisible/OnBecomeInvisible就能正常触发,你的原脚本就能生效。
方案2:手动检测主体是否在相机视野内
如果不想给主体加额外组件,可以改用GeometryUtility.TestPlanesAABB手动判断主体包围盒是否在相机视野内,修改后的脚本如下:
using UnityEngine; public class UpdateRendererOverrideManager : MonoBehaviour { public SkinnedMeshRenderer eye; private Camera mainCamera; private void Start() { mainCamera = Camera.main; } private void Update() { // 获取主体的包围盒,优先用Renderer,没有则用Collider Bounds bounds; var renderer = GetComponent<Renderer>(); if (renderer != null) { bounds = renderer.bounds; } else { var collider = GetComponent<Collider>(); bounds = collider != null ? collider.bounds : new Bounds(transform.position, Vector3.one * 0.1f); } // 检测主体是否在当前相机视野内 bool isVisible = GeometryUtility.TestPlanesAABB(GeometryUtility.CalculateFrustumPlanes(mainCamera), bounds); eye.updateWhenOffscreen = isVisible; } }
方案3:平衡性能与显示的简化处理
如果能接受轻微性能损耗,直接开启眼睛的updateWhenOffscreen,然后在Project Settings -> Quality中调整Skinned Mesh Update Rate,降低非视野内皮肤网格的更新频率,以此平衡性能开销和显示效果。
内容的提问来源于stack exchange,提问作者xDonnervogelx

