Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question Dynamically Setting shader properties using ComputeBuffers

Discussion in 'Shaders' started by Opeth001, Apr 18, 2021.

  1. Opeth001

    Opeth001

    Joined:
    Jan 28, 2017
    Posts:
    1,112
    Hello everyone,

    im creating a custom hybrid renderer that is based on DrawMeshInstancedIndirect to minimize CPU work and data sync between CPU->GPU (GPU Buffering) by offloading all jobs like culling... to the GPU using ComputeShaders and ComputBuffers.

    im trying to support shader properties override in my custom hybrid renderer, but to make this work with different shaders, i need to dynamically set properties for every shader based on it's properties overrides.

    note: the cpu knows for each DrawCall what properties need to be modified. (propertyName/propertyID and value)

    so, what is the best way to dynamically set properties from within a shader like MaterialPropertyBlock does internally ?

    Any advice and suggestions will be greatly appreciated!
    Thank you!
     
    Last edited: Apr 18, 2021
  2. Opeth001

    Opeth001

    Joined:
    Jan 28, 2017
    Posts:
    1,112
    i ended up creating a Computebuffer holding a struct with Float4[FixedSize] buffer, so i can dynamically put values in it.
    in CPU side every element within the ComputeBuffer looks like this:
    //all fields are blittable and linear in the structure, so I can set the values in Bursted Jobs by interpreting the structure as NativeArray <float4>.
    Code (CSharp):
    1. private struct Properties
    2.     {
    3.         public Unity.Mathematics.float4 value0;
    4.         public Unity.Mathematics.float4 value1;
    5.         public Unity.Mathematics.float4 value2;
    6.         public Unity.Mathematics.float4 value3;
    7.         public Unity.Mathematics.float4 value4;
    8.         ...
    9.         public static int Cpu_Size()
    10.         {
    11.             return UnsafeUtility.SizeOf<Properties>();
    12.         }
    13.     }
    in GPU side every element within the ComputeBuffer looks like this:
    Code (CSharp):
    1. struct OverrideProperties {
    2.            float4 values[5];
    3. };
    4.  
    5. StructuredBuffer<OverrideProperties> _Properties;
    6.  
    This is how i access those data within the shader:
    Code (CSharp):
    1. Varyings vert(Attributes IN, uint instanceID: SV_InstanceID) {
    2.                     Varyings OUT = (Varyings)0;
    3.  
    4.                     UNITY_SETUP_INSTANCE_ID(IN);
    5.                     UNITY_TRANSFER_INSTANCE_ID(IN, OUT);
    6.                     UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
    7.  
    8.                     //Setup Properties
    9. #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED
    10. //Optimized in Compute Shader so CPU->GPU Upload by constructing worldMatrix by only passing Position,Rotation,Scale
    11. OverridePropertiesTest _property = _PropertiesTest[instanceID];
    12. unity_ObjectToWorld = float4x4(_property.values[0], _property.values[1], _property.values[2], _property.values[3]);
    13. OUT.color = _property.values[4];
    14. #endif
    15. ....
    16. return OUT;
    17.  }
    it worked for the Editor as well as for a low-end mobile device (Old OnePlus 2).
    I got a stable 60 ~ 57 fps by calling DrawMeshInstancedIndirect 40 times on a simple Mesh cube with 1000 instances per drawcall.

    the problem I am facing now is, suppose I have a custom ComputeBuffer containing ShaderPropertyIndex (Shader.PropertyToID) and data Type (Float, Float4..), how can i set the value like in the example above to the correct property from within the shader Once Per instanced (if possible)/ or within the vertex function?

    Thanks!
     
    Last edited: Apr 19, 2021