Fill-rate, Canvases and input – 번역

Fill-rate, Canvases and input

원문 링크

이전글 – Unity UI Profiling Tools 

 

Fill-rate, Canvases and input

확인 완료한 버전: 5.3 – 난이도: 고급

이번 챕터는 유니티 UI를 구성하는 방법에 대한 다양한 주제를 살펴봅니다.

 

Fill-rate 문제 해결하기 (Remediating fill-rate issues)

GPU의 프래그먼트 파이프라인(Fragment Pipeline)에 가해지는 부하를 줄이기 위한 방법에는 크게 2가지 방법이 있습니다.

  • 프래그먼트 쉐이더(Fragment shader)의 복잡도 줄이기
    • 이에 대한 자세한 내용은 “UI 쉐이더 및 로우-스펙 장치들” 섹션을 참고하시기 바랍니다.
  • 샘플링해야하는 픽셀의 수 줄이기

UI 쉐이더가 표준화되면서, 일반적으로 가장 많이 발생하는 문제는 과도한 fill-rate의 사용으로 인한 문제입니다. 이 문제는 다수의 UI 요소들이 겹치거나 여러 UI 요소들이 화면의 상당 부분을 차지하는 경우에 주로 발생합니다. 두가지 경우 모두 매우 높은 수준의 오버드로우(Overdraw)로 이어질 수 있습니다.

Fill-rate의 과도한 사용을 덜어내고 오버드로우를 줄이기 위해서 다음과 같은 개선방법을 고려해보는 것이 좋습니다.

 

보이지 않는 UI 제거 (Eliminating invisible UI)

기존 UI의 재설계를 최소한으로 줄이는 방법은 플레이어가 보지 못하는 UI 요소를 비활성화하는 것입니다. 이 방법을 적용할 수 있는 가장 일반적인 상황은, 화면 전체를 불투명한 UI로 덮는 경우입니다. 이 경우, 전체 화면 크기의 UI 아래에 배치된 UI 요소들은 모두 비활성화시킬 수 있습니다.

이를 구현하는 가장 간단한 방법은 화면에 보이지 않는 UI 요소들을 모두 포함하고 있는 루트 게임오브젝트를 비활성화시키는 것입니다. 이에 대한 다른 해결책에 대한 내용은, 캔버스 렌더러 비활성화하기(Disabling Canvas Renderers) 섹션을 참고하시기 바랍니다.

 

보이지 않는 카메라 출력 비활성화하기 (Disabling invisible camera output)

유니티 UI에서 “불투명한” 배경으로 전체 화면 UI가 열리더라도, 월드 공간의 카메라는 여전히 이 UI 뒤에 그려지는 표준 3D 씬을 렌더링합니다. 3D 씬을 그리는 렌더러는 전체 화면을 덮는 유니티 UI가 전체 3D 씬을 가린다는 것을 인식하지 못하기 떄문입니다.

따라서, 화면 전체를 완전히 덮는 UI가 열리는 경우, 이 UI에 의해서 가려지는 월드 공간의 카메라를 모두 비활성시키는 것이 좋습니다. 이렇게 하면, 불필요한 3D 월드에 대한 렌더링 작업을 제거하기 때문에 GPU의 부하를 줄이는데 도움이 됩니다.

참고: 캔버스가 “Screen Space – Overlay”로 설정된 경우에는 활성화된 카메라의 수에 관계없이, 캔버스가 그려집니다.

 

대부분의 카메라가 가려지는 경우 (Majority-obscured cameras)

“전체 화면을 덮는” UI 중에 다수가 3D 월드 전체를 실제로 가리는 것은 아니지만, 월드 공간의 일부만 화면에서 보이는 경우가 많습니다. 이런 경우, 월드 공간에서 렌더 텍스쳐(Render Texture)에 실제로 보이는 부분만 캡쳐하는 것이 훨씬 더 효율적인 방법이 될 수 있습니다. 월드 공간에서 화면에 보이는 부분이 렌더 텍스쳐에 “캐싱(cached)”되면, 실제 월드-공간 카메라를 비활성화시킨다음, 렌더 텍스쳐에 저장된 내용을 해당 UI 스크린 뒤에 그려서 좀 더 최적화된 3D 월드 화면을 제공할 수 있습니다.

 

컴포지션 기반 UI (Composition-based UIs)

