【Unity】 场景优化策略

这篇具有很好参考价值的文章主要介绍了【Unity】 场景优化策略。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Unity 场景优化策略

GPU instancing

使用GPU Instancing可以将多个网格相同、材质相同、材质属性可以不同的物体合并为一个批次,从而减少Draw Calls的次数。这可以提高性能和渲染效率。

GPU instancing可用于绘制在场景中多次出现的几何体,例如树木或灌木丛。

渲染管线兼容性

特征 内置渲染管线 通用渲染管线 (URP) 高清渲染管线 (HDRP) 自定义可编程渲染管线 (SRP)
GPU instancing 是的 是 (1) 是 (1) 是 (1)

注意

  1. 仅当着色器与 SRP Batcher 不兼容时。

** 设置GPU instancing**

设置很简单只需一步

在默认的材质球下找到Enable GPU Instancing,勾选就可以。

enable gpu instancing,Unity,unity,游戏引擎
对比效果

没有勾选时:Batches是230左右,Saved By Batching是0

enable gpu instancing,Unity,unity,游戏引擎

勾选后:Batches是8,Saved By Batching是222左右

enable gpu instancing,Unity,unity,游戏引擎

使用下文的shader给材质添加随机色后:Batches是4,Saved By Batching是63(这里没有添加阴影Batch会少)

enable gpu instancing,Unity,unity,游戏引擎

补充:

MaterialPropertyBlock

批处理一般作用与相同的材质。当需要对shader相同,材质属性不同的模型批处理时可以用MaterialPropertyBlock。

MaterialPropertyBlock除了在 Renderer.SetPropertyBlock 被使用,还可以在 Graphics.DrawMesh使用。

    void Start()
    {
        MaterialPropertyBlock material = new MaterialPropertyBlock();
        material.SetColor("_Color", new Color(Random.Range(0f, 1f), Random.Range(0f, 1f), Random.Range(0f, 1f)));
        GetComponent<MeshRenderer>().SetPropertyBlock(material);

    }

这里可以发现,虽然颜色不一样,但是材质球指向的是同一个

** 创建支持 GPU instancing的着色器**

渲染管线兼容性

特征 内置渲染管线 通用渲染管线 (URP) 高清渲染管线 (HDRP) 自定义可编程渲染管线 (SRP)
自定义 GPU instancing着色器 是的

顶点和片元着色器示例

Shader "Custom/SimplestInstancedShader"
{
    Properties
    {
        _Color ("Color", Color) = (1, 1, 1, 1)
    }

    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
           //生成实例化变体。它是可选的。
            #pragma multi_compile_instancing
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
               //在顶点着色器输入/输出结构中定义INSTANCE_ID。
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                //使INSTANCE_ID访问片元着色器中的实例化属性。
                UNITY_VERTEX_INPUT_INSTANCE_ID 
            };
            //声明名为 的每个实例常量缓冲区的开始
            UNITY_INSTANCING_BUFFER_START(Props)
                UNITY_DEFINE_INSTANCED_PROP(float4, _Color)
           //声明名为 的每个实例常量缓冲区的结尾     
            UNITY_INSTANCING_BUFFER_END(Props)

            v2f vert(appdata v)
            {
                v2f o;
				//允许顶点着色器函数访问INSTANCE_ID
                UNITY_SETUP_INSTANCE_ID(v);
                //将INSTANCE_ID从输入结构复制到顶点着色器中的输出结构。
                UNITY_TRANSFER_INSTANCE_ID(v, o);
                o.vertex = UnityObjectToClipPos(v.vertex);
                return o;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                //允许片元着色器函数访问INSTANCE_ID
                UNITY_SETUP_INSTANCE_ID(i);
                //访问实例化常量缓冲区中的每个实例着色器属性
                return UNITY_ACCESS_INSTANCED_PROP(Props, _Color);
            }
            ENDCG
        }
    }
}

静态批处理

它通过将多个静态物体合并成一个批次来减少渲染调用,从而减少CPU和GPU的负载,可以显著减少渲染过程中的Draw Call数量,从而提高性能。

