升级版GPUInstancing

1. 痛点

昨天在CS的博客笔记里我琢磨了下DrawMeshInstancing,有提到他一次draw最多支持1023个,在多就要加drawcall,此外如果是动态数据还要每帧向GPU索要数据并在CPU端更新网格坐标,因此有如下两个痛点:

  1. 多于1023个坐标就要切分数组,加drawcall,1023*1024个物体就是1024个drawcall
  2. GPU和CPU数据每帧传递浪费时间

下面就有一个新的方法来解决以上痛点,u1s1,百度出来的资料真的是不行,还是要科学冲浪。
api:Graphics.DrawMeshInstancedIndirect
他的原理是将物体的坐标等信息逐mesh的打包成数组传给GPU显存,依据instanceID为数组下标,在shader中直接获取某个mesh的信息(浅见)。
也就是在shader中加一个StructuredBuffer<>并以instanceID为下标来区分不同的mesh draw,属于是CS和shader的缝合怪。
这一下就解放双手了

Shader "Custom/UnlitInstanceIndirectShader"
{
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_instancing nolightmap nodirlightmap nodynlightmap novertexlight
            
            #include "UnityCG.cginc"

            struct MeshProperties 
            {
                float4x4 mat; // world matrix
                float4 color;
            };
            StructuredBuffer<MeshProperties> _Properties;

            struct appdata
            {
                float4 vertex : POSITION;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;   
                float4 color : COLOR;
            };

            v2f vert(appdata v, uint instanceID : SV_InstanceID)
            {
                v2f o;
                o.vertex = mul(_Properties[instanceID].mat, v.vertex);
                o.vertex = mul(UNITY_MATRIX_VP, o.vertex);
                o.color = _Properties[instanceID].color;
                return o;
            }

            fixed4 frag(v2f o) : SV_Target
            {
                return o.color;
            }
            ENDCG
        }
    }
}

这样,CPU只需要在初始化的时候给GPU传一次数据,然后把全部的工作交给GPU就可以了,由GPU托管数据,由CS来更新数据,由shader渲染数据,完美。

2. 如何使用

CS,shader和C#都要安排,尝试写一个能用一个坐标推开一百万个物体的demo
shader上面已经贴了,下面写C#

2.1 CPU端

Graphics.DrawMeshInstancedIndirect 参数描述
mesh 要绘制的mesh
submeshIndex mesh的子集
material 使用的材质
bounds 包围盒,如果这个包围盒超出视锥,unity会自动取消这次drawcall(不是剔除画出来的某单独的东西),这一堆渲染物体内部的剔除还是要自己做
bufferWithArgs 一个包含5个参数的ComputeBuffer,里面存着一些八股参数
argsOffset 后面都暂时用不着
properties 这个没用了,因为最多就存1023个数据
castShadows
receiveShadows
layer
camera
lightProbeUsage

这个bufferWithArgs一开始我没搞懂是干啥的,后来发现没啥用,跟着官方demo抄就行,参数个个顾名思义,好像没什么修改意义。

public class TestComputeShader : MonoBehaviour
{
   
    const int Range = 1024;
    const int Population = Range * Range;

    public Mesh mesh;  // 手拖unity内置mesh
    public Material mat;  // 手拖

    private ComputeBuffer meshPropertiesBuffer;
    private ComputeBuffer argsBuffer;

    public 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值