当前位置: 首页 > news >正文

Unity优化技巧:自动隐藏视野外的3D模型

在3D游戏开发中,场景中可能包含大量模型,而许多模型可能同时处于玩家视野之外。这些不可见的模型仍然消耗CPU和GPU资源,导致性能下降。本文将介绍如何实现一个自动隐藏视野外模型的系统,通过两个Unity脚本实现性能优化。

系统概述

这个系统由两个核心脚本组成:

  1. ModelVisibilityManager1:管理器脚本,负责跟踪所有需要自动隐藏的模型
  2. AutoHideWhenOutOfView1:组件脚本,附加到需要自动隐藏的模型上

系统工作流程:

  • 管理器每帧检查所有注册模型的可见性
  • 当模型离开相机视野时自动隐藏
  • 当模型重新进入视野时自动显示
  • 避免不必要的渲染和计算开销

脚本1:ModelVisibilityManager1(管理器)

using System.Collections.Generic;
using UnityEngine;public class ModelVisibilityManager1 : MonoBehaviour
{public static ModelVisibilityManager1 Instance { get; private set; }private List<AutoHideWhenOutOfView1> registeredControllers = new List<AutoHideWhenOutOfView1>();public Camera targetCamera;void Awake(){// 单例模式实现if (Instance == null){Instance = this;DontDestroyOnLoad(gameObject);}else{Destroy(gameObject);}// 设置默认相机if (targetCamera == null){targetCamera = Camera.main;}}// 注册模型控制器public void Register(AutoHideWhenOutOfView1 controller){if (!registeredControllers.Contains(controller)){registeredControllers.Add(controller);}}// 注销模型控制器public void Unregister(AutoHideWhenOutOfView1 controller){if (registeredControllers.Contains(controller)){registeredControllers.Remove(controller);}}void Update(){// 每帧检查所有注册模型的可见性foreach (var controller in registeredControllers){controller.ManualVisibilityCheck(targetCamera);}}
}

单例模式实现

public static ModelVisibilityManager1 Instance { get; private set; }

使用静态属性确保全局只有一个实例,其他脚本可以通过ModelVisibilityManager1.Instance访问它。

初始化设置

void Awake()
{if (Instance == null){Instance = this;DontDestroyOnLoad(gameObject);}else{Destroy(gameObject);}if (targetCamera == null){targetCamera = Camera.main;}
}
  • 如果当前实例为空,则设置当前实例为单例,并标记为在场景切换时不销毁
  • 如果已存在实例,则销毁当前对象,保证单例的唯一性
  • 如果targetCamera未被赋值,则使用场景中的主相机作为目标相机

注册管理

private List<AutoHideWhenOutOfView1> registeredControllers = new List<AutoHideWhenOutOfView1>();public void Register(AutoHideWhenOutOfView1 controller)
{if (!registeredControllers.Contains(controller)){registeredControllers.Add(controller);}
}public void Unregister(AutoHideWhenOutOfView1 controller)
{if (registeredControllers.Contains(controller)){registeredControllers.Remove(controller);}
}
  • 维护一个列表存储所有需要自动隐藏的模型组件
  • 提供RegisterUnregister方法管理组件列表

可见性检查

public void CheckVisibility(Camera camera)
{foreach (var controller in registeredControllers){controller.CheckVisibility(camera);}
}
  • 遍历所有已注册的控制器
  • 调用每个控制器的CheckVisibility方法进行可见性检测

    关键功能解析:

  • 单例模式

    • 确保场景中只有一个管理器实例
    • 使用DontDestroyOnLoad保持管理器在场景切换时不被销毁
  • 相机设置

    • 默认使用场景主相机
    • 可通过Inspector自定义目标相机
  • 模型注册系统

    • Register方法添加需要自动隐藏的模型
    • Unregister方法移除已销毁的模型
    • 避免重复注册
  • 每帧可见性检查

    • 在Update中遍历所有注册的模型
    • 调用每个模型的可见性检查方法

脚本2:AutoHideWhenOutOfView1(模型组件)

using UnityEngine;[RequireComponent(typeof(Renderer))]
public class AutoHideWhenOutOfView1 : MonoBehaviour
{private Renderer modelRenderer;private bool isVisible = true;void Awake(){// 获取渲染器组件modelRenderer = GetComponent<Renderer>();if (modelRenderer == null){enabled = false; // 无渲染器则禁用脚本}// 向管理器注册自身ModelVisibilityManager1.Instance.Register(this);}void OnEnable(){isVisible = true;}// 由管理器调用的可见性检查方法public void ManualVisibilityCheck(Camera camera){bool isInView = IsInCameraView(camera);// 从不可见到可见:激活模型if (!isVisible && isInView){gameObject.SetActive(true);isVisible = true;}// 从可见到不可见:隐藏模型else if (isVisible && !isInView){gameObject.SetActive(false);isVisible = false;}}// 检查模型是否在相机视野内bool IsInCameraView(Camera camera){Bounds bounds = modelRenderer.bounds;Plane[] planes = GeometryUtility.CalculateFrustumPlanes(camera);return GeometryUtility.TestPlanesAABB(planes, bounds);}void OnDestroy(){// 从管理器中注销ModelVisibilityManager1.Instance.Unregister(this);}
}

组件初始化

private bool isVisible = true;
private Renderer modelRenderer;void Awake()
{modelRenderer = GetComponent<Renderer>();
}
  • isVisible:记录当前模型是否处于激活状态
  • 获取模型上的渲染器组件用于后续检测

可见性检测逻辑

public void CheckVisibility(Camera camera)
{bool isInView = IsInCameraView(camera);if (!isVisible && isInView){gameObject.SetActive(true);isVisible = true;//Debug.Log(name + " 已重新进入视野,已激活");}else if (isVisible && !isInView){gameObject.SetActive(false);isVisible = false;//Debug.Log(name + " 离开视野,已隐藏");}
}
  • 调用IsInCameraView检测模型是否在相机视野内
  • 当模型从不可见变为可见时激活模型
  • 当模型从可见变为不可见时停用模型

视锥体检测算法

private bool IsInCameraView(Camera camera)
{Bounds bounds = modelRenderer.bounds;Plane[] planes = GeometryUtility.CalculateFrustumPlanes(camera);return GeometryUtility.TestPlanesAABB(planes, bounds);
}
  • 获取模型的包围盒(AABB)
  • 计算相机的视锥体平面
  • 使用Unity内置方法检测包围盒是否与视锥体相交

清理注册

void OnDestroy()
{ModelVisibilityManager1.Instance.Unregister(this);
}
  • 当对象被销毁时,从管理器的注册列表中移除自身

关键功能解析:

  1. 渲染器依赖

    • 使用[RequireComponent]确保模型有渲染器
    • 无渲染器时自动禁用脚本
  2. 可见性状态管理

    • isVisible变量跟踪当前可见状态
    • 避免重复激活/停用模型
  3. 视野检测算法

    • 使用GeometryUtility类计算相机视锥体
    • 通过包围盒(AABB)与视锥体平面相交测试判断可见性
    • 高效且精确的3D空间检测方法
  4. 生命周期管理

    • Awake中注册到管理器
    • OnDestroy中从管理器注销
    • 确保没有内存泄漏
http://www.lryc.cn/news/606691.html

相关文章:

  • Python爬虫实战:研究pycares技术构建DNS解析系统
  • 玻尔兹曼分布与玻尔兹曼探索
  • 从比划沟通到指令同步:声网让跨国游戏升级
  • 什么是爬虫协议?
  • Unity相机控制
  • Sklearn 机器学习 文本数据 TF-IDF实现文本向量化
  • 噪声对比估计(NCE):原理、演进与跨领域应用
  • git SSL certificate problem: self-signed certificate in certificate chain 解决办法
  • ZED 2/2i 相机安装与调试完整指南 | Ubuntu 20.04 + CUDA 11.8
  • 从本地到云端:将Linux文件夹上传至GitHub仓库的完整指南
  • 如何填写PDF表格的例子
  • iOS 抓不到包怎么办?全流程排查思路与替代引导
  • uniapp基础 (一)
  • 逻辑回归召回率优化方案
  • uniapp无线(WIFI)运行调试APP(真机)
  • Java设计模式之行为型模式(解释器模式)实现方式详解
  • RabbitMQ 延时队列插件安装与使用详解(基于 Delayed Message Plugin)
  • 在uni-app中引入本地日志插件
  • 开发者体验如何度量?
  • android APT技术
  • 嵌入式系统教学范式演进:云端仿真平台如何重构温湿度监测实验教学
  • JavaScript语法树简介:AST/CST/词法/语法分析/ESTree/生成工具
  • 2025 腾讯广告算法大赛 Baseline 项目解析
  • gd32modbus从机移植
  • 烽火HG680-KX-海思MV320芯片-2+8G-安卓9.0-强刷卡刷固件包
  • 关税战火中的技术方舟:新西兰证券交易所的破局之道 ——从15%关税冲击到跨塔斯曼结算联盟,解码下一代交易基础设施
  • VSCode:通义灵码插件安装使用 -- 免费AI编程工具
  • 高端房产管理小程序
  • C++继承中虚函数调用时机问题及解决方案
  • Spring框架下的中医针灸系统实现