静态批处理适用于那些不会在运行时改变位置、旋转或缩放的物体,例如地形、建筑物等。

渲染管线兼容性

特征 内置渲染管线 通用渲染管线 (URP) 高清渲染管线 (HDRP) 自定义可编程渲染管线 (SRP)
静态批处理 是的 是的 是的 是的

静态批处理的设置

设置也很简单只需两步

  1. 在ProjectSettings→player→OtherSetting→StaticBatching,勾选

  2. 在默认的材质球下找到Enable GPU Instancing,勾选就可以。

enable gpu instancing,Unity,unity,游戏引擎

静态批处理的限制

  • 游戏对象处于活动状态且禁止(非禁止对象的会强制禁止)。
  • 游戏对象具有MeshFilter组件,并且该组件已启用。
  • MeshFilter 组件引用了Mesh
  • 网格的顶点数大于 0。
  • 该网格尚未与另一个网格合并。
  • 游戏对象具有MeshRenderer组件,并且该组件已启用。
  • 要批处理在一起的网格,使用相同的顶点属性。例如,Unity 可以对使用顶点位置、顶点法线和一个 UV 的网格进行批处理,但不能对使用顶点位置、顶点法线、UV0、UV1 和顶点切线的网格进行批处理。

效果

Batches是8,Saved By Batching是211

enable gpu instancing,Unity,unity,游戏引擎

静态批处理的控制

使用StaticBatchingUtility类来控制静态批处理。

using UnityEngine;

public class StaticBatchingController : MonoBehaviour
{
    void Start()
    {
       StartStaticBatch();
    }

    GameObject[] GetGameObjectsToBatch()
    {
        // 返回需要静态批处理的游戏对象数组
        // 例如:可以通过标签、层级或者其他方式来获取需要静态批处理的游戏对象
        // 这里只是一个简单示例,实际情况可能需要根据具体需求来获取游戏对象
        return GameObject.FindGameObjectsWithTag("StaticBatchingObject");
    }
    void StartStaticBatch()
    {
        // 获取所有需要静态批处理的游戏对象
        GameObject[] gameObjectsToBatch = GetGameObjectsToBatch();
        // 执行静态批处理
        StaticBatchingUtility.Combine(gameObjectsToBatch, this.gameObject);
    }
    void StopStaticBatch()
    {
        // 禁用静态批处理
        StaticBatchingUtility.Combine(null, this.gameObject);
    }
}

动态批处理

通过将运行时动态地将多个静态或动态的游戏对象合并成一个批次,减少渲染调用的数量,提高帧率和性能。

渲染管线兼容性

特征 内置渲染管线 通用渲染管线 (URP) 高清渲染管线 (HDRP) 自定义可编程渲染管线 (SRP)
动态批处理 是的 是的 是的

静态批处理的设置

设置也很简单只需一步

在ProjectSettings→player→OtherSetting→DynamicBatching,勾选

动态批处理的限制

  • Unity 无法对包含超过 225 个顶点的网格应用动态批处理。这是因为网格的动态批处理每个顶点都有开销。
    使用顶点位置、顶点法线和单个 UV,则 Unity 最多可以批处理 225 个顶点。但是,如果着色器使用顶点位置、顶点法线、UV0、UV1 和顶点正切,则 Unity 只能批处理 180 个顶点。
  • 如果对象使用不同的材质实例,则 Unity 无法将它们批处理在一起,即使它们本质是使用一个shader。唯一的例外是阴影投射器渲染。
  • 带有光照贴图的游戏对象具有额外的渲染器参数。这意味着,如果要对光照映射的游戏对象进行批处理,它们必须指向相同的光照贴图位置。
  • Unity 无法将动态批处理完全应用于使用多个pass的shader对象。
    • 几乎所有 Unity 着色器都支持多个灯光前向渲染为了实现这一点,他们为每个光源处理一个额外的渲染通道。Unity 仅对第一个渲染通道进行批处理。它无法对额外的每像素光源的绘制调用进行批处理。

效果

Batches是8,Saved By Batching是220左右

enable gpu instancing,Unity,unity,游戏引擎

手动合并网格

