최적화 가이드라인

From Neos Wiki
Jump to navigation Jump to search
This page is a translated version of the page Optimization Guidelines and the translation is 98% complete.
Other languages:
English • ‎日本語 • ‎한국어

이 문서는 커뮤니티 기반으로 작성되어진 문서이며, 여러가지 성능 최적화 기법들이 기록되어 있습니다. 또한, 모든 위키문서는 누구라도 이 문서를 수정할 수는 있으나, 네오스팀의 공식적인 의견(디스코드 답변 등)과 같은 기반근거도 같이 제공해 주세요.

렌더링

블렌드셰이프

블렌드셰이프는 메시를 구성하는 모든 점들의 위치를 동적으로 변화시킵니다. (참조링크). 만약, 블렌드셰이프 영역과 그렇지 않은 정적인 메시 영역이 분리되어있지 않다면, 성능낭비입니다. 네오스는 SkinnedMeshRenderer component 아래에 있는 "블렌드셰이프의 영향을 받지 않는 메시"를 이용하여 자동적인 최적화를 수행할 수 있습니다. 이를 이용한 성능개선 결과는 각 사례별로 다르므로 진행전/후 테스트를 해 보셔야 합니다.

Any blendshape not at zero has a performance cost proportional to the number of vertices, even if the blendshape is not changing. For example, a one million vertex mesh will have a significantly higher performance impact with a blendshape at 0.01 than with the blendshape at 0. If you have a mesh with non-driven blendshapes set to anything other than zero, consider baking them.

머티리얼

몇몇 머티리얼(특히 Fur material)은 다른 유형에 비해 성능을 많이 소비 합니다. (참조링크)

Alpha/Transparent/Additive/Multiply와 같은 Blend mode들은 투명 머티리얼로 상정됩니다. 이 모드는 렌더링과 필터링을 수행해야 하므로 성능비용이 비싼편입니다. 투명 머티리얼들은 전통적인 포워드 렌더링 파이프라인을 이용하므로 빛의 동적인 움직임을 자연스럽게 처리하지 못합니다. PBS 머티리얼의 Opaque와 Cutout Blend mode는 디퍼드 렌더링을 이용하기에 조명처리를 더 잘 수행합니다.

텍스쳐 해상도

정사각형의 텍스쳐 해상도(2, 4, 8, 16 ..... 4096... etc)는 VRAM에서 작업할때 좀 더 효율적입니다.

텍스쳐 아틀라스

만약 동일 유형의 머티리얼을 여러개 사용하는 경우라면, If you have a number of different materials of the same type, 아틀라스 텍스쳐(한개의 큰 이미지 파일에 여러개의 텍스쳐를 합친 텍스쳐)의 이용을 고려하는것도 그 방법입니다. (참조링크)

각각의 메시가 서로다른 설정을 사용하더라도 맵을 추가하는 식으로 머티리얼을 합칠 수 있습니다. 하지만, 지나치게 큰 텍스쳐는 VRAM의 소비가 커질 수 있습니다. (참조링크)

아틀라스가 도움이 안되는 경우:

  • 서로 다른 머티리얼이 모두 필요한 경우(예. PBS 아바타에 사용되는 Fur 머티리얼)

절차적 대 정적 에셋

절차적 메시의 속성값을 제어할일이 없다면, 성능향상을 위해 정적 메시로 베이크하세요. 절차적 메시와 텍스쳐는 월드에서 각각 별개로 오브젝트화 됩니다. 정적 메시의 경우, 월드에 한개의 인스턴스만 존재합니다. (참조링크)

GPU 메시 인스턴스 생성

만약, 동일한 정적 메시나 머티리얼로 여러 인스턴스(오브젝트)를 생성한 경우, 모두 인스턴스화 되며, 이는 많은수의 나무를 배치하는 환경(참조링크)처럼 동일 오브젝트로 여러 인스턴스를 추가하여 렌더링할때 상당한 성능 향상을 기대할 수 있습니다. SkinnedMeshRenderers의 경우 이런 GPU 인스턴싱에 효과적이지 않습니다.(참조링크)

거울과 카메라

거울과 카메라의 성능 비용은 부가적인 렌더링 과정으로 인해 상당히 비쌉니다. 특히나 해상도에 따라 그 비용은 그만큼 더 커집니다. 일반적으로 거울은 카메라보다 성능비용이 비싼편인데, 그 이유는 VR환경일때 눈 하나당 한개씩 렌더링 과정이 추가되기 때문입니다.

