读一读

public enum CardMaterialGroupNameDefine
{ 
    Bag,
    DeckGroup,
    DeckList,
    Max
}

public class CardMaterialGroup
{
    private CardMaterialGroupNameDefine m_Define;
    private Dictionary<string, Material> m_Materials = new Dictionary<string, Material>();
    public CardMaterialGroup(CardMaterialGroupNameDefine define)
    {
        m_Define = define;
    }


    public Material GetMaterial(bool isAi, bool isDark)
    {
        string name = (isAi ? "AI" : "Normal") + "_" + (isDark ? "Dard" : "NoDard");
        if (m_Materials.TryGetValue(name, out var mat))
        {
            return mat;
        }

        var originMat = RK.Mat.GetMaterialInstance(isAi ? AddressablePath.Material.AICardKuangMaterial : AddressablePath.Material.NormalCardKuangMaterial);
        mat = GameObject.Instantiate(originMat);
        mat.name = $"{mat.name}_{m_Define.ToString()}_{name}";
        m_Materials.Add(name, mat);
        return mat;
    }
}

public class CardMaterialMgr : RK_Singleton<CardMaterialMgr>
{
    private Dictionary<CardMaterialGroupNameDefine, CardMaterialGroup> m_CardMaterialGroupMap = new Dictionary<CardMaterialGroupNameDefine, CardMaterialGroup>();

    public CardMaterialMgr()
    {
        for (int i = 0; i < (int)CardMaterialGroupNameDefine.Max; i++)
        {
            var define = (CardMaterialGroupNameDefine)i;
            var group = new CardMaterialGroup(define);
            m_CardMaterialGroupMap.Add(define, group);
        }
    }

    public CardMaterialGroup GetCardMaterialGroup(CardMaterialGroupNameDefine define)
    {
        if (m_CardMaterialGroupMap.TryGetValue(define, out var group))
        { 
            return group;
        }

        return null;
    }
}


通过材质管理 使同一类型状态使用同一个材质,使其符合合批条件或则GUP Instance条件


#pragma multi_compile_instancing //ADD

struct appdata_t {
    float4 vertex : POSITION;
    float2 texcoord : TEXCOORD0;
    UNITY_VERTEX_INPUT_INSTANCE_ID //ADD
};

struct v2f {
    float4 vertex : SV_POSITION;
    float2 texcoord : TEXCOORD0;
    UNITY_VERTEX_INPUT_INSTANCE_ID //ADD
};

v2f vert (appdata_t v)
{
    v2f o;
    UNITY_SETUP_INSTANCE_ID(v); //ADD
    UNITY_TRANSFER_INSTANCE_ID(v, o); //ADD
    o.vertex = UnityObjectToClipPos(v.vertex);
    o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
    return o;
}


fixed4 frag (v2f i) : SV_Target
{
    UNITY_SETUP_INSTANCE_ID(i); //ADD
    fixed4 c = tex2D(_MainTex, i.texcoord) * _Color;
    c.a *= _AlphaMix;

    return c;
}






一个场景都是有很多的模型构建而成的,如果要热更新资源就需要细化每一个资源,把每一个资源下载下来然后拼凑在一起形成完整的场景。这些装饰型的场景部件很多都是静态的,所以我们可以把这些部件以材质为分组,对于同一个材质的部件可以放到同一个空物体下,然后在空物体上添加脚本,把子物体的内容静态批处理,减少DC。

using UnityEngine;

public class StaticBind : MonoBehaviour {
    
    void Start () {
        StaticBatchingUtility.Combine(gameObject);
    }
}

Shader有一个值叫LOD,只有LOD值小于某个设定的值,这个Shader才会被使用,而使用了那些超过设定值的Shader的物体将不会被渲染。可以通过Shader.globalMaximumLOD来设置这个最大值,不限定设置的大小。

void Start () {
    Shader.globalMaximumLOD = 251;
}

图片.png

图片.png


LOD的技术原理就是当一个物体离摄像机很远时,模型上的很多细节是无法被察觉到的,因此,LOD允许当对象逐渐远离摄像机时,减少模型上的面片数量,从而提高性能

在Unity中,使用一个添加上LOD Group组件来使用LOD功能,将事先准备好的多个包含不同细节程度的模型分别赋值给LOD Group组件中的不同等级,Unity会自动判断当前位置上需要使用哪个等级的模型。

GIF1.gif

GIF.gif


在建模的时候,尽量减少模型中三角面片的数目。在Unity中显示的顶点数目要比建模软件中显示的顶点数多,这是因为Unity在渲染角度上去理解,在GPU看来,有时需要把一个顶点拆分成两个或更多的顶点,一是为了分离纹理坐标,二是为了产生平滑的边界。例如一个立方体,相同的顶点,但在不同的面上,他的纹理坐标是不一样的,所以会拆分为多个顶点。而平滑边界也是类似的,不过就是同一个顶点会对应多个法线信息或切线信息。对于GPU来讲,顶点的每一个属性和顶点之间必须是一对一的关系。

所以在建模优化的时候,移除不必要的硬边以及纹理衔接,避免边界平滑和纹理分离


一、静态批处理

应用在那些一开始就不动的物体上,只需要在Inspector上吧Static勾选上就可以了。不允许移动和其他处理了。Unity会在一开始运行的时候将这些Static的网格物体变换到世界空间中只合并处理一次为更大的顶点和索引缓存,对于使用相同材质的物体,Unity只需要使用一个DC就可以绘制完成了。对于使用不同材质的物体也可以提升渲染性能,尽管需要调用多个DC,但是静态批处理可以减少这些DC之间的状态切换,往往这些状态的切换是很费时的。注意:静态批处理会占用更多的内存来存储合并的几何结构,如果一些物体共享了相同的网格,那么在内存中每一个物体都会对应一个该网格的复制品。

二、动态批处理

动态批处理是Unity自动进行的,如果需要使用静态批处理就需要满足一定的条件:需要使用相同的材质、网格的顶点属性规模要小于900(顶点位置、法线、纹理坐标),也就是顶点数目不要超过300,因为Unity使用动态批处理时需要每一帧的去将这些网格合并、多Pass的Shader会中断批处理,例如在直射光的前提下加多了一个Spot Light灯光,Shader会调用额外的Pass去叠加灯光效果。

三、Enable GPU Instancing

这是最新渲染api提供的一种技术,可以在材质上勾选它打开。如果绘制1000个物体,他将一个模型的vbo(顶点缓冲)提交给一次显卡,至于1000个物体不同的位置、状态、颜色等等将他们整合成一个per instance attribute的buffer给gpu,在显卡上区别绘制,它大大减少了提交次数,这对于需要绘制大量相同模型的物体来说非常高效同时避免了合批的内存浪费。