【问题标题】:How reduce draw call in this sence? URP SRP Batcher在这种情况下如何减少绘图调用? URP SRP 批处理器
【发布时间】:2022-09-27 15:05:24
【问题描述】:

Unity2021.3.10f1、URP、SRP Batcher 开启

为此,我创建了一个 10x10x10 的立方体矩阵。 立方体是一个预制件。它的默认大小为 1:1:1,具有与 SRP Batcher 兼容的着色器。

现在运行时有 5000 多个批次。如何减少批次?

  • SRP 批处理器用于 Scriptable Render 管道,与 URP 不太兼容。你试过关掉它吗?
  • 是的,我试过了。批量减少到 50~60。相同的 FPS。实际上,我想优化这个场景的 FPS。很多相同的立方体,绘制它们花费了太多的 CPU。
  • 您是否尝试过 GPU 实例化?
  • 谢谢你。我已经尝试过 GPU 实例。那个立方体需要盒子对撞机。我不知道如何添加碰撞。我会寻找它。
  • 尝试GpuInstancingForGameObjects.csdrag&drop 所有这些都是 gpu 实例化的)

标签: unity3d urp


【解决方案1】:

// scr* https://gist.github.com/andrew-raphael-lukasik/df4a36ff2ad89078258fd653c422a021
using System.Collections.Generic;
using UnityEngine;

public class GpuInstancingForGameObjects : MonoBehaviour
{
    [SerializeField] Camera _camera = null;
    [SerializeField] MeshRenderer[] _meshRenderers = new MeshRenderer[0];
    
    /// <summary>
    /// Prefer "true" ☑ as "false" ☐ require updates every frame.
    /// It is a good idea to keep lists of still and moving mesh renderers in a separate components.
    /// </summary>
    public bool meshesAreStill = true;

    Dictionary<(Mesh mesh,Material material),(List<Transform> transforms,Bounds aabb)> _sources = new Dictionary<(Mesh,Material),(List<Transform>,Bounds)>();
    Dictionary<(Mesh mesh,Material material),(Matrix4x4[] matrices,Bounds aabb)> _batches = new Dictionary<(Mesh,Material),(Matrix4x4[],Bounds)>();
    Dictionary<int,Stack<Matrix4x4[]>> _freeMatrices = new Dictionary<int,Stack<Matrix4x4[]>>();
    Plane[] _frustum = new Plane[6];
    
    void Start ()
    {
        Initialize();
        UpdateMatrices();

        if( _camera==null ) _camera = Camera.main;
        if( _camera==null )
        {
            Debug.LogError( "no camera, can't continue" , this );
            enabled = false;
        }
    }

    void Update ()
    {
        if( !meshesAreStill ) UpdateMatrices();

        GeometryUtility.CalculateFrustumPlanes( _camera , _frustum );
        foreach( var batch in _batches )
        {
            var meshMaterialPair = batch.Key;
            var matricesAabbPair = batch.Value;
            var aabb = matricesAabbPair.aabb;
            if( GeometryUtility.TestPlanesAABB(_frustum,aabb) )
            {
                Graphics.DrawMeshInstanced(
                    mesh:           meshMaterialPair.mesh ,
                    submeshIndex:   0 ,
                    material:       meshMaterialPair.material ,
                    matrices:       matricesAabbPair.matrices
                );
            }
        }
    }

    #if UNITY_EDITOR
    // void OnDrawGizmosSelected ()
    void OnDrawGizmos ()
    {
        Initialize();

        Gizmos.color = Color.yellow;
        foreach( var source in _sources )
        {
            var transformsAabbPair = source.Value;
            var aabb = transformsAabbPair.aabb;
            Gizmos.DrawWireCube( aabb.center , aabb.size );
            
            if( Application.isPlaying && !GeometryUtility.TestPlanesAABB(_frustum,aabb) )
                UnityEditor.Handles.Label( aabb.center , "(out of camera view)" );
        }
    }
    #endif

    void Initialize ()
    {
        _sources.Clear();
        foreach( var meshRenderer in _meshRenderers )
        {
            if( meshRenderer==null ) continue;
            var meshFilter = meshRenderer.GetComponent<MeshFilter>();
            if( meshFilter==null ) continue;
            var mesh = meshFilter.sharedMesh;
            if( mesh==null ) continue;
            foreach( var material in meshRenderer.sharedMaterials )
            {
                if( !material.enableInstancing && Application.isPlaying )
                {
                    Debug.LogWarning($"\"{material.name}\" material won't be rendered as it's <b>GPU Instancing</b> is not enabled",meshRenderer);
                    continue;
                }
                if( material==null ) continue;
                var aabb = meshRenderer.bounds;
                var meshMaterialPair = ( mesh , material );
                if( _sources.ContainsKey( meshMaterialPair ) )
                {
                    var transforms = _sources[meshMaterialPair].transforms;
                    transforms.Add( meshRenderer.transform );

                    var newAabb = _sources[meshMaterialPair].aabb;
                    newAabb.Encapsulate( aabb );

                    _sources[meshMaterialPair] = ( transforms , newAabb );
                }
                else
                {
                    _sources.Add( meshMaterialPair , ( new List<Transform>(){ meshRenderer.transform } , aabb ) );
                }
            }
            if( Application.isPlaying )
                meshRenderer.enabled = false;
        }
    }

    void UpdateMatrices ()
    {
        foreach( var batch in _batches )
        {
            var matricesAabbPair = batch.Value;
            var matrices = matricesAabbPair.matrices;
            if( _freeMatrices.ContainsKey( matrices.Length ) )
            {
                _freeMatrices[matrices.Length].Push( matrices );
            }
            else
            {
                var stack = new Stack<Matrix4x4[]>();
                stack.Push( matrices );
                _freeMatrices.Add( matrices.Length , stack );
            }
        }
        _batches.Clear();

        foreach( var source in _sources )
        {
            var meshMaterialPair = source.Key;
            var transformsAabbPair = source.Value;
            var transforms = transformsAabbPair.transforms;
            
            int numTransforms = transforms.Count;
            Matrix4x4[] matrices = null;
            if( _freeMatrices.ContainsKey(numTransforms) && _freeMatrices[numTransforms].Count!=0 )
            {
                matrices = _freeMatrices[numTransforms].Pop();
            }
            else matrices = new Matrix4x4[ numTransforms ];

            for( int i=0 ; i<numTransforms ; i++ )
                matrices[i] = transforms[i].localToWorldMatrix;
            _batches.Add( meshMaterialPair , ( matrices , transformsAabbPair.aabb ) );
        }
    }

}

此解决方案提供 AABB 截头体剔除,不足以优化您的体素类案例。如果您认为这些框代表体素,那么您的下一步将是在此处实现体素遮挡剔除(隐藏此形状内的框)。

【讨论】:

    猜你喜欢
    • 2014-05-17
    • 1970-01-01
    • 1970-01-01
    • 2013-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多