카메라(/Rendering/Camera 구성요소)의 경우 near(최근)/far(최장)거리 조절과 selective(대상지정캡쳐)/exclusive(캡쳐제외대상)을 이용하여 성능향상을 꾀할 수 있습니다. 기본적으로 불필요한 대상은 렌더링하지 마세요.

거울과 카메라를 ValueUserOverride 구성요소를 이용하여 로컬화하는 방법을 추천합니다.

반사 프로브

베이크된 반사 프로브는 꽤나 저렴합니다, 특히 128x128의 기본 해상도 일 때. 실제 비용은 큐브 맵을 저장하는 데 사용되는 VRAM입니다.[1]

실시간 반사 프로브는 매우 비싸며 6대의 카메라와 견줄 만합니다. [2]

조명

빛의 영향은 빛이 비추는 픽셀 수에 비례합니다. 이 값은 영향을 미치는 기하학에 관계없이 월드의 가시광선 볼륨 크기에 따라 결정됩니다. 따라서 짧은 거리 또는 부분적으로 차단되는 조명이 더 저렴합니다.

그림자가 있는 빛은 없는 빛보다 훨씬 더 비쌉니다. 디퍼드 쉐이딩에서 그림자 캐스팅 메시는 여전히 각각의 그림자 캐스팅 빛에 대해 한 번 이상 렌더링되어야 합니다. 또한 그림자를 적용하는 조명 셰이더는 그림자를 비활성화 하였을 때 사용하는 것보다 렌더링 오버헤드가 더 높습니다. [3] [4]

그림자가 있는 포인트 라이트는 주변 씬을 6번 렌더링하기 때문에 매우 비쌉니다. 그림자가 필요하면 되도록 스폿 광원(Spot Light)이나 방향 광원(Directional Light)을 사용하세요. [5]

컴포넌트의 ShadowCastMode Enum 값을 사용하여, MeshRenderer 또는 SkinnedMeshRenderer 컴포넌트가 그림자를 캐스팅할지 제어할 수 있습니다. 이것을 'Off'로 변경해, 일부 메시에 그림자를 캐스팅 하고 싶지만, 모든 메시에는 그림자를 캐스팅하고 싶지 않을때(따라서, 관련하는 조명의 그림자를 무효로 하고 싶지 않을때) 도움이 됩니다. 또한 디테일이 높은 매쉬의 그림자 캐스팅을 끄고, 비슷하지만 디테일이 낮은 메시를 배치하고 ShadowCastMost 를 'ShadowsOnly'로 설정하여 퍼포먼스 향상을 노릴수 있습니다. Comment from Geenz in response to Medra during Office Hours

컬링

'컬링'은 성능 비용을 줄이기 위해 세계의 특정 부분을 처리하지 않거나 적어도 렌더링하지 않는 것을 말합니다.

프러스텀 컬링

네오스는 자동적으로 프로스텀 컬링을 수행, 즉 시야 밖의 개체는 렌더링되지 않습니다(예: 유저 뒤에있는 오브젝트). 프로스텀 컬링의 경우, 가시성과 관련하여 연산 비용이들지만, 보통은 각 메시에 따라 일정합니다. 검출 프로세스는 각 오브젝트의 바운딩 박스에 의존하고 있으며 바운딩 박스는 기본적으로 메시 전체를 완전히 감싸는 축 정렬된 상자입니다. 따라서 메시 복잡도와는 관계가 없습니다(초기 연산을 위한 저장이나, 스킨 메시, 본의 갯수, 다른 연산 모드들). 이 시스템에서 최적으로 동작하기 위해서는 몇가지 고려해야할 사항이 있습니다. [6]:

  • 이 시스템에서 오브젝트가 컬링되어야 하는지 여부를 체크하는 비용은 엑티브된 메시의 수에 따라 변화합니다. 즉, 사용자가 만든 컬링 시스템(아래 참조 below)와 함께 사용함으로써, 테스트 되어야하는 활성화 메시의 수를 줄일 수 있습니다.
  • 바운딩박스로 인하여, 메시의 어떠한 부분이라도 보이도록 경정되면, 전체 메시를 렌더링 해야합니다 - 네오스는 메시를 부분적으로만 렌더링할 수 없습니다.
    • 따라서 일반적으로 전체 메시가 한 번에 보이지 않을 경우 큰 메시를 작은 조각으로 분리하는 것이 좋은 방법 이라고 할 수 있습니다. 넓은 월드의 지형 메시를 서브-메시로 분할하는게 적합 하다고 볼수 있습니다.
    • 한편, 일반적으로 동시에 표시되는 메시와 결합하는 것이 좋은 경우도 있습니다. 여러 개의 머티리얼을 가진 메시를 조합한다고 해서, 직접적으로 렌더링 비용이 절감되는 것은 아니지만, 메시 컬링 여부에 대한 연산 비용을 "절감" 됩니다. 여러 개의 메시를 하나의 메시로 베이크한 경우, 바운딩 박스의 테스트는 그 결합된 메시에 대해 한 번만 수행됩니다. 이것은 사실상 유니티(Unity)에있는 정적 배칭(static batching)의 Neos 버전 입니다.

