• Unity GPU Instancing的使用尝试


    似乎是在Unity5.4中开始支持GPU Instacing,但如果要比较好的使用推荐用unity5.6版本,因为这几个版本一直在改。

    这里测试也是使用unity5.6.2进行测试

    在5.6的版本里,Instancing不再是一个单独的shader,而是一个开关。

    如果使用Instancing功能需要开启,否则调用相关接口时会报错

    默认情况下,多个一样的模型会被动态批次合并优化掉,动态批次合并有很多种情况不可用,其中一种就是镜像的情况。

    这里用镜像后的实例模型和GPU Instancing做比较

    注意,在Unity5.6.2或者之后的版本中,只要材质球勾选Instancing,即自动开启并使用GPU Instancing。

    GPU Instancing大致代码如下(用Graphics一次性调用减少了层级对象的创建开销):

    void Update()
    {
        var meshRenderer = template.GetComponent<MeshRenderer>();
        var meshFilter = template.GetComponent<MeshFilter>();
        var mesh = meshFilter.sharedMesh;
        var matrices = new Matrix4x4[instanceCount];
    
        for (int i = 0; i < matrices.Length; i++)
        {
            var position = Random.insideUnitSphere * range;
            var rotation = Quaternion.LookRotation(Random.insideUnitSphere);
            var scale = Vector3.one * Random.Range(-2f, 2f);
            var matrix = Matrix4x4.TRS(position, rotation, scale);
    
            matrices[i] = matrix;
        }
    
        Graphics.DrawMeshInstanced(mesh, 0, meshRenderer.sharedMaterial, matrices);
    }

    是实时随机的位置,会看见只有13个Batches.

    常规实例化测试脚本(挂了正弦运动脚本,注意镜像反转,使其无法动态批次合并):

    for (int i = 0; i < instanceCount; i++)
    {
        var instancedTemplate = Instantiate(template);
        instancedTemplate.transform.position = Random.insideUnitSphere * range;
        instancedTemplate.transform.forward = Random.insideUnitSphere;
        instancedTemplate.transform.localScale = Vector3.one * Random.Range(-2f, 2f);
    }

    大概在1020个Batches

     另外我还打了个APK包测了下,居然能在我的红米3S上跑。这就有点厉害了

    那么GPU Instacing其实也有一些限制的,比如不支持蒙皮网格等(不过资源商店有一个Animation Instacing: 链接)

    (补充:Unity官方开源了一个Animation Instacing: https://blogs.unity3d.com/cn/2018/04/16/animation-instancing-instancing-for-skinnedmeshrenderer/)

    这些支持信息在官网的页面都有罗列 https://docs.unity3d.com/Manual/GPUInstancing.html

    硬件需求:

    GPU Instancing is available on the following platforms and APIs:

    • DirectX 11 and DirectX 12 on Windows

    • OpenGL Core 4.1+/ES3.0+ on Windows, macOS, Linux, iOS and Android

    • Metal on macOS and iOS

    • Vulkan on Windows and Android

    • PlayStation 4 and Xbox One

    • WebGL (requires WebGL 2.0 API)

     

    模块间的需求(没找到原版的帖子,翻译版摘抄一段):

    下列情况不能使用Instancing:

    • 使用Lightmap的物体
    • 受不同Light Probe / Reflection Probe影响的物体
    • 使用包含多个Pass的Shader的物体,只有第一个Pass可以Instancing前向渲染时,受多个光源影响的物体只有Base Pass可以instancing,Add Passes不行

    另外,默认的DrawMeshInstanced有1024实例数的限制

    需要DrawMeshInstancedIndirect,而这个接口依赖ComputerShader,一些平台不支持。

    然后再测一下GPU Instanced Indirect,也就是DrawMeshInstancedIndirect这个接口

    似乎是借助ComputerShader实现超过1024数量的Instancing

    下图为3万个Cube:

    代码和shader我做了点修改,大致如下:

    void Update()
    {
        // Update starting position buffer
        if (cachedInstanceCount != instanceCount) UpdateBuffers();
    
        for (int i = 0; i < mPositions.Length; i++)
        {
            float angle = Random.Range(0.0f, Mathf.PI * 2.0f);
            float distance = Random.Range(20.0f, 100.0f);
            float height = Random.Range(-2.0f, 2.0f);
            float size = Random.Range(0.05f, 0.25f);
            mPositions[i] = new Vector4(Mathf.Sin(angle) * distance, height, Mathf.Cos(angle) * distance, size);
        }
    
        positionBuffer.SetData(mPositions);
        instanceMaterial.SetBuffer("positionBuffer", positionBuffer);
    
        // Render
        Graphics.DrawMeshInstancedIndirect(
            instanceMesh,
            0,
            instanceMaterial,
            new Bounds(Vector3.zero, new Vector3(100.0f, 100.0f, 100.0f)),
            argsBuffer);
    }

    shader需要额外定制,这点比较蛋疼。如果换成standard读不到positionBuffer这种结构。

    DrawMeshInstancedIndirect的具体使用案例,可以参考这两个链接:

    https://docs.unity3d.com/ScriptReference/Graphics.DrawMeshInstancedIndirect.html

    https://github.com/tiiago11/Unity-InstancedIndirectExamples

    补充测试工程地址https://gitee.com/Hont/GPUInstancingTest

    (unity2017.4)

    扩展阅读:

    Geometry instancing

    https://en.wikipedia.org/wiki/Geometry_instancing

    Unity中的批处理优化与GPU Instancing

    http://forum.china.unity3d.com/thread-22714-1-3.html

  • 相关阅读:
    docker私有仓库harbor的安装及使用
    docker 搭建 zipkin
    docker安装redis并以配置文件方式启动
    docker 安装 mysql5.7.25
    什么是反射?可以解决什么问题?
    什么是死锁?如何防止死锁?
    说说TCP和UDP的区别
    什么是XSS攻击?
    怎么更改Visual Studio项目名字
    windows上使用getopt和getopt_long
  • 原文地址:https://www.cnblogs.com/hont/p/7143626.html
Copyright © 2020-2023  润新知