Unity GPU 인스턴싱 가이드
이 문서는 Unity에서 GPU 인스턴싱을 지원하는 커스텀 셰이더를 만드는 방법에 대한 것입니다. GPU 인스턴싱을 활용하여 성능 최적화를 이루고 다수의 객체를 효율적으로 렌더링할 수 있습니다.
GPU 인스턴싱을 지원하는 셰이더 생성
셰이더 생성 시 다음과 같은 키워드와 매크로를 사용해야 합니다:
#pragma multi_compile_instancing
- 인스턴싱 변형을 생성합니다.
#pragma instancing_options
- 인스턴스에 대한 옵션을 정의합니다.
- 인스턴스 ID
UNITY_VERTEX_INPUT_INSTANCE_ID
: 버텍스 셰이더 입출력 구조에서 인스턴스 ID를 정의합니다.- 인스턴스당 상수 버퍼
UNITY_INSTANCING_BUFFER_START(bufferName)
/UNITY_INSTANCING_BUFFER_END(bufferName)
- 인스턴스당 프로퍼티를 래핑합니다.
- 인스턴스 프로퍼티 정의
UNITY_DEFINE_INSTANCED_PROP
- 인스턴스당 셰이더 프로퍼티를 정의합니다.
인스턴싱 옵션 스위치
instancing_options
지시문에서는 다음과 같은 스위치를 사용할 수 있습니다:
스위치 | 설명 |
---|---|
forcemaxcount | 모든 플랫폼에 배치 크기를 강제로 적용합니다. |
assumeuniformscaling | 모든 인스턴스의 스케일링이 동일하다고 가정합니다. |
nolodfade | LOD 페이드 값에 GPU 인스턴싱을 적용하지 않도록 합니다. |
nolightprobe | 라이트 프로브와의 호환성을 방지합니다. |
procedural | 인스턴스 데이터를 수동으로 설정할 때 사용합니다. |
셰이더 예제
표면 셰이더 예제
각 인스턴스에 다르게 설정된 색상을 갖는 표면 셰이더 생성 예제입니다.
Shader "Custom/InstancedColorSurfaceShader" { Properties { _Color ("Color", Color) = (1,1,1,1) _MainTex ("Albedo (RGB)", 2D) = "white" {} _Glossiness ("Smoothness", Range(0,1)) = 0.5 _Metallic ("Metallic", Range(0,1)) = 0.0 }
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
#pragma surface surf Standard fullforwardshadows
#pragma target 3.0
sampler2D _MainTex;
struct Input
{
float2 uv_MainTex;
};
half _Glossiness;
half _Metallic;
UNITY_INSTANCING_BUFFER_START(Props)
UNITY_DEFINE_INSTANCED_PROP(fixed4, _Color)
UNITY_INSTANCING_BUFFER_END(Props)
void surf (Input IN, inout SurfaceOutputStandard o) {
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * UNITY_ACCESS_INSTANCED_PROP(Props, _Color);
o.Albedo = c.rgb;
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
버텍스 및 프래그먼트 셰이더 예제
각 인스턴스에 다른 색상을 부여하는 버텍스 및 프래그먼트 셰이더 예제입니다.
Shader "Custom/SimplestInstancedShader" { Properties { _Color ("Color", Color) = (1, 1, 1, 1) }
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_instancing
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2f
{
float4 vertex : SV_POSITION;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
UNITY_INSTANCING_BUFFER_START(Props)
UNITY_DEFINE_INSTANCED_PROP(float4, _Color)
UNITY_INSTANCING_BUFFER_END(Props)
v2f vert(appdata v)
{
v2f o;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_TRANSFER_INSTANCE_ID(v, o);
o.vertex = UnityObjectToClipPos(v.vertex);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
UNITY_SETUP_INSTANCE_ID(i);
return UNITY_ACCESS_INSTANCED_PROP(Props, _Color);
}
ENDCG
}
}
}
런타임 시 인스턴스당 데이터 변경 예제
MaterialPropertyBlock을 사용하여 런타임 시 객체의 인스턴스별 색상을 랜덤하게 설정하는 예제입니다.
using UnityEngine;
public class MaterialPropertyBlockExample : MonoBehaviour { public GameObject[] objects;
void Start()
{
MaterialPropertyBlock props = new MaterialPropertyBlock();
MeshRenderer renderer;
foreach (GameObject obj in objects)
{
float r = Random.Range(0.0f, 1.0f);
float g = Random.Range(0.0f, 1.0f);
float b = Random.Range(0.0f, 1.0f);
props.SetColor("_Color", new Color(r, g, b));
renderer = obj.GetComponent<MeshRenderer>();
renderer.SetPropertyBlock(props);
}
}
}
결론
GPU 인스턴싱은 Unity에서 성능을 향상시키는 강력한 도구입니다. 이 가이드를 참고하여 GPU 인스턴싱을 지원하는 셰이더를 생성하고 최적화된 렌더링을 구현해 보시기 바랍니다.