또한 SkinnedMeshRenderer components에는 바운딩 연산을 위한 여러 모드가 있어 서로 다른 성능 비용이 듭니다. 연산 모드는 각 SkinnedMeshRenderer 컴포넌트의 BoundsComputeMethod에 의해 표시됩니다[7]:.

  • Static은 메시만을 기반으로 하는 매우 싼 방법입니다. 이것은 실시간 연산이 필요하지 않으므로 가능하면 이것을 사용하는 것이 이상적인 방법입니다.
  • FastDisjointRootApproximate는 먼저 전체 본 수를 줄이기 위해 모든 본을 분리된 그룹에 머지(Merge)합니다(겹쳐져져있는 본은 하나로 머지됩니다). 그리고 이것을 사용하여 실시간으로 바운드를 근사합니다. 가장빠른 실시간 방법은 'Static' 사용 시 메시 일부가 컬링되어 있을 경우 권장합니다.
  • MediumPerBoneApproximate은 모든 본의 바운드에서 메시의 바운드를 계산합니다. 더 정확하지만 더 느립니다.
  • SlowRealtimeAccurate은 실제로 변환된 지오메트리(Geometry)를 사용하여, 스킨된 메시가 항상 처리되어야 합니다. 매우 무겁지만 본 이외에 블렌드 셰이프 같은 것을 존중(respect)합니다.
  • Proxy는 다른 것들과는 다르며, 잠재적으로 저렴합니다. Proxy Bounds Source 필드에서 참조된 다른 Skinned Mesh Renderer를 위해 계산된 바운딩 상자에 의존합니다. 큰 메인 메시가 있어 그것에 링크된 작은 메시의 가시성이 필요한 경우 편리합니다[8].

유저가 만든 컬링 시스템

사용자의 위치에 따라 슬롯을 비활성화하거나 컴포넌트를 비활성화하여 월드에 추가적인 컬링 시스템을 만들 수 있습니다. 매우 효율적인 컬링 솔루션은 ColliderUserTracker component로 만들 수 있습니다. 이 방법은 NoClip 로코모션과 호환되지 않음으로 유의하시기 바랍니다. 이 컴포넌트를 컬링 시스템에 사용하는 방법은 ProbablePrime 의 유튜브를 통해서 확인 하실 수 있습니다.

콜라이더 컴포넌트의 특정 컬링 관련 고려 사항

콜라이더가 자주 활성화/비활성화 하는 수동 컬링의 실행은 가능하면 피해주십시오. 콜라이더의 포퍼먼스에 미치는 영향은 렌더러와는 조금 다른 구조로 되어 있습니다. 콜라이더의 퍼포먼스 비용은 연광성이 있을 경우에만 체크되므로 이미 최적화되어 있습니다. 콜라이더를 정기적으로 온/오프하면 이 알게 모르게 실행 되던 최적화 프로세스가 중단되어 비용이 더 들게 됩니다.[9]

로직스

로직스를 적게 사용하는 것보다. 계산을 적은 영역에서 하는 것보다는 계산을 적게 하는 것이 중요합니다. "오직 컴포넌트"를 사용하는 것이 더 최적화된 방법이라고 생각하여, 로직스 사용을 기피하는 것 또한 권장하지 않습니다. 여러 로직스 노드를 사용하는 것보다 특정 컴포넌트를 사용하는 것이 더 좋은 해결책인 경우도 많고, 또한 그 반대도 많습니다.

근본적으로 로직스 노드는 컴포넌트입니다. - ProbablePrime의 영상을 시청해보세요.