디자이너는 일반적으로 배경 및 UI 요소를 겹쳐서 배치하고 결합하는, 컴포지션(Composition)을 통해서 최종 UI를 제작합니다. 이런 방법은 상대적으로 간단하고 반복 작업을 하기에 매우 편리하지만, 유니티 UI가 Transparent 렌더링 큐를 사용하기 때문에 성능면에서 부적합합니다.

배경 및 텍스트를 가진 버튼이 있는 단순한 UI를 생각해보겠습니다. 특정 픽셀이 텍스트 메쉬에 위치해있는 경우에 GPU는 배경의 텍스쳐, 그 다음 버튼의 텍스쳐, 마지막으로 텍스트 아틀라스의 텍스쳐를 샘플링해야하기 때문에, 최종적으로 3가지 항목을 샘플링해야 합니다. UI의 복잡도가 증가하고, 배경에 겹쳐서 배치되는 UI 요소들이 증가하게되면 샘플링해야하는 개체의 수가 급격하게 늘어날 수 있습니다.

크기가 큰 특정 UI가 fill-rate 문제를 발생시키는 원인으로 확인되면, 배경을 장식하는데 사용되는 UI 요소 및 변하지 않는 UI 요소들을 배경 텍스쳐에 최대한 병합해서 특수한 UI 스프라이트를 제작하는 것이 가장 좋은 방법입니다. 이를 적용하면, 원하는 다지안을 얻기 위해서 다른 UI 요소 위에 겹쳐서 배치해야하는 UI 요소의 수를 줄일 수 있습니다. 하지만, 이 방법은 많은 노동을 필요로하고 프로젝트에서 사용하는 텍스쳐 아틀라스의 크기가 증가하게 됩니다.

특수한 UI 스프라이트를 통해서, 겹쳐서 배치되는 UI 요소의 수를 줄이는 이런 원리는 하위-UI 요소에도 적용할 수 있습니다. 아이템을 스크롤할 수 있도록 구성된 창을 가진 상점 UI를 생각해보겠습니다. 아이템을 나타내는 각 UI 요소에는 테두리, 배경 그리고 가격, 이름 및 기타 정보를 나타내는 아이콘들이 있다고 가정해 보겠습니다.

상점 UI에는 배경이 필요하지만, 상점의 아이템 UI요소들이 배경을 스크롤하기 때문에 아이템 UI 요소는 배경 스프라이트에 병합될 수 없습니다. 하지만, 아이템의 테두리, 가격, 이름, 그 외의 UI 요소들은 아이템의 배경 스프라이트에 병합될 수 있습니다. 이를 적용하면, 아이콘의 크기 및 수에 따라서 상당한 양의 fill-rate를 절감하는 효과를 볼 수 있습니다.

하지만 이 방법은 여러 UI 요소를 겹쳐서 배치하는 방법과 비교했을때 몇 가지 단점이 있습니다. 특수하게 제작된 UI요소는 재사용이 불가능하며, 아티스트의 리소스가 추가적으로 필요합니다. 또한, 크기가 큰 텍스쳐를 새로 추가하면 해당 UI 텍스쳐를 유지하는데 필요한 메모리의 양이 크게 증가할 수 있습니다. 특히, 해당 UI 텍스쳐가 필요에 따라서 적절하게 로드 및 해제되지 않는 경우에 그렇습니다.

 

UI 쉐이더와 저-사양 장치 (UI shaders and low-spec devices)

유니티 UI에서 사용하는 내장 쉐이더는 마스킹, 클리핑(Clipping) 외의 기타 수많은 복잡한 작업을 지원합니다. 이렇게 추가된 복잡성으로 인해서, 이 UI 쉐이더는 단순한 유니티 2D 쉐이더에 비해서 아이폰 4와 같은 저-사양 장치에서 성능이 떨어집니다.

저사양 장치를 대상으로하는 프로그램에서 마스킹, 클리핑, 그 외의 “화려한” 기능들이 필요하지 않은 경우에, 아래의 쉐이더와 같이, 커스텀 쉐이더를 제작해서 불필요한 작업들을 생략시킬 수 있습니다:

