Unity GPU Instance(大量相同网格物体合批)

栏目: 后端 · 发布时间: 6年前

内容简介:在Unity中 同网格同材质的模型是可以合批的动态批处理和静态批处理都可以合批 但是都有其限制动态批处理有顶点数不能超过900的限制 只适合比较简单的模型

前言

在Unity中 同网格同材质的模型是可以合批的

动态批处理和静态批处理都可以合批 但是都有其限制

动态批处理有顶点数不能超过900的限制 只适合比较简单的模型

静态批处理的物体不能移动、旋转、缩放

如果动态静态批处理都无法使用 能否用其他方式合批呢?

可以尝试一下GPU Instance 虽然也有所限制 但是提供了更多可能

使用GPU Instancing的条件

1.Shader支持GPU Instancing

2.硬件支持GPI Instancing

3.代码动态绘制物体

硬件需求:

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不行

GPU Instancing确实可以动态合批 但是需要Shader的支持

虽然官方的Standard Shader提供了GPU Instance的选项 但是给材质设置不同颜色后合批失败了 这里有坑 使用了其他Shader后解决

GPU Instance测试

测试代码:

using UnityEngine;
using System.Collections.Generic;

/// <summary>
/// PropertyBlockTest
/// ZhangYu 2019-06-17
/// </summary>
public class PropertyBlockTest : MonoBehaviour {

    public GameObject prefab;
    public int count = 100;
    private Mesh insMesh;
    private Material insMaterial;
    private List<Matrix4x4> insMatrices;
    private MaterialPropertyBlock insBlock;
    private List<Color> insColors;
    private int colorID;

    private void Start () {
        GPUInstanceByBlock();
        //GPUInstanceByDrawMesh();
    }

    private void Update() {
        if (insMesh != null) DrawMeshes();
    }

    // 方法1:通过Shader + PropertyBlock 实现GPU Instance
    private void GPUInstanceByBlock() {
        MaterialPropertyBlock block = new MaterialPropertyBlock();
        int colorID = Shader.PropertyToID("_Color");
        GameObject[] objs = new GameObject[count];
        for (int i = 0; i < count; i++) {
            Vector3 position = new Vector3(Random.Range(-8, 8f), Random.Range(-4, 4f), 3);
            Color color = new Color(Random.Range(0, 1f), Random.Range(0, 1f), Random.Range(0, 1f));
            block.SetColor(colorID, color);
            GameObject obj = Instantiate(prefab);
            // 用Block代替Material设置值 这样就能合批了
            obj.GetComponent<MeshRenderer>().SetPropertyBlock(block);
            obj.transform.position = position;
            obj.SetActive(true);
        }
    }

    // 方法2:通过DrawMesh + Shader + PropertyBlock实现GPU Instance
    private void GPUInstanceByDrawMesh() {
        insMesh = prefab.GetComponent<MeshFilter>().mesh;
        insMaterial = prefab.GetComponent<Renderer>().material;
        insMatrices = new List<Matrix4x4>();
        insColors = new List<Color>();
        insBlock = new MaterialPropertyBlock();
        colorID = Shader.PropertyToID("_Color");
        for (int i = 0; i < count; i++) {
            Vector3 position = new Vector3(Random.Range(-8, 8f), Random.Range(-4, 4f), 3);
            Quaternion rotation = prefab.transform.rotation;
            Color color = new Color(Random.Range(0, 1f), Random.Range(0, 1f), Random.Range(0, 1f));
            // Position + Rotation + Scale > Matrix4x4
            Matrix4x4 matrix = TransformToMatrix(position, rotation);
            insMatrices.Add(matrix);
            insColors.Add(color);
        }
    }

    private void DrawMeshes() {
        // 测试结果:
        // 同网格 同材质 可以合批 需要Shader支持GPU Instance + 用PropertyBlock设置参数

        // DrawMeshInstanced() 一次绘制多个物体 调用一次 一个DrawCall
        //Graphics.DrawMeshInstanced(insMesh, 0, insMaterial, insMatrices, insBlock);

        // DrawMesh() 一次绘制一个物体 多次调用 可以合成一批
        for (int i = 0; i < count; i++) {
            insBlock.SetColor(colorID, insColors[i]);
            Graphics.DrawMesh(insMesh, insMatrices[i], insMaterial, 1, Camera.main, 0, insBlock);
        }
    }

    private Matrix4x4 TransformToMatrix(Vector3 position) {
        return Matrix4x4.TRS(position, Quaternion.identity, Vector3.one);
    }

    private Matrix4x4 TransformToMatrix(Vector3 position, Quaternion rotation) {
        return Matrix4x4.TRS(position, rotation, Vector3.one);
    }

    private Matrix4x4 TransformToMatrix(Vector3 position, Quaternion rotation, Vector3 scale) {
        return Matrix4x4.TRS(position, rotation, scale);
    }

}

测试Shader:

Shader "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;
        UNITY_VERTEX_INPUT_INSTANCE_ID
    };

    struct v2f
    {
        float4 vertex : SV_POSITION;
        UNITY_VERTEX_INPUT_INSTANCE_ID // necessary only if you want to access instanced properties in fragment Shader.
    };

        UNITY_INSTANCING_BUFFER_START(Props)
        UNITY_DEFINE_INSTANCED_PROP(float4, _Color)
        UNITY_INSTANCING_BUFFER_END(Props)

        v2f vert(appdata v)
    {
        v2f o;

        UNITY_SETUP_INSTANCE_ID(v);
        UNITY_TRANSFER_INSTANCE_ID(v, o); // necessary only if you want to access instanced properties in the fragment Shader.

        o.vertex = UnityObjectToClipPos(v.vertex);
        return o;
    }

    fixed4 frag(v2f i) : SV_Target
    {
        UNITY_SETUP_INSTANCE_ID(i); // necessary only if any instanced properties are going to be accessed in the fragment Shader.
        return  UNITY_ACCESS_INSTANCED_PROP(Props, _Color);
    }
        ENDCG
    }
    }
}

SkinMeshRender的GPU Instancing

Unity官方开源的Animation Instacing: https://blogs.unity3d.com/cn/...

CSDN博主

《Unity中使用GPU Instancing优化SkinnedMesh渲染》 https://blog.csdn.net/xoyojan...

参考资料:

《[unity]GPU Instance学习》: https://www.jianshu.com/p/ecf...

《使用MaterialPropertyBlock来替换Material属性操作》 https://blog.uwa4d.com/archiv...

《Unity3D研究院GPU Instancing实战(九十七)》 https://www.xuanyusong.com/ar...


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Data Structures and Algorithms with JavaScript

Data Structures and Algorithms with JavaScript

Michael McMillan / O'Reilly Media / 2014-2-22 / USD 28.51

If you’re using JavaScript on the server-side, you need to implement classic data structures that conventional object-oriented programs (such as C# and Java) provide. This practical book shows you how......一起来看看 《Data Structures and Algorithms with JavaScript》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

SHA 加密
SHA 加密

SHA 加密工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具