Search Unity

Question Graphics.DrawMeshInstancedIndirect Questions

Discussion in 'General Graphics' started by FE-Games, Apr 12, 2021.

  1. FE-Games

    FE-Games

    Joined:
    Jul 1, 2020
    Posts:
    15
    Hello,

    I came across the Graphics.DrawMeshInstancedIndirect feature for a few days.
    There are some things I don't really understand yet.

    1. Explain the arguments

    Code (CSharp):
    1. Graphics.DrawMeshInstancedIndirect(instanceMesh, 0, instanceMaterial, new Bounds(Vector3.zero, new Vector3(100.0f, 100.0f, 100.0f)), argsBuffer);
    iam only have 1 material for my whole game, so i don't need submeshIndex.

    frist when iam generating something outside the bounds, whats then?

    argsBuffer is the most confusing thing for me.

    Code (CSharp):
    1.         // Indirect args
    2.         if (instanceMesh != null) {
    3.             args[0] = (uint)instanceMesh.GetIndexCount(0);
    4.             args[1] = (uint)instanceCount;
    5.             args[2] = (uint)instanceMesh.GetIndexStart(0);
    6.             args[3] = (uint)instanceMesh.GetBaseVertex(0);
    7.         } else {
    8.             args[0] = args[1] = args[2] = args[3] = 0;
    9.         }
    10.         argsBuffer.SetData(args);
    that's in the docs, but i don't need submeshIndex so args (0,2,3) are useless for me?

    In my case, the shader needs to know the positions and colors of each object.
    How can I use the arguments to save space?

    this is what iam doing:
    (its only do it once in start for testing)

    Code (CSharp):
    1.         if (positionBuffer != null) {
    2.             positionBuffer.Release();
    3.         }
    4.        
    5.         positionBuffer = new ComputeBuffer(instanceCount, 16);
    6.         positionBuffer.SetData(positions);          
    7.         instanceMaterial.SetBuffer("positionBuffer", positionBuffer);
    8.        
    9.        
    10.         if (colorBuffer != null) {
    11.             colorBuffer.Release();
    12.         }
    13.        
    14.         colorBuffer = new ComputeBuffer(instanceCount, 16);
    15.         colorBuffer.SetData(colors);
    16.         instanceMaterial.SetBuffer("colorBuffer", colorBuffer);
    there are 2 buffers (one for positions and one for colors) both are Vector4.
    iam also don't know what "positionBuffer.Release()" does.


    All i want is:
    generate thousants of same meshes, with different colors (also transparency)

    currently my gpu (render threat) is 0.2ms but my cpu is over 14.7ms why??

    2. is Graphics.DrawProceduralIndirect faster then InstancedIndirect when i try to generate a world?


    hope i learn more about it.

    Some improvements would be better variables for me to take. The colors do not have to be given to the shader via a Vector4 but as an int (since each color has its own value).

    3. what does the 4th Argument in Vector4 positions do?

    thank you iam new in scripting shaders so, i only understand single things.
     
  2. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    2,285
    Hi,

    the bounds is used for CPU frustum culling. If you know the max extents of what you plan to draw, from script, set it appropriately, otherwise make it huge.

    you need to set index 0 and 1 in the args buffer (indices in the submesh, and how many instances) even if you only have 1 submesh.

    positionBuffer.Release deletes the compute buffer. Its data won’t be available anywhere after this line (gone from cpu and gpu)

    DrawProceduralIndirect does not use a pre-authored mesh. So it’s not about being faster/slower, it’s for a different use (eg when you want to construct geometry procedurally in a shader, such as lots of camera facing billboards)

    The 4th value in a position is called a Homogenous Coordinate. You would be best Googling that term to learn about it. Usually it’s good enough to just set it to 1.0 and forget about it.

    (I’ve not answered everything - only what I can) :)
     
  3. FE-Games

    FE-Games

    Joined:
    Jul 1, 2020
    Posts:
    15
    Thank you so much for the answers.

    What can i do to reduce the amount of data transfered between cpu and gpu, like the ComputeBuffers? iam have two computebuffers, one for position and one for color.

    My positions allways integers so is there a way to make it smaller?

    Code (CSharp):
    1.                 fixed3 localPosition = v.vertex.xyz * data.w;
    2.                 fixed3 worldPosition = data.xyz + localPosition;
    3.                 fixed3 worldNormal = v.normal;
    What is worldNormal I don't know yet, but do all 3 variables have to be set?
     
    Last edited: Apr 12, 2021
  4. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    2,285
    If you do not require 32bit integers for your coordinates, you could pack them into 16 bit integers.
    in your structured buffer shader that would look like:

    uint2 fourPacked16BitIntegers;

    uint value0 = asint(fourPacked16BitIntegers.x & 0xffff);
    uint value1 = asint(fourPacked16BitIntegers.x >> 16);
    uint value2 = asint(fourPacked16BitIntegers.y & 0xffff);

    that would be your xyz. if you can fit in 16 bits the positions must be -32K to +32K.

    and in your script you would have to pack the values too.
    packing data like this is a separate topic tho, best researched online, if it's unfamiliar to you.

    As for the normal, you need that for lighting. it says which direction the surface is facing, so we can calculate how brightly it is lit. if you are only moving the mesh positions with the instance data, the normal should be fine to just use the mesh normal unchanged. but if you start rotating your meshes, you'll need more instsance data for rotation, and this will affect the output normal too.

    i presume you saw the example, but just in case: on: https://docs.unity3d.com/ScriptReference/Graphics.DrawMeshInstancedIndirect.html
     
  5. FE-Games

    FE-Games

    Joined:
    Jul 1, 2020
    Posts:
    15
    Hello, sorry but i don't understand what you mean with uint (uint is for me totally new).

    My Shader is this:
    Code (CSharp):
    1. Shader "Instanced/InstancedVertexShader" {
    2.     SubShader {
    3.         Tags { "RenderType"="Opaque" }
    4.         Tags {"Queue"="Transparent" "IgnoreProjector"="True"}
    5.         Blend SrcAlpha OneMinusSrcAlpha
    6.         LOD 100
    7.  
    8.         Pass {
    9.             CGPROGRAM
    10.             #pragma vertex vert
    11.             #pragma fragment frag
    12.             #pragma multi_compile_instancing
    13.             #include "UnityCG.cginc"
    14.  
    15.             StructuredBuffer<fixed4> positionBuffer;
    16.             StructuredBuffer<fixed4> colorBuffer;
    17.            
    18.             struct v2f
    19.             {
    20.                 fixed4 vertex : SV_POSITION;
    21.                 fixed4 color : COLOR0;
    22.             };
    23.  
    24.             v2f vert(appdata_full v, uint instanceID : SV_InstanceID) {
    25.                
    26.                 fixed4 data = positionBuffer[instanceID];  
    27.                 fixed4 color = colorBuffer[instanceID];
    28.                 fixed3 localPosition = v.vertex.xyz * data.w;
    29.                 fixed3 worldPosition = data.xyz + localPosition;
    30.                 fixed3 worldNormal = v.normal;
    31.                                
    32.                 v2f o;
    33.                 o.vertex = mul(UNITY_MATRIX_VP, fixed4(worldPosition, 1.0f));
    34.                 o.color = color;
    35.                 return o;
    36.             }
    37.            
    38.             fixed4 frag (v2f i) : SV_Target
    39.             {
    40.                 return i.color;
    41.             }
    42.             ENDCG
    43.         }
    44.     }
    45. }
    i got two questions:

    where to put in uint thing what you say and what does it do.

    and does this shader needs #pragma multi_compile_instancing?
    because if i remove it or let it in i can't see a different inside unity when i hit play.