1. 일반
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
struct appdata
{
    float4 vertex : POSITION;
    float2 uv : TEXCOORD0;
};
struct v2f
{
    float4 vertex : SV_POSITION;
    float2 uv : TEXCOORD0;
};
float4 Billboard(float4 vertex)
{
    float3 camUpVec      =  normalize( UNITY_MATRIX_V._m10_m11_m12 );
    float3 camForwardVec = -normalize( UNITY_MATRIX_V._m20_m21_m22 );
    float3 camRightVec   =  normalize( UNITY_MATRIX_V._m00_m01_m02 );
    float4x4 camRotMat   = float4x4( camRightVec, 0, camUpVec, 0, camForwardVec, 0, 0, 0, 0, 1 );
                
    vertex = mul( vertex , unity_ObjectToWorld );
    vertex = mul( vertex , camRotMat );
    vertex = mul( vertex , unity_WorldToObject );
    return UnityObjectToClipPos(vertex);
}
v2f vert (appdata v)
{
    v2f o;
    o.vertex = Billboard(v.vertex);
    o.uv = v.uv;
    return o;
}
2. GPU 인스턴싱으로 그리는 경우
Graphics.DrawMeshInstancedIndirect()를 통해 그릴 때, 매개변수 마테리얼의 쉐이더- 
    
Quad 메시
 - 컴퓨트 버퍼(
_PositionBuffer)를 통해 각 인스턴스의 위치 지정 _Scale변수 또는 컴퓨트 버퍼를 통해 각 인스턴스의 크기 지정
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
StructuredBuffer<float3> _PositionBuffer;
float _Scale;
float4 CalculateVertex(float4 vertex, float3 worldPos)
{
    float3 camUpVec      =  normalize( UNITY_MATRIX_V._m10_m11_m12 );
    float3 camForwardVec = -normalize( UNITY_MATRIX_V._m20_m21_m22 );
    float3 camRightVec   =  normalize( UNITY_MATRIX_V._m00_m01_m02 );
    float4x4 camRotMat   = float4x4( camRightVec, 0, camUpVec, 0, camForwardVec, 0, 0, 0, 0, 1 );
    vertex = mul(vertex, camRotMat); // Billboard
    vertex.xyz *= _Scale;   // Scale
    vertex.xyz += worldPos; // Instance Position
    // World => VP => Clip
    return mul(UNITY_MATRIX_VP, vertex);
}
v2f vert (appdata_full v, uint instanceID : SV_InstanceID)
{
    v2f o;
    o.vertex = CalculateVertex(v.vertex, _PositionBuffer[instanceID]);
    o.uv = v.texcoord;
    return o;
}