쓰기과 드라이버

Sync 의 값을 변경하면 데이터 모델에 대한 변경이 세션의 다른 사용자에게 전달되어야 하기 때문에, 네트워크 트래픽이 발생합니다. ValueUserOverride 에서는 오버라이드 자체가 Sync 이기 때문에 이 네트워크 활동은 없어지지 않습니다.[10]

예외:

  • Drivers는 모든 사용자가 로컬로 계산을 수행하며, 네트워크 트래픽이 발생하지 않습니다.
  • "Self Driven values" (Writeback을 활성화하고 동일한 소스와 Target을 지정한 ValueCopy를 지칭함)는 Write node를 사용하여 값을 변경하여도 로컬로 계산됩니다.
  • 동일한 업데이트에서 한 값에 여러 번 쓰기가 발생하는 경우 마지막 값만 네트워크를 통해 복제됩니다.

일반적으로 로컬에서 계산하게 하고, 네트워크 사용을 피하는 것이 좋지만, 복잡한 계산의 경우 한 명의 유저가 계산하고 결과를 Sync 하는 것이 좋습니다.

동적 변수와 임펄스

Dynamic Variables는 매우 효율적이며, 성능에 구애받지 않고 사용할 수 있습니다. 하지만 Dynamic Variable Spaces 생성 및 파기에는 큰비용이 들기 때문에 사용을 지양하는 것이 좋습니다.[11]

Dynamic Impulses 또한 효율적이며, 특히 receiver에 가까운 슬롯에 Target 하면 좋습니다.[12]

잦은 임펄스

Update 노드의 잦은 업데이트, Fire While True 등의 잦은 업데이트가 네트워크 복제로 연결되는 경우를 가능한 한 지양하여야 합니다. 이것을 Drivers로 바꾸어 로컬로 계산하도록 바꾸는 것을 검토해 주세요.

업데이트 릴레이 노드

Updating Relays는 Logix의 정상적인 짝수 구동 성질을 회피하고 프레임마다. 평가(evaluation)를 강제하기 때문에 비용이 많이 듭니다. 디스플레이가 갱신되지 않기 때문에 갱신 릴레이가 필요한 것처럼 보일 수 있지만, 대부분의 경우 문제는 디스플레이의 고유한 것이며, 최종적인 Logix에는 필요하지 않습니다. 이 노드의 사용은 가능한 한 피하여야 합니다.

시퀀스 노드

Sequence node는 성능적으로 나쁘지 않지만, 너무 많이 사용하면 코딩 방법이 이상해집니다. 노드를 연쇄적으로 연결하여, 예기치 못한 오류 전파를 막지만, Sequence는 에러가 발생하여도 계속 실행되기 때문에 잘못된 사용을 하게 된다면, 로직스를 나쁜 상태(bad state)로 만들게 됩니다.

캐시 노드

Cache node 사용은 네오스가 자동으로 수행하는 매우 특수한 최적화가 있기 때문에 걱정하지 않으셔도 됩니다. [13]

샘플 컬러 노드

Sample Color 노드는 작고 좁은 시야를 렌더링하여 동작하기 때문에 본질적으로 비용이 많이 듭니다. Near Clip 및 Far Clip 입력을 사용하여 렌더링 범위를 제한하여 퍼포먼스 비용을 절감할 수 있습니다. 비용 문제로 사용을 지양하는 것이 좋습니다. [14]

슬롯 카운트

Slot Count와 패킹된 Logix 수는 성능적으로 중요하지 않습니다. 복잡한 설정의 경우 로드와 세이브에 부하가 걸리며, 이 부하는 로직스 노드를 하나의 슬롯에 넣는다고 해서 없어지지 않습니다. Neos는 여전히 똑같은 수의 컴포넌트를 로드 및 저장하여야 합니다.[15]

프로파일링(Profiling)

만약 퍼포먼스를 저해할 가능성이 있는 새로운 아이템을 만들고 있다면, 프로파일링해보는 것을 권장합니다.

  • [대시 메뉴]의 [홈] 탭에 있는 [Debug] 메뉴에 도움이 되는 타이밍이 많습니다.
  • SteanVR에는 GPU의 프레임 타임을 표시할 수 있는 "퍼포먼스 그래프 표시"가 있습니다. 개발자 설정에서 헤드셋 내에 표시할 수도있습니다. (설정 메뉴에서 "Advanced Settings"을 토글)