TA/Unity2020. 7. 7. 11:35

GPU instancing

 

https://docs.unity3d.com/Manual/GPUInstancing.html

 

사내 프로젝트 테스트 결과 프레임이 소폭 상승하는것을확인해 프로젝트에 적용하기로 했음.

IOS 테스트도 문제 없었음.

 

 

 

 

본문 내용 정리(구글 번역)

 

 

GPU 인스턴스는 다음 플랫폼 및 API에서 사용할 수 있습니다.

DirectX 11 and DirectX 12 on Windows

OpenGL Core 4.1+/ES3.0+ on Windows, macOS, Linux, iOS and Android

Metal on macOS and iOS

Vulkan on Windows and Android

PlayStation 4 and Xbox One

WebGL (requires WebGL 2.0 API)

 

 

 

 

 

특징및 제한사항

다이나믹 배칭보다 우선 작동한다, 인스턴싱된 오브젝트는 다이나믹 배칭은 작동안함

여러개의 라이트를 받게되면 기본 패스만 인스턴싱 처리된다.

라이트맵이나 리플렉션 프로브가 적용되면 인스터싱 되지않는다.

쉐이더가 투 패스 이상일 경우 첫번째 패스만 인스턴싱됨

너무많은 인스턴싱은(D3D : 64KB, Opengl : 16KB) 쉐이더 컴파일 실패를 부를수 있다.

UNITY_MAX_INSTANCE_COUNT 로 숫자를 제한할수있다.

최대갯수는 500개, 오픈지엘은125개가 기본

오픈지엘 3.0이상 작동

SkinnedMeshRenderer는 지원되지 않음

 

 

 

인스턴스 별 데이터 추가

 

기본적으로 Unity는 인스턴스화 된 각각의 드로 콜에서 서로 다른 Transform을 가진 GameObject 인스턴스를 일괄 처리합니다. 인스턴스화 된 GameObjects에 더 많은 분산을 추가하려면 Shader를 수정하여 Material 색상과 같은 인스턴스 별 속성을 추가하십시오.

 

 

아래 예제는 각 인스턴스에 대해 서로 다른 색상 값을 가진 인스턴스화 된 셰이더를 만드는 방법을 보여줍니다.

 

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 // Physically based Standard lighting model, and enable shadows on all light types #pragma surface surf Standard fullforwardshadows // Use Shader model 3.0 target #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" }

 

 

 

 

_Color를 인스턴스 속성으로 선언하면 Unity는 GameObject에 설정된 MaterialPropertyBlock 객체에서

_Color 값을 수집하여 단일 그리기 호출에 넣습니다.

 

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); }

 

 

 

 

인스턴스화 셰이더가 사용되지 않거나 _Color가 인스턴스 별 속성이 아닌 일반적인 경우에는 MaterialPropertyBlock의

다른 값으로 인해 드로잉 호출 배치가 중단됩니다. 이러한 변경 사항을 적용하려면 GPU 인스턴스를 활성화해야합니다. 이렇게하려면 Project 창에서 Shader를 선택하고

Inspector에서 Instance Enable 확인란을 선택합니다.

 

 

 

 

 

 

 

 

버텍스 및 프래그먼트 셰이더에 인스턴스 추가

다음 예제는 단순한 비 조명 셰이더를 사용하고 다른 색상으로 인스 턴싱 할 수있게합니다.

 

 

Shader "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 // necessary only if you want to access instanced properties in fragment Shader. }; 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); // necessary only if you want to access instanced properties in the fragment Shader. o.vertex = UnityObjectToClipPos(v.vertex); return o; } fixed4 frag(v2f i) : SV_Target { UNITY_SETUP_INSTANCE_ID(i); // necessary only if any instanced properties are going to be accessed in the fragment Shader. return UNITY_ACCESS_INSTANCED_PROP(Props, _Color); } ENDCG } } }

 

 

 

 

Shader modifications

AdditionFunction