手动将多个网格合并为一个网格,在网格靠得很近且彼此不相对移动的情况下,可以很好地替代,静态批处理和动态批处理。

警告:Unity 无法单独剔除您组合的网格。这意味着,如果组合网格的一部分出现在屏幕上,Unity 会绘制整个组合网格。如果网格是静态的,并且希望 Unity 单独剔除它们,使用静态批处理。

合并网格的设置方法

  • 在创作网格时在资源生成工具中。即模型制作阶段将其合并到一起,同时这样处理相同的模型会照成模型体量的变大。
  • 在 Unity 中使用 Mesh.CombineMeshes

CombineMeshes的用法

//强制添加组件
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
public class ExampleClass : MonoBehaviour
{
    void Start()
    {
        MeshFilter[] meshFilters = GetComponentsInChildren<MeshFilter>();
     //  CombineInstance 结构体 用于描述要使用 Mesh.CombineMeshes 组合的网格。
        CombineInstance[] combine = new CombineInstance[meshFilters.Length];

        int i = 0;
        while (i < meshFilters.Length)
        {
            combine[i].mesh = meshFilters[i].sharedMesh;
            combine[i].transform = meshFilters[i].transform.localToWorldMatrix;
            meshFilters[i].gameObject.SetActive(false);

            i++;
        }

        Mesh mesh = new Mesh();
        mesh.CombineMeshes(combine);
        transform.GetComponent<MeshFilter>().sharedMesh = mesh;
        transform.gameObject.SetActive(true);
    }
}
CombineInstance 字段 说明
lightmapScaleOffset 应用于网格的烘焙光照贴图UV比例和偏移量。
mesh 要组合的网格。
realtimeLightmapScaleOffset 应用于网格的实时光照贴图UV比例和偏移。
subMeshIndex 网格的子网格索引。
transform 在组合之前要变换网格的矩阵。有关示例,请参阅 Mesh.CombineMeshes。

效果

Batches是8,Saved By Batching是0

enable gpu instancing,Unity,unity,游戏引擎

遮挡剔除

遮挡剔除不说了

频繁使用遮挡剔除可能会导致一些性能问题,特别是在复杂的场景中。因为每次相机移动或场景发生变化时,都需要重新计算遮挡剔除信息,这可能会消耗一定的计算资源。

LOD

Unity中使用LOD(Level of Detail)时,可以根据相机与物体的距离,自动切换不同级别的模型,以提高性能和减少渲染开销。

unityLOD设置方法

  1. 创建多个不同级别的模型,分别代表远、中、近距离的模型。

  2. 将这些模型作为同一个游戏对象的子对象,并添加LOD Group组件。

  3. 在LOD Group组件中设置每个级别的距离和对应的模型。

  4. Unity会根据相机与物体的距离自动切换不同级别的模型。

    enable gpu instancing,Unity,unity,游戏引擎

效果

可以与静态批处理和动态批处理结合

Batches是11,Saved By Batching是310左右

enable gpu instancing,Unity,unity,游戏引擎

层剔除 layerCullDistances

用于指定摄像机在渲染不同图层时的剔除距离。通过设置layerCullDistances,可以控制摄像机在渲染不同图层时的剔除距离,从而提高渲染性能。层剔除和lod类似,也是按距离剔除,不同的是层剔除不会替换文章来源地址https://www.toymoban.com/news/detail-857475.html

float[] distances = new float[32];//设定32个默认图层
distances[11] = 300;//为第11层设定距离
Camera.mian.layerCullDistances = distances;//将剔除层传递给相机

