Unity GPU Instancing 自己写个简单的测试用例1

141 篇文章 31 订阅

由于工作原因,好久没写博客了,后续慢慢补上这段时间的打杂学习到的内容

之前在 OpenGL 上实现了 GPU Instancing

在 Unity 也是差不多的,只不过 Unity 对 ShaderLab 和 应用层 C++ 封装了黑箱处理

但是原理是差不多的:在 GPU 建立一块缓存,用于存放不同实例的不同属性,便于绘制时的差异效果

那么今天就搬一下砖


Shader

// author : jave.lin
// Unity 中 实现 Instancing 的 Shader
Shader "Game/CoinInstancingShader"
{
    Properties
    {
        [NoScaleOffset] _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #define SELF_ROT     // 测试自转
            #define TINT_COLOR   // 测试着色
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_instancing
            #include "UnityCG.cginc"
            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };
            struct v2f
            {
                float4 vertex : SV_POSITION;
                float2 uv : TEXCOORD0;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            sampler2D _MainTex;

            // SRP 中,可以使用一个 UnityPerMaterial 再裹一层
            // 总之这些潜规则要熟悉 Unity 才能知道
            //  - https://forum.unity.com/threads/materialpropertyblock-with-shader-graph.697868/
            // CBUFFER_START(UnityPerMaterial)
                UNITY_INSTANCING_BUFFER_START(MyInstancing)
                    UNITY_DEFINE_INSTANCED_PROP(float4x4, _MMat)
                #ifdef TINT_COLOR
                    UNITY_DEFINE_INSTANCED_PROP(fixed4, _Color)
                #endif
                #ifdef SELF_ROT
                    UNITY_DEFINE_INSTANCED_PROP(float, _AngleOffset)
                #endif
                UNITY_INSTANCING_BUFFER_END(MyInstancing)
            // CBUFFER_END

            // unity 的 instancing 参考下面的连接内容
            // jave.lin : refer to : 
            //  - https://docs.unity3d.com/Manual/GPUInstancing.html
            // UNITY_INSTANCING_BUFFER_START(MyInstancing)
            //     UNITY_DEFINE_INSTANCED_PROP(float4x4, _MMat)
            //     UNITY_DEFINE_INSTANCED_PROP(half4, _Color)
            // UNITY_INSTANCING_BUFFER_END(MyInstancing)

            // 这里只是功能演示,一般尽量不在 VS, FS 中构建矩阵
            // 想这个自旋转的矩阵,完全可以合并在 Model Matrix 中来处理
            // 下面只是做测试
            // 可参考我之前写的软渲染器中的:GenYRotateMat 函数
            // https://github.com/javelinlin/3DSoftRenderer/blob/master/SoftRenderer/RendererCoreCommon/Renderer/Common/Mathes/Mathes.cs
            #ifdef SELF_ROT
            float4x4 GetYRotMat(float y, float offset)
            {
                float angle = y + offset;
                float c = cos(angle);
                float s = sin(angle);
                return float4x4(
                    float4( c, 0,  s, 0),
                    float4( 0, 1,  0, 0),
                    float4(-s, 0,  c, 0),
                    float4( 0, 0,  0, 1)
                );
            }
            #endif

            v2f vert (appdata v)
            {
                v2f o;
                UNITY_SETUP_INSTANCE_ID(v)
                UNITY_TRANSFER_INSTANCE_ID(v, o);

                float4x4 mMat = UNITY_ACCESS_INSTANCED_PROP(MyInstancing, _MMat);
                #ifdef SELF_ROT
                float angle = UNITY_ACCESS_INSTANCED_PROP(MyInstancing, _AngleOffset);
                mMat = mul(mMat, GetYRotMat(_Time.w, angle));
                #endif

                float4 vertex = mul(mMat, v.vertex);
                o.vertex = mul(UNITY_MATRIX_VP, vertex);
                o.uv = v.uv;
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                UNITY_SETUP_INSTANCE_ID(i);

            #ifdef TINT_COLOR
                fixed4 col = tex2D(_MainTex, i.uv);
                col.rgb = UNITY_ACCESS_INSTANCED_PROP(MyInstancing, _Color).rgb * col;
                return col;
            #else
                return tex2D(_MainTex, i.uv);
            #endif
            }
            ENDCG
        }
    }
}


CSharp 脚本

using UnityEngine;

[ExecuteInEditMode]
public class InstancedScript : MonoBehaviour
{
    private static int _MMat = Shader.PropertyToID("_MMat");
    private static int _Color = Shader.PropertyToID("_Color");
    private static int _AngleOffset = Shader.PropertyToID("_AngleOffset");
    private static MaterialPropertyBlock mpb;

    public Color col;
    public float angle_offset;

    private MeshRenderer mesh_renderer;

    private void Start()
    {
        mesh_renderer = GetComponent<MeshRenderer>();
        if (mpb == null) mpb = new MaterialPropertyBlock();
    }

    private void Update()
    {
        mpb.SetMatrix(_MMat, transform.localToWorldMatrix);
        mpb.SetColor(_Color, col);
        mpb.SetFloat(_AngleOffset, angle_offset);
        mesh_renderer.SetPropertyBlock(mpb);
    }
}


材质上勾上:Enable GPU Instanced


运行效果

在这里插入图片描述


Project

backup : GPU_Instancing_DEMO


目前上面的方式不是unity比较好的方式,后续有空再搬一砖:在CSharp调用API绘制

加班太狠,生活琐事多,学习计划都打乱了


References

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值