#pragma multi_compile_instancing Unity가 인스턴스 변형을 생성하도록 지시하려면이 옵션을 사용하십시오. 표면 쉐이더에는 필요하지 않습니다.
UNITY_VERTEX_INPUT_INSTANCE_ID 버텍스 쉐이더 입력 / 출력 구조에서 이것을 사용하여 인스턴스 ID를 정의하십시오. 자세한 내용은 SV_InstanceID를 참조하십시오.
UNITY_INSTANCING_BUFFER_START(name) / 
UNITY_INSTANCING_BUFFER_END(name)
모든 인스턴스 별 등록 정보는 특별히 명명 된 상수 버퍼에 정의되어야합니다. 이 매크로 쌍을 사용하여 각 인스턴스에 고유하게 만들 속성을 래핑합니다.
UNITY_DEFINE_INSTANCED_PROP(float4, _Color) 이 메서드를 사용하여 유형별 및 이름 별 인스턴스 별 Shader 속성을 정의합니다. 이 예제에서 _Color 속성은 고유합니다.
UNITY_SETUP_INSTANCE_ID(v); 이것을 사용하여 셰이더 기능에서 인스턴스 ID에 액세스 할 수있게 만듭니다. 버텍스 쉐이더의 맨 처음에 사용해야하며 프래그먼트 쉐이더에서는 옵션입니다.
UNITY_TRANSFER_INSTANCE_ID(v, o); 이것을 사용하여 입력 구조의 인스턴스 ID를 버텍스 쉐이더의 출력 구조로 복사하십시오. 프래그먼트 셰이더에서 인스턴스 별 데이터에 액세스해야하는 경우에만 필요합니다.
UNITY_ACCESS_INSTANCED_PROP(arrayName, color) 인스턴스화 상수 버퍼에 선언 된 인스턴스 별 Shader 속성에 액세스하려면이 옵션을 사용합니다. 인스턴스 ID를 사용하여 인스턴스 데이터 배열을 색인화합니다. 매크로의 arrayName은 UNITY_INSTANCING_BUFFER_END (이름) 매크로의 arrayName과 일치해야합니다.



 

 

#pragma instancing_options #pragma instancing_options 지시어는 다음 스위치를 사용할 수 있습니다.

 

SwitchFunction

forcemaxcount:batchSizeand maxcount:batchSize 대부분의 플랫폼에서 Unity는 대상 장치의 최대
상수 버퍼 크기를 모든 인스턴스 별 속성을 포함
하는 구조체의 크기로 나누어 인스턴스화 데이터
 배열 크기를 자동으로 계산합니다. 일반적으로
배치 크기에 대해 걱정할 필요가 없습니다.
그러나 일부 플랫폼 (Vulkan, Xbox One 및 Switch)
에서는 여전히 고정 배열 크기가 필요합니다.
 maxcount 옵션을 사용하여 해당 플 '폼에 대한 일}
 처리 크기를 지정할 수 있습니다.
이 옵션은 다른 플랫폼에서 완전히 무시됩니다.
모든 플랫폼에서 배치 크기를 강제로 설정하려면
 forcemaxcount를 사용하십시오
(예를 들어, DrawMeshInstanced를 통해 256 개의
 인스턴스 스프라이트가있는 드로잉 만 발행하는
 경우). 두 옵션의 기본값은 500입니다.
assumeuniformscaling 유니티에 모든 인스턴스가 균일 한 스케일링
(모든 X, Y, Z 축에 대해 동일한 스케일)을 가지고
있다고 가정하도록 지시하려면이 옵션을
사용하십시오.
lodfade 이것을 사용하여 LOD 페이드 값을 인스턴스화
할 수 있습니다. 이것은 SpeedTree 및 LOD
페이드 기능을 사용하는 다른 LOD 기술에
유용합니다.
procedural:FunctionName

Unity가 Graphics.DrawMeshInstancedIndirect와 

함께 사용할 추가 변형을 생성하도록 지시하려면이

 옵션을 사용하십시오.

버텍스 쉐이더 단계의 시작 부분에서 Unity는 

콜론 다음에 지정된 함수를 호출합니다. 

인스턴스 데이터를 수동으로 설정하려면 

일반적으로 인스턴스 당 데이터를 셰이더에 

추가하는 것과 같은 방법으로이 함수에 인스턴스 

별 데이터를 추가하십시오. Unity는 가져온 

인스턴스 속성 중 하나가 조각 Shader에 포함되어

 있으면 조각 Shader의 시작 부분에서이 함수를 

호출합니다.

 

 

 

UnityObjectToClipPos 셰이더 스크립트를 작성할 때는 mul (UNITY_MATRIX_MVP, v.vertex) 대신 항상

UnityObjectToClipPos (v.vertex)를 사용하십시오. 인스턴스화 된 쉐이더에서 UNITY_MATRIX_MVP를 정상적으로 계속 사용할 수 있지만

UnityObjectToClipPos는 오브젝트 공간에서 클립 공간으로 정점 위치를 변환하는

가장 효율적인 방법입니다. Unity는 또한 프로젝트의 모든 셰이더를 스캔하고,

mul (UNITY_MATRIX_MVP, v)의 모든 항목을 UnityObjectToClipPos (v)로 자동으로

대체하는 셰이더 업그레이드 프로그램을 구현합니다. UNITY_MATRIX_MVP (UNITY_MATRIX_MV와 함께)가 사용되는 장소가 여전히있는 경우

콘솔 창 (메뉴 : 창> 콘솔)은 성능 경고를 표시합니다.

'TA > Unity' 카테고리의 다른 글

Editor - Color UI (후처리 스크립트)  (0) 2020.07.07
Shader - tex2Dlod  (0) 2020.07.07
모바일 Time scroll 오류 해결방법  (0) 2020.07.07
texcoord를 늘려 사용하는 방법  (0) 2020.07.07
unity shdaer AplhaTest Shadow pass  (0) 2020.07.07
Posted by 프리랜서 디자이너