到了这里,关于【Unity】 场景优化策略的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • [游戏开发]Unity Addressable打包策略

    Addressables的基础看这篇文章 Addressable全教程 最近公司在写新的框架,决定放弃老的bundle打包方式,使用Addressable,因此我要捋顺新的打包方案,并且解决所有疑问。 打包的最终目的是:build出一堆Bundle文件,而哪些因素会影响出包结果,总结一下有3个关键因素和1个非关键因

    2024年02月17日
    浏览(51)
  • unity场景转换(实现开始游戏和返回游戏)

    1、新建两个场景,一个命名为start,另一个命名为game,如下图 2、打开start,创建一个平面和一个按钮(右键,UI,Button),平面绕X轴旋转-90度,按钮的text设置为开始游戏,把按钮拖到场景中合适的位置,如下图 3、编写代码start,把它赋给Canvas,注意是赋给Canvas,不是给按钮,代

    2024年02月11日
    浏览(44)
  • Unity2020 Unity2021 场景灯光烘焙简单教程,Unity场景灯光优化, 一些简单的问题

    吃饱饭 多喝水 睡好觉 将需要烘焙的场景和不需要烘焙的场景不放到一个父物体下面 模型尽量是分开的, 烘焙很耗费时间,很吃显卡和CPU性能 将需要烘焙的场景设置为static 选择灯光,将灯光设置为bake 打开Lighting 窗口 (windows 》rendering》lighting) 烘焙,建议取消自动烘焙。

    2024年02月01日
    浏览(72)
  • Unity游戏开发:场景切换的实现

    在unity中可以将不同场景的背景和道具放置在不同的Scene当中,通过对Scene的加载和卸载来实现场景之间的切换。同时创建一个基础场景(Control Scene)来对整个游戏系统进行管理,在基础场景(Control Scene)中不放置背景图片或者游戏道具而只添加各种控制单元和Canvas。 在场景

    2024年02月15日
    浏览(49)
  • Unity中Batching优化的GPU实例化(1)

    在之前的文章中,我们解析了 Batching 优化中的 动态合批 和 静态合批。在这篇文章中我们来做一下 GPU实例化测试之前的准备 Unity中Batching优化的动态合批 Unity中Batching优化的静态合批 GPU实例化主要应用于大量网格生成的情况 我们先在Unity中,实现一下大量生成网格 public Gam

    2024年02月04日
    浏览(42)
  • Unity中Batching优化的GPU实例化(3)

    在上篇文章中,我们主要解析了 Unity 中 GPU实例化的定义 实例化ID 步骤干了什么。 Unity中Batching优化的GPU实例化(2) 我们在这篇文章中,把定义的 实例化ID 给使用起来,使合成一个批次的模型 包含的渲染的对象坐标显示正确。 UNITY_SETUP_INSTANCE_ID(v); 放在顶点着色器/片断着色

    2024年02月03日
    浏览(46)
  • Unity中Batching优化的GPU实例化(4)

    在之前的文章中,我们解决了GPU实例化需要的 appdata 、v2f 数据准备 和 使GPU实例化后的顶点位置正确。 Unity中Batching优化的GPU实例化(2) Unity中Batching优化的GPU实例化(3) 在这篇文章中,我们来实现一下GPU实例化后怎么使不同对象使用不同的材质颜色,这里只是用颜色作为例

    2024年02月05日
    浏览(57)
  • Unity-UGUI优化策略

    界面出栈规则: 界面目录导航、策划界面回退需求造成界面套娃问题,夹带一系列层级问题,应该和策划进行友好沟通,避免界面不合理的出栈入栈规则 overdraw: 尽量减少同屏 半透明物体渲染 Unity 之 UGUI优化(Optimizing UGUI)—当最专业的拖拖拽拽

    2024年02月13日
    浏览(47)
  • Unity GPU Skinning Tool: 提升3D游戏动画性能的新利器

    项目地址:https://gitcode.com/ForeverZack/Unity-Gpu-Skinning-Tool 在Unity引擎的世界里,Unity GPU Skinning Tool是一个强大的工具,它将骨骼动画计算从CPU转移到GPU,显著提高了游戏中的角色动画性能。对于那些需要大量3D角色与复杂动画的游戏开发者而言,这是一个非常值得尝试的技术。 Un

    2024年04月25日
    浏览(51)
  • Unity常用设计模式-策略模式:游戏中的智慧选择

    一、什么是策略模式?        策略模式是一种行为设计模式,它定义了一系列算法,并使得这些算法可以相互替换,而使得使用算法的客户端代码不受影响。在策略模式中,算法被封装成独立的类,使得它们可以独立于客户端而变化。这种模式提供了一种简单而强大的方法

    2024年02月20日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包