Shader "UI/Fast-Default"
{
    Properties
    {
        [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
        _Color ("Tint", Color) = (1,1,1,1)
    }

    SubShader
    {
        Tags
        { 
            "Queue"="Transparent" 
            "IgnoreProjector"="True" 
            "RenderType"="Transparent" 
            "PreviewType"="Plane"
            "CanUseSpriteAtlas"="True"
        }

        Cull Off
        Lighting Off
        ZWrite Off
        ZTest [unity_GUIZTestMode]
        Blend SrcAlpha OneMinusSrcAlpha

        Pass
        {
        CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
            #include "UnityUI.cginc"
            
            struct appdata_t
            {
                float4 vertex   : POSITION;
                float4 color    : COLOR;
                float2 texcoord : TEXCOORD0;
            };

            struct v2f
            {
                float4 vertex   : SV_POSITION;
                fixed4 color    : COLOR;
                half2 texcoord  : TEXCOORD0;
                float4 worldPosition : TEXCOORD1;
            };
            
            fixed4 _Color;
            fixed4 _TextureSampleAdd;
            v2f vert(appdata_t IN)
            {
                v2f OUT;
                OUT.worldPosition = IN.vertex;
                OUT.vertex = mul(UNITY_MATRIX_MVP, OUT.worldPosition);

                OUT.texcoord = IN.texcoord;
                
                #ifdef UNITY_HALF_TEXEL_OFFSET
                OUT.vertex.xy += (_ScreenParams.zw-1.0)*float2(-1,1);
                #endif
                
                OUT.color = IN.color * _Color;
                return OUT;
            }

            sampler2D _MainTex;
            fixed4 frag(v2f IN) : SV_Target
            {
                return (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color;
            }
        ENDCG
        }
    }
}

 

UI 캔버스 리빌드 (UI Canvas rebuilds)

UI를 화면에 나타내기 위해서는, UI 시스템에서 화면에 표시되는 각 UI 컴포넌트에 해당하는 지오메트리(UI 메쉬)를 제작해야합니다. 이 과정에는 동적 레이아웃 코드 실행, UI 텍스트 문자열의 문자를 표현하기 위한 폴리곤 생성, 드로우 콜(Draw call)을 줄이기 위해서 단일 메쉬에 지오메트리를 최대한 병합하는 작업이 포함됩니다. 이 과정은 여러-단계로 처리되며 이 글의 처음 부분인 기초(Fundamentals) 섹션에 자세하게 설명되어 있습니다.

캔버스 리빌드(Canvas Rebuild)는 다음의 두가지 이유로 인해서 성능에 문제가 될 수 있습니다:

– 캔버스에 화면에 그려야하는 UI 요소들이 많은 경우, 배치(batch)처리 자체를 계산하는 과정의 부하가 매우 커집니다. 이는 캔버스에 배치된 화면에 그려져야하는 UI 요소의 수가 증가함에 따라서, 해당 UI 요소들을 정렬하고 분석하는 비용이 크게 증가하기 때문입니다.
– 만약 해당 캔버스가 자주 dirty 상태가 되는 경우, 변경하는 부분이 상대적으로 작더라도, 해당 캔버스를 새로 갱신하는데 너무 오랜 시간이 걸릴 수 있습니다.

이 문제들은 모두 캔버스에 배치된 UI 요소의 수가 증가함에 따라서 심각한 문제가될 수 있습니다.

알림(중요): 특정 캔버스에 배치된 화면에 그려야하는 UI 요소가 변경된 경우, 해당 캔버스는 배치(batch) 처리 프로세스를 다시 실행해야합니다. 이 프로세스는 UI 요소의 변경 여부에 관계없이, 캔버스에 배치된 UI 요소를 모두 다시 분석합니다. 여기서 “변경”이란 UI 오브젝트의 모양에 영향을 주는 사항을 모두 지칭합니다. 여기에는 스프라이트 렌더러에 할당된 스프라이트, 트랜스폼 위치 및 스케일, 텍스트 메쉬에 포함된 텍스트 등이 포함됩니다.

 

하위 계층의 순서 (Child order)

유니티 UI는 계층 뷰의 정렬 순서에 따라서 해당 오브젝트의 순서가 결정되어, 뒤에서 앞의 순서로 생성됩니다. 계층뷰에서 위에 위치한 오브젝트는 계층뷰 아래에 위치한 오브젝트보다 뒤에 있는 것으로 간주됩니다. 계층 뷰를 위에서 아래의 순서로 계층 구조를 따라서 순회하면서 동일한 재질(material), 동일한 텍스쳐를 사용하고 중간 계층(1)(intermediate layers)을 사용하지않는 모든 오브젝트에 대한 정보를 수집하여 배치(Batch)가 처리됩니다. 중간 계층은 배치 처리를 강제로 중단시킵니다.

유니티 프레임 디버거(Unity Frame Debugger) 섹션에서 설명했듯이, 프레임 디버거를 사용해서 특정 UI가 중간 계층에 있는지 여부를 검사할 수 있습니다. 중간 계층(intermediate layers)은 특정 UI 오브젝트가 다른 두 개의 오브젝트 사이에 끼어있는 상황을 나타냅니다.

이 문제는 텍스트와 스프라이트가 서로 가까이 있을때 주로 발생합니다: 텍스트 메쉬의 폴리곤의 대부분이 투명하기 때문에, 눈에 띄지는 않지만 텍스트의 바운딩 박스(bounding box)가 근처의 스프라이트와 겹칠 수 있습니다. 이 문제는 다음의 두 가지 방법으로 해결할 수 있습니다:

  • 배치(batch)처리 가능한 오브젝트가 배치처리가 불가능한 오브젝트 사이에 위치하지 않도록 UI 요소의 순서를 재정렬합니다; 즉, 배치처리가 불가능한 오브젝트를 배치처리 가능한 오브젝트의 위 또는 아래로 위치를 이동시킵니다.
  • 보이지 않는데 겹치는 공간을 제거하기 위해서 오브젝트의 위치를 조정합니다.

이 두가지 방법 모두 유니티 프레임 디버거(Unity Frame Debugger)를 열고 활성화한 상태에서 유니티 에디터에서 작업할 수 있습니다. 유니티 프레임 디버거에서 드로우 콜의 수를 관찰하면서, UI 요소가 겹치는 것으로 인해 낭비되는 드로우 콜의 수를 최소화시키기 위한 UI의 순서 및 위치를 찾을 수 있습니다.

 

캔버스 분할하기 (Splitting Canvases)

몇가지 경우를 제외하고는, 일반적으로 캔버스를 하위 캔버스 또는 동등한 위치의 다른 캔버스로 분할하는 것이 좋습니다.

동등한 위치의 다른 캔버스로 분할하는 방법은, UI의 특정 부분이 나머지 UI 요소들과는 별도의 드로우 깊이(Draw depth)로 제어되는 경우에 가장 적합합니다. 즉, 해당 UI가 나머지 UI 요소들 보다 가장 위에 위치하거나 가장 아래에 위치해야 하는 경우에 적합합니다 (예: 튜토리얼의 화살표).

다른 경우에는 대부분, 하위 캔버스가 상위 캔버스의 디스플레이 설정을 상속하기 때문에 하위 캔버스로 분할하는 것이 편리한 경우가 많습니다.

언뜻보기에 UI를 여러 개의 하위 캔버스로 나누는 것이 좋아보일 수 있지만, 캔버스 시스템은 서로 분리되어 있는 다른 캔버스와들을 배치(batch)처리하지 않는다는 점에 주의해야 합니다. 성능면에서 좋은 UI 디자인을 위해서, 리빌드(rebuild)의 비용을 최소화하는 것과 낭비되는 드로우 콜을 최소화하는 것 사이에서 적절하게 균형을 잡아야 합니다.

 

일반적인 가이드라인 (General guidelines)

캔버스는 캔버스를 구성하는 UI 요소가 변경될 때마다 다시 배치(rewatch)처리되기 때문에, UI 요소를 많이 포함하고 있는 캔버스를 최소 두개 이상으로 분할하는 것이 좋습니다. 또한, 변경되는 시점이 동일한 UI 요소들은 같은 캔버스에 위치시키는 것이 좋습니다. 프로레스바(Progressbar)와 카운트다운 타이머가 그 예가 될 수 있습니다. 이 둘은 모두 동일한 데이터를 기반으로 동작하기 때문에 같은 시점에 갱신됩니다. 따라서 동일한 캔버스에 위치시키는 것이 좋습니다.

배경 및 레이블과 같은, 고정적이고 변경되지 않는 UI 요소를 첫번째 캔버스에 위치시키는 것이 좋습니다. 이를 통해서, 캔버스가 처음 표시될 때 한번만 배치(batch)처리되고나면, 더이상 배치(batch)처리할 필요가 없게됩니다.

두번째 캔버스에는 자주 변경되는 “동적인” UI 요소를 모두 위치시킵니다. 이렇게 구성하면, 이 캔버스에서는 주로 dirty 상태로 표시된 UI 요소들을 지속적으로 배치(batch)처리합니다. 동적인 UI 요소의 수가 매우 많아지면, 계속해서 변경되는 동적인 UI 요소와 간헐적으로 변경되는 UI 요소들을 구분해서 다시 분할하는 것이 좋습니다.

하지만 이런 가이드라인은 실제로 적용하기가 다소 어렵습니다. 특히, UI 컨트롤을 프리팹으로 만들때 적용하기가 어렵습니다. 그대신 부하가 큰 UI 요소를 하위 캔버스로 분할해서 캔버스를 세분화할 수 있습니다.

 

유니티 5.2 및 최적화된 배칭 (Unity 5.2 and Optimized Batching)

유니티 5.2에서는 배치(batch)를 처리하는 코드가 실질적으로 다시 작성되어, 유니티 4.6, 5.0, 5.1버젼에 비해서 성능이 크게 향상되었습니다. 또한, 코어가 1개 이상인 장치에서는 유니티 UI 시스템이 대부분의 프로세싱 처리를 작업 쓰레드(worker thread)로 옮겨서 처리합니다. 일반적으로, 유니티 5.2에서는 하나의 UI를 수십개의 하위 캔버스로, 적극적으로 분할시킬 필요가 없습니다. 이제는 모바일 장치에서 동작되는 UI의 다수를 2개 또는 3개 정도의 캔버스를 사용해서 효율적으로 구성할 수 있습니다.

유니티 5.2의 최적화에 대한 자세한 내용은 이 블로그 포스트를 참고하시기 바랍니다.

 

유니티 UI의 입력 및 래이캐스팅 (Input and raycasting in Unity UI)

기본적으로, 유니티 UI는 Graphic Raycaster 컴포넌트를 사용해서 터치 및 pointer-hover와 같은, 입력 이벤트를 처리합니다. 이런 이벤트들은 일반적으로 Standalone Input Manager 컴포넌트에서 처리됩니다. 그 이름에도 불구하고, Standalone Input Manager는 “보편적인” 입력 관리자 시스템으로 설계되었고, 포인터와 터치 입력을 모두 처리합니다.

 

모바일에서의 잘못된 마우스 입력 감지 (Erroneous mouse input detection on mobile (5.3))

유니티 5.4 이전 버젼에서는 터치 입력의 사용이 불가능한 경우, Graphic Raycaster가 추가되어있는, 활성화된 캔버스(Canvas)에서 포인터의 위치를 확인하기 위해서 프레임 당 한번 레이캐스트를 실행합니다. 이는 플랫폼에 관계없이 같은 방식으로 동작합니다; 마우스가 없는 iOS와 안드로이드 장치에서도 마우스 포인터의 위치를 찾고, 그 위치 아래에 있는 UI 요소를 찾으려고 시도합니다(2).

이런 동작은 CPU 시간을 낭비하며, 유니티 어플리케이션 CPU 프레임 시간의 5% 이상을 소비하는 것으로 확인되었습니다.

이 문제는 유니티 5.4에서 해결되었습니다. 유니티 5.4 버젼부터는 마우스가 없는 장치에서 마우스 포인터의 위치를 추적하지 않고, 불필요한 레이캐스트를 처리하지 않습니다.

유니티 5.4 이전 버젼을 사용하는 경우, 모바일 개발자가 자신만의 입력 관리자 클래스를 만들어서 사용할 것을 권장합니다. 단순히 유니티 UI 소스 코드에서 Standard Input Manager의 내용을 복사해서 ProcessMouseEvent 메소드와 이 메소드를 호출하는 메소드를 주석처리하는 간단한 작업을 통해서 입력 관리자 클래스를 제작할 수 있습니다.

 

레이캐스트 최적화 (Raycast optimization)

Graphic Raycaster는 ‘Raycast Target’ 설정이 true로 설정된 Graphic 컴포넌트를 모두 순회하는 비교적 단순한 방식으로 구현되어 있습니다. 각 Raycast Target에 대해서, Raycaster는 일련의 테스트를 진행합니다. 특정 Raycast Target이 이 테스트를 통과하면, hit 목록에 추가됩니다.

Raycast 구현 세부정보 (Raycast implementation details)

그 테스트는 다음과 같습니다:

  • 해당 Raycast Target이 활성화된 상태이고, 화면에 그려지고 있는지 테스트합니다. (예: 지오메트리(UI 메쉬)를 갖는 경우)
  • 입력 위치가 Raycast Target이 연결되어있는 RectTransform안에 있는지 테스트합니다.
  • Raycast Target 또는 그 자식 계층(깊이에 관계없이)에서 ICanvasRaycastFilter 컴포넌트를 가지고 있는 경우, Raycast Filter 컴포넌트에 해당 Raycast를 허용합니다.

Raycast Target의 hit 목록은 그 다음, 깊이(depth)에 따라서 정렬되고, 역 타겟(reversed targets)을 위해서 필터링되며, 카메라 뒤에(즉, 화면에 표시되지 않는 UI 요소) 렌더링되는 요소들이 제거되도록 필터링 됩니다.

Graphic Raycaster는 또한 Graphic Raycaster의 “Blocking Objects” 속성의 각 플래그(flag)가 설정되어 있으면, 3D 또는 2D 물리 시스템에 Ray를 투사할수도 있습니다. (스크립트에서는 해당 속성의 이름이 blockingObjects 입니다.)

2D 또는 3D 블로킹 오브젝트(blocking objects)가 활성화된 경우, 레이캐스트-차단 Physics Layer가 설정된 2D 또는 3D 오브젝트 아래에 그려지는 Raycast Target은 모두 hit 목록에서 제거됩니다.

그런 다음, hit 목록이 반환됩니다.

 

레이캐스팅 최적화 팁 (Raycasting optimization tips)

Raycast Target은 모두 Graphic Raycaster에서 테스트 해야하기 때문에, 포인터 이벤트가 처리되어야하는 UI 컴포넌트에서만 ‘Raycast Target’ 설정을 활성화하는 것이 좋습니다. Raycast Target 목록이 작을수록, 그리고 확인해야하는 계층이 얕을 수록 Raycast를 테스트하는 속도가 빠릅니다.

버튼과 같이 배경과 텍스트 색상을 모두 변경하기 위해서 포인터 이벤트에 반응하는 UI 오브젝트 여러 개가 혼합된 UI 컨트롤의 경우, 일반적으로 해당 복합 UI 컨트롤의 루트 게임오브젝트를 단일 Raycast Target으로 설정하는 것이 좋습니다. 이렇게 설정한 단일 Raycast Target이 포인터 이벤트를 받으면, 이 이벤트에 반응해야하는 각 컴포넌트에 이벤트를 전달할 수 있습니다.

계층구조 깊이 및 레이캐스트 필터 (Hierarchy depth and raycast filters)

각각의 Graphic Raycaster는 레이캐스트 필터를 검색할때 트랜스폼 계층을 루트까지 모두 탐색합니다. 이 작업의 비용은 계층구조의 깊이에 비례해서 선형적으로 증가합니다. 계층구조 내의 각 트랜스폼에 추가되어있는 모든 컴포넌트에서 ICanvasRaycastFilter를 구현했는지 여부를 확인해야하기 때문에, 이 작업은 비용이 저렴하지 않습니다.

CanvasGroup, Image, Mask, RectMask2D와 같이 ICanvasRaycastFilter를 사용하는 표준 유니티 UI 컴포넌트는 여러가지가 있기 떄문에 이런 순회 작업을 쉽게 제거하기는 어렵습니다.

 

하위 캔버스와 OverrideSorting 속성 (Sub-canvases and the OverrideSorting property)

하위 캔버스의 overrideSorting 속성은 Graphic Raycaster가 트랜스폼 계층을 순회하는 것을 중단시킬 수 있습니다. 이 속성을 활성화 했는데도 정렬 문제나 레이캐스트 감지 문제가 발생하지 않는 경우에는, 이 속성을 사용해서 레이캐스트 계층 순회 비용을 줄이는 것이 좋습니다.

각주 (Endnotes)

  1. “중간 계층(Intermediate layer)”은 배치(batch)처리가 가능한 오브젝트와 다른 재질(Material)을 사용하는 오브젝트로서, 배치처리가 가능한 두 오브젝트들 사이에 위치한 것을 말합니다.
  2. Hover 이벤트가 전송되어야 하는지 여부를 발견하기 위함입니다.

 

내용 끝까지 읽어주셔서 감사합니다.
배너 클릭은 저에게 많은 힘이 됩니다.
감사합니다 🙂

 

다음글 – Optimizing UI Controls

RonnieJ

프리랜서 IT강사로 활동하고 있습니다. 게임 개발, C++/C#, 1인 기업에 관심이 많습니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

Please turn AdBlock off

Notice for AdBlock users

Please turn AdBlock off