Skip to content

Instantly share code, notes, and snippets.

@unitycoder
Forked from ArieLeo/Usage.cs
Created December 6, 2023 09:16
Show Gist options
  • Select an option

  • Save unitycoder/c6e1cd29ceccbcef89d1e18b2ca07855 to your computer and use it in GitHub Desktop.

Select an option

Save unitycoder/c6e1cd29ceccbcef89d1e18b2ca07855 to your computer and use it in GitHub Desktop.

Revisions

  1. @Refsa Refsa revised this gist Oct 12, 2021. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion readme.md
    Original file line number Diff line number Diff line change
    @@ -11,4 +11,6 @@ The output from this goes into position output of vertex stage. It needs to be c

    Shader Graph should now work just as normal, just that it uses data passed from ComputeBuffers.

    Do note that the example code in Render.cs is sub-optimal and is mostly there as an example of how to use it from the C# side.
    Do note that the example code in Render.cs is sub-optimal and is mostly there as an example of how to use it from the C# side.

    You can find a sample unitypackage [here](https://github.com/Refsa/RendererEx/files/7304926/ShaderGraph_InstancedIndirect.zip)
  2. @Refsa Refsa revised this gist Oct 8, 2021. No changes.
  3. @Refsa Refsa revised this gist Oct 7, 2021. 1 changed file with 6 additions and 0 deletions.
    6 changes: 6 additions & 0 deletions Usage.cs
    Original file line number Diff line number Diff line change
    @@ -34,6 +34,12 @@ void Awake()
    SpawnExample();
    }

    void OnDestroy()
    {
    argsBuffer?.Release();
    drawDataBuffer?.Release();
    }

    void LateUpdate()
    {
    // Only needs to be called if "instances" changed
  4. @Refsa Refsa revised this gist Oct 7, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion readme.md
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,5 @@
    First is a passthrough custom function node that loads the hlsl code.
    ![image](https://user-images.githubusercontent.com/4514574/136415071-05981b0a-c9f2-4ee0-952d-83331c8afa42.png)
    ![image](https://user-images.githubusercontent.com/4514574/136416552-77720b60-db68-4671-9070-23eb060163ff.png)

    Second custom function node contains the code to setup procedural instancing.
    It needs to be implmeneted in a custom function node or else it wont work.
  5. @Refsa Refsa revised this gist Oct 7, 2021. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions readme.md
    Original file line number Diff line number Diff line change
    @@ -1,13 +1,13 @@
    First is a passthrough custom function node that loads the hlsl code.
    ![image](https://user-images.githubusercontent.com/4514574/136408156-2a544e66-9a39-4d19-b009-9307f47018fe.png)
    ![image](https://user-images.githubusercontent.com/4514574/136415071-05981b0a-c9f2-4ee0-952d-83331c8afa42.png)

    Second custom function node contains the code to setup procedural instancing.
    It needs to be implmeneted in a custom function node or else it wont work.
    Important bits is the `#pragma instancing_options procedural:setup` where "procedural:setup" calls a function in the included code in the previous node.
    ![image](https://user-images.githubusercontent.com/4514574/136408208-4417f688-6b12-4348-b02c-619c84f0d0c2.png)
    ![image](https://user-images.githubusercontent.com/4514574/136415101-590c1376-4190-46fa-952a-d0365f01b576.png)

    The output from this goes into position output of vertex stage. It needs to be connected for shader graph to compile it.
    ![image](https://user-images.githubusercontent.com/4514574/136408258-213deeb6-f537-41a9-b943-28de5d9963ca.png)
    ![image](https://user-images.githubusercontent.com/4514574/136415144-6315b5b0-6215-4521-ac8c-64494432ca95.png)

    Shader Graph should now work just as normal, just that it uses data passed from ComputeBuffers.

  6. @Refsa Refsa revised this gist Oct 7, 2021. 1 changed file with 49 additions and 32 deletions.
    81 changes: 49 additions & 32 deletions shaderGraphSupport.hlsl
    Original file line number Diff line number Diff line change
    @@ -1,53 +1,70 @@
    #ifndef SHADER_GRAPH_SUPPORT_H
    #define SHADER_GRAPH_SUPPORT_H

    #include "./Common.hlsl"
    // You could also upload the model matrix
    struct DrawData {
    float3 position;
    float4 rotation;
    float3 scale;
    };
    StructuredBuffer<DrawData> _DrawData;

    void calculatePos_float(in float4 vpos, out float4 worldPos)
    inline float4x4 TRSMatrix(float3 position, float4 rotation, float3 scale)
    {
    #if UNITY_ANY_INSTANCING_ENABLED
    DrawData drawData = _DrawData[unity_InstanceID];
    worldPos = TRS(drawData.position, drawData.rotation, drawData.scale, vpos);
    #else
    worldPos = vpos;
    #endif
    }
    float4x4 m = 0.0;

    void getData_float(out float3 position, out float4 rotation, out float3 scale)
    {
    #if UNITY_ANY_INSTANCING_ENABLED
    DrawData drawData = _DrawData[unity_InstanceID];
    position = drawData.position;
    rotation = drawData.rotation;
    scale = drawData.scale;
    #else
    position = 0;
    rotation = 0;
    scale = 1;
    #endif
    m[0][0] = (1.0 - 2.0 * (rotation.y * rotation.y + rotation.z * rotation.z)) * scale.x;
    m[1][0] = (rotation.x * rotation.y + rotation.z * rotation.w) * scale.x * 2.0;
    m[2][0] = (rotation.x * rotation.z - rotation.y * rotation.w) * scale.x * 2.0;
    m[3][0] = 0.0;

    m[0][1] = (rotation.x * rotation.y - rotation.z * rotation.w) * scale.y * 2.0;
    m[1][1] = (1.0 - 2.0 * (rotation.x * rotation.x + rotation.z * rotation.z)) * scale.y;
    m[2][1] = (rotation.y * rotation.z + rotation.x * rotation.w) * scale.y * 2.0;
    m[3][1] = 0.0;

    m[0][2] = (rotation.x * rotation.z + rotation.y * rotation.w) * scale.z * 2.0;
    m[1][2] = (rotation.y * rotation.z - rotation.x * rotation.w) * scale.z * 2.0;
    m[2][2] = (1.0 - 2.0 * (rotation.x * rotation.x + rotation.y * rotation.y)) * scale.z;
    m[3][2] = 0.0;

    m[0][3] = position.x;
    m[1][3] = position.y;
    m[2][3] = position.z;
    m[3][3] = 1.0;

    return m;
    }

    void getInstanceID_float(out float instanceID)
    inline void SetUnityMatrices(uint instanceID, inout float4x4 objectToWorld, inout float4x4 worldToObject)
    {
    #if UNITY_ANY_INSTANCING_ENABLED
    instanceID = rex_id;
    #else
    instanceID = 0;
    #endif
    }
    DrawData drawData = _DrawData[instanceID];

    objectToWorld = mul(objectToWorld, TRSMatrix(drawData.position, drawData.rotation, drawData.scale));

    void passthroughVec4_float(in float4 In, out float4 Out)
    {
    Out = In;
    float3x3 w2oRotation;
    w2oRotation[0] = objectToWorld[1].yzx * objectToWorld[2].zxy - objectToWorld[1].zxy * objectToWorld[2].yzx;
    w2oRotation[1] = objectToWorld[0].zxy * objectToWorld[2].yzx - objectToWorld[0].yzx * objectToWorld[2].zxy;
    w2oRotation[2] = objectToWorld[0].yzx * objectToWorld[1].zxy - objectToWorld[0].zxy * objectToWorld[1].yzx;

    float det = dot(objectToWorld[0].xyz, w2oRotation[0]);
    w2oRotation = transpose(w2oRotation);
    w2oRotation *= rcp(det);
    float3 w2oPosition = mul(w2oRotation, -objectToWorld._14_24_34);

    worldToObject._11_21_31_41 = float4(w2oRotation._11_21_31, 0.0f);
    worldToObject._12_22_32_42 = float4(w2oRotation._12_22_32, 0.0f);
    worldToObject._13_23_33_43 = float4(w2oRotation._13_23_33, 0.0f);
    worldToObject._14_24_34_44 = float4(w2oPosition, 1.0f);
    #endif
    }

    void passthroughVec3_float(in float3 In, out float3 Out)
    {
    Out = In;
    }

    void setupDummy() { }

    void setup()
    {
    #if UNITY_ANY_INSTANCING_ENABLED
  7. @Refsa Refsa revised this gist Oct 7, 2021. 3 changed files with 82 additions and 67 deletions.
    52 changes: 41 additions & 11 deletions Usage.cs
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,7 @@
    using System.Collections.Generic;
    using System.Runtime.InteropServices;
    using UnityEngine;

    class Render : MonoBehaviour
    {
    struct DrawData
    @@ -7,8 +11,8 @@ struct DrawData
    public Vector3 Scale;
    }

    Mesh mesh;
    Material material;
    public Mesh mesh;
    public Material material;

    List<DrawData> instances;

    @@ -20,28 +24,54 @@ struct DrawData
    void Awake()
    {
    instances = new List<DrawData>();

    argsBuffer = new ComputeBuffer(5, sizeof(uint), ComputeBufferType.IndirectArguments);
    // Meshes with sub-meshes needs more structure, this assumes a single sub-mesh
    args[0] = mesh.GetIndexCount(0);

    mpb = new MaterialPropertyBlock();

    SpawnExample();
    }

    void LateUpdate()
    {
    if (drawDataBuffer == null || drawDataBuffer.count < instances.Count)
    {
    drawDataBuffer?.Release();
    drawDataBuffer = new ComputeBuffer(instances.Count, Marshal.SizeOf<DrawData>();
    }
    drawDataBuffer.SetData(instances);
    materialPropertyBlock.SetBuffer("_DrawData", drawDataBuffer);
    // Only needs to be called if "instances" changed
    PushDrawData();
    mpb.SetBuffer("_DrawData", drawDataBuffer);

    args[1] = instances.Count;
    args[1] = (uint)instances.Count;
    argsBuffer.SetData(args);

    Graphics.DrawMeshInstancedIndirect(
    mesh, 0, material,
    new Bounds(Vector3.zero, Vector3.one * 1000f),
    argsBuffer, 0,
    materialPropertyBlock
    mpb
    );
    }

    void PushDrawData()
    {
    if (drawDataBuffer == null || drawDataBuffer.count < instances.Count)
    {
    drawDataBuffer?.Release();
    drawDataBuffer = new ComputeBuffer(instances.Count, Marshal.SizeOf<DrawData>());
    }
    drawDataBuffer.SetData(instances);
    }

    void SpawnExample()
    {
    instances.Clear();
    for (int i = 0; i < 4096; i++)
    {
    instances.Add(new DrawData()
    {
    Pos = Random.insideUnitSphere * 100f,
    Rot = Random.rotation,
    Scale = Vector3.one * Random.Range(1f, 10f)
    });
    }
    }
    }
    7 changes: 6 additions & 1 deletion readme.md
    Original file line number Diff line number Diff line change
    @@ -2,8 +2,13 @@ First is a passthrough custom function node that loads the hlsl code.
    ![image](https://user-images.githubusercontent.com/4514574/136408156-2a544e66-9a39-4d19-b009-9307f47018fe.png)

    Second custom function node contains the code to setup procedural instancing.
    It needs to be implmeneted in a custom function node or else it wont work.
    It needs to be implmeneted in a custom function node or else it wont work.
    Important bits is the `#pragma instancing_options procedural:setup` where "procedural:setup" calls a function in the included code in the previous node.
    ![image](https://user-images.githubusercontent.com/4514574/136408208-4417f688-6b12-4348-b02c-619c84f0d0c2.png)

    The output from this goes into position output of vertex stage. It needs to be connected for shader graph to compile it.
    ![image](https://user-images.githubusercontent.com/4514574/136408258-213deeb6-f537-41a9-b943-28de5d9963ca.png)

    Shader Graph should now work just as normal, just that it uses data passed from ComputeBuffers.

    Do note that the example code in Render.cs is sub-optimal and is mostly there as an example of how to use it from the C# side.
    90 changes: 35 additions & 55 deletions shaderGraphSupport.hlsl
    Original file line number Diff line number Diff line change
    @@ -1,78 +1,58 @@
    #ifndef SHADER_GRAPH_SUPPORT_H
    #define SHADER_GRAPH_SUPPORT_H

    // You could also upload the model matrix
    struct DrawData {
    float3 position;
    float4 rotation;
    float3 scale;
    // A custom instance id, useful for culling and other flags
    int id;
    };
    StructuredBuffer<DrawData> _DrawData;
    #include "./Common.hlsl"

    void setup()
    void calculatePos_float(in float4 vpos, out float4 worldPos)
    {
    #if UNITY_ANY_INSTANCING_ENABLED
    SetUnityMatrices(unity_InstanceID, unity_ObjectToWorld, unity_WorldToObject);
    DrawData drawData = _DrawData[unity_InstanceID];
    worldPos = TRS(drawData.position, drawData.rotation, drawData.scale, vpos);
    #else
    worldPos = vpos;
    #endif
    }

    inline float4x4 TRSMatrix(float3 position, float4 rotation, float3 scale)
    void getData_float(out float3 position, out float4 rotation, out float3 scale)
    {
    float4x4 m = 0.0;

    m[0][0] = (1.0 - 2.0 * (rotation.y * rotation.y + rotation.z * rotation.z)) * scale.x;
    m[1][0] = (rotation.x * rotation.y + rotation.z * rotation.w) * scale.x * 2.0;
    m[2][0] = (rotation.x * rotation.z - rotation.y * rotation.w) * scale.x * 2.0;
    m[3][0] = 0.0;

    m[0][1] = (rotation.x * rotation.y - rotation.z * rotation.w) * scale.y * 2.0;
    m[1][1] = (1.0 - 2.0 * (rotation.x * rotation.x + rotation.z * rotation.z)) * scale.y;
    m[2][1] = (rotation.y * rotation.z + rotation.x * rotation.w) * scale.y * 2.0;
    m[3][1] = 0.0;

    m[0][2] = (rotation.x * rotation.z + rotation.y * rotation.w) * scale.z * 2.0;
    m[1][2] = (rotation.y * rotation.z - rotation.x * rotation.w) * scale.z * 2.0;
    m[2][2] = (1.0 - 2.0 * (rotation.x * rotation.x + rotation.y * rotation.y)) * scale.z;
    m[3][2] = 0.0;

    m[0][3] = position.x;
    m[1][3] = position.y;
    m[2][3] = position.z;
    m[3][3] = 1.0;

    return m;
    #if UNITY_ANY_INSTANCING_ENABLED
    DrawData drawData = _DrawData[unity_InstanceID];
    position = drawData.position;
    rotation = drawData.rotation;
    scale = drawData.scale;
    #else
    position = 0;
    rotation = 0;
    scale = 1;
    #endif
    }

    inline void SetUnityMatrices(uint instanceID, inout float4x4 objectToWorld, inout float4x4 worldToObject)
    void getInstanceID_float(out float instanceID)
    {
    #if UNITY_ANY_INSTANCING_ENABLED
    DrawData drawData = _DrawData[instanceID];
    rex_id = drawData.id;

    objectToWorld = mul(objectToWorld, TRSMatrix(drawData.position, drawData.rotation, drawData.scale));

    float3x3 w2oRotation;
    w2oRotation[0] = objectToWorld[1].yzx * objectToWorld[2].zxy - objectToWorld[1].zxy * objectToWorld[2].yzx;
    w2oRotation[1] = objectToWorld[0].zxy * objectToWorld[2].yzx - objectToWorld[0].yzx * objectToWorld[2].zxy;
    w2oRotation[2] = objectToWorld[0].yzx * objectToWorld[1].zxy - objectToWorld[0].zxy * objectToWorld[1].yzx;

    float det = dot(objectToWorld[0].xyz, w2oRotation[0]);
    w2oRotation = transpose(w2oRotation);
    w2oRotation *= rcp(det);
    float3 w2oPosition = mul(w2oRotation, -objectToWorld._14_24_34);

    worldToObject._11_21_31_41 = float4(w2oRotation._11_21_31, 0.0f);
    worldToObject._12_22_32_42 = float4(w2oRotation._12_22_32, 0.0f);
    worldToObject._13_23_33_43 = float4(w2oRotation._13_23_33, 0.0f);
    worldToObject._14_24_34_44 = float4(w2oPosition, 1.0f);
    instanceID = rex_id;
    #else
    instanceID = 0;
    #endif
    }

    void passthroughVec4_float(in float4 In, out float4 Out)
    {
    Out = In;
    }

    void passthroughVec3_float(in float3 In, out float3 Out)
    {
    Out = In;
    }

    void setupDummy() { }

    void setup()
    {
    #if UNITY_ANY_INSTANCING_ENABLED
    SetUnityMatrices(unity_InstanceID, unity_ObjectToWorld, unity_WorldToObject);
    #endif
    }

    #endif
  8. @Refsa Refsa created this gist Oct 7, 2021.
    47 changes: 47 additions & 0 deletions Usage.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,47 @@
    class Render : MonoBehaviour
    {
    struct DrawData
    {
    public Vector3 Pos;
    public Quaternion Rot;
    public Vector3 Scale;
    }

    Mesh mesh;
    Material material;

    List<DrawData> instances;

    ComputeBuffer drawDataBuffer;
    ComputeBuffer argsBuffer;
    uint[] args = new uint[5];
    MaterialPropertyBlock mpb;

    void Awake()
    {
    instances = new List<DrawData>();
    argsBuffer = new ComputeBuffer(5, sizeof(uint), ComputeBufferType.IndirectArguments);
    // Meshes with sub-meshes needs more structure, this assumes a single sub-mesh
    args[0] = mesh.GetIndexCount(0);
    }

    void LateUpdate()
    {
    if (drawDataBuffer == null || drawDataBuffer.count < instances.Count)
    {
    drawDataBuffer?.Release();
    drawDataBuffer = new ComputeBuffer(instances.Count, Marshal.SizeOf<DrawData>();
    }
    drawDataBuffer.SetData(instances);
    materialPropertyBlock.SetBuffer("_DrawData", drawDataBuffer);

    args[1] = instances.Count;
    argsBuffer.SetData(args);

    Graphics.DrawMeshInstancedIndirect(
    mesh, 0, material,
    argsBuffer, 0,
    materialPropertyBlock
    );
    }
    }
    9 changes: 9 additions & 0 deletions readme.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,9 @@
    First is a passthrough custom function node that loads the hlsl code.
    ![image](https://user-images.githubusercontent.com/4514574/136408156-2a544e66-9a39-4d19-b009-9307f47018fe.png)

    Second custom function node contains the code to setup procedural instancing.
    It needs to be implmeneted in a custom function node or else it wont work.
    ![image](https://user-images.githubusercontent.com/4514574/136408208-4417f688-6b12-4348-b02c-619c84f0d0c2.png)

    The output from this goes into position output of vertex stage. It needs to be connected for shader graph to compile it.
    ![image](https://user-images.githubusercontent.com/4514574/136408258-213deeb6-f537-41a9-b943-28de5d9963ca.png)
    78 changes: 78 additions & 0 deletions shaderGraphSupport.hlsl
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,78 @@
    #ifndef SHADER_GRAPH_SUPPORT_H
    #define SHADER_GRAPH_SUPPORT_H

    // You could also upload the model matrix
    struct DrawData {
    float3 position;
    float4 rotation;
    float3 scale;
    // A custom instance id, useful for culling and other flags
    int id;
    };
    StructuredBuffer<DrawData> _DrawData;

    void setup()
    {
    #if UNITY_ANY_INSTANCING_ENABLED
    SetUnityMatrices(unity_InstanceID, unity_ObjectToWorld, unity_WorldToObject);
    #endif
    }

    inline float4x4 TRSMatrix(float3 position, float4 rotation, float3 scale)
    {
    float4x4 m = 0.0;

    m[0][0] = (1.0 - 2.0 * (rotation.y * rotation.y + rotation.z * rotation.z)) * scale.x;
    m[1][0] = (rotation.x * rotation.y + rotation.z * rotation.w) * scale.x * 2.0;
    m[2][0] = (rotation.x * rotation.z - rotation.y * rotation.w) * scale.x * 2.0;
    m[3][0] = 0.0;

    m[0][1] = (rotation.x * rotation.y - rotation.z * rotation.w) * scale.y * 2.0;
    m[1][1] = (1.0 - 2.0 * (rotation.x * rotation.x + rotation.z * rotation.z)) * scale.y;
    m[2][1] = (rotation.y * rotation.z + rotation.x * rotation.w) * scale.y * 2.0;
    m[3][1] = 0.0;

    m[0][2] = (rotation.x * rotation.z + rotation.y * rotation.w) * scale.z * 2.0;
    m[1][2] = (rotation.y * rotation.z - rotation.x * rotation.w) * scale.z * 2.0;
    m[2][2] = (1.0 - 2.0 * (rotation.x * rotation.x + rotation.y * rotation.y)) * scale.z;
    m[3][2] = 0.0;

    m[0][3] = position.x;
    m[1][3] = position.y;
    m[2][3] = position.z;
    m[3][3] = 1.0;

    return m;
    }

    inline void SetUnityMatrices(uint instanceID, inout float4x4 objectToWorld, inout float4x4 worldToObject)
    {
    #if UNITY_ANY_INSTANCING_ENABLED
    DrawData drawData = _DrawData[instanceID];
    rex_id = drawData.id;

    objectToWorld = mul(objectToWorld, TRSMatrix(drawData.position, drawData.rotation, drawData.scale));

    float3x3 w2oRotation;
    w2oRotation[0] = objectToWorld[1].yzx * objectToWorld[2].zxy - objectToWorld[1].zxy * objectToWorld[2].yzx;
    w2oRotation[1] = objectToWorld[0].zxy * objectToWorld[2].yzx - objectToWorld[0].yzx * objectToWorld[2].zxy;
    w2oRotation[2] = objectToWorld[0].yzx * objectToWorld[1].zxy - objectToWorld[0].zxy * objectToWorld[1].yzx;

    float det = dot(objectToWorld[0].xyz, w2oRotation[0]);
    w2oRotation = transpose(w2oRotation);
    w2oRotation *= rcp(det);
    float3 w2oPosition = mul(w2oRotation, -objectToWorld._14_24_34);

    worldToObject._11_21_31_41 = float4(w2oRotation._11_21_31, 0.0f);
    worldToObject._12_22_32_42 = float4(w2oRotation._12_22_32, 0.0f);
    worldToObject._13_23_33_43 = float4(w2oRotation._13_23_33, 0.0f);
    worldToObject._14_24_34_44 = float4(w2oPosition, 1.0f);
    #endif
    }

    void passthroughVec3_float(in float3 In, out float3 Out)
    {
    Out = In;
    }

    #endif