원문 : http://bytewrangler.blogspot.kr/2011/10/signed-distance-fields.html

주의 : 허락받고 번역한 것이 아니므로 언제든 내려갈 수 있습니다.

주의 : 번역이 개판이므로 이상하면 원문을 참조하십시오.



Signed Distance Fields


필자는 Valve Software 의 Ghris Green 이 작성한 이 백서에서 처음으로 부호있는 디스턴스 필드( Signed Distance Fields )라는 것을 접했습니다. Valve 는 자신들의 이용가능한 그래픽스 기술들에 대한 기술 문서들을 만드는데, 정말 멋집니다. 이 경우에, 이 기법은 팀 포트리스 2 에서 사용되었는데, 특히 게임 내의 표지판이나 데칼들에 사용되었습니다.


부호있는 디스턴스 필드는 ( 일반적으로는 흑백인 ) 비트맵 데이터를 저장하는 다른 방식입니다. 비트맵의 각 픽셀이 그 점에서의 강도( intensity )를 표현하는 것이 아니라, 소스 이미지에서 검정색이 아닌 가장 가까운 픽셀에 대한 거리를 표현합니다. 그 모양 바깥쪽에 존재하는 픽셀들은 양수 거리 값을 가지게 됩니다. 반면에 그 모양 안쪽의 픽셀들은 음수 거리 값을 가지게 됩니다. 그러므로 "부호있는( signed )" 이라는 이름이 들어갑니다.


그림 1: 부호있는 디스턴스 필드가 픽셀 수준에서 보여지는 방식에 대한 예제.


디스턴스 필드는 사실 실수 데이터로 구성되어 있지만, 설명의 목적 때문에 정수로 보여 준다는 것에 주의하시기 바랍니다.


부호있는 디스턴스 필드를 생성하기 위해서, 여러분은 소스 이미지에 대한 디스턴스 트랜스폼( distance transform )을 적용합니다. 그리고 나서 원래 이미지를 렌더링하기 위해 다음과 같이 합니다.



부호있는 디스턴스 필드를 실제로 유용하게 만드는 것은 여러분이 이미지를 리사이징할 필요가 있을 때입니다. 이 거리값은 3D 하드웨어에 의해서 보간되는데, 그것은 전통적인 비트맵의 강도 값이 보간되는 방식과 동일합니다. 그러나 엣지가 테스트에 의해 생성되기 때문에, 그것은 crisp 하게 남아 있게 됩니다. 이는 여러분이 비트맵을 여러 번 확대할 수 있으며, 전통적인 비트맵이 필터링 아티팩트 때문에 뭉개지거나 두툼해지는 것과는 다르게 그런 현상을 겪지 않게 된다는 것을 의미합니다.


Creating the Distance Field


디스턴스 필드를 계산하기 위해서 사용할 수 있는 많은 트랜스폼들이 존재합니다. 가장 좋은 접근법은 고해상도 소스 이미지를 사용하고 여러분의 응용프로그램에 적절한 사이즈로 그것을 다운샘플링하는 것입니다. 그러면 디스턴스 필드의 속성이 많은 정보들을 보존하게 됩니다.


Brute force 기법( 비트맵에서 주어진 픽셀과 다른 픽셀들 간의 유클리디안( euclidean ) 거리를 계산하는 것을 의미합니다 )은 완벽한 디스턴스 필드를 생성하지만, 그것은 O(n^2) 복잡도를 가지기 때문에 큰 이미지에 대해서는 매우 느립니다. ( 정확하지는 않지만 ) 더 빠른 알고리즘이 존재하긴 합니다만 알고리즘을 선택하는 것은 별로 중요하지 않습니다. 왜냐하면 런타임에 실행할 필요가 없기 때문입니다. Valve 는 실제로 brute force 방식을 사용했으며 그들의 서버에서 밤 시간동안에 batch job 으로 처리합니다. 필자는 그냥 더 빠른 접근법을 선택했습니다. 왜냐하면 결과를 얻기 편하기 때문입니다.


그림 2: Bulldog 에서 최종 디스턴스 필드가 어떤 모양인지 보여주는 예제.


An application of Distance Fields


디스턴스 필드를 위한 소스 데이터는 일반적으로 흑백이기 때문에, 그것의 유용성은 제한되어 있습니다. 그러나 디스턴스 필드에 매우 적합한 응용프로그램은 텍스트를 그리는 것입니다.


예를 들어 TrueType 이나 OpenType 폰트( 혹은 정확한 개념을 사용하기 위해 "typeface" )는 벡터 형식으로 저장됩니다. 이것은 각 상형문자들( glyphs, typeface 내의 문자들 )이 코너( corner )와 제어점( control point )을 위해 x, y 좌표를 가진 도형으로서 표현됨을 의미합니다. 이는 스크린 상의 디스플레이를 위해서 비트맵으로 변환되거나 "래스터화( rasterised )"됩니다. 여러분이 원하는 텍스트의 크기에 의존해서 x, y 좌표들은 스케일링( scale )되며 문자 도형을 표현하는 커브들도 스케일링됩니다. 래스터화 과정은 현대 하드웨어에서도 느릴 수 있습니다. 그래서 게임에서 선호되는 방식은 여러분이 원하는 크기로 폰트를 미리 래스터화해서 비트맵에 저장하는 것입니다. 그리고 나서 비트맵으로부터 개별 문자들을 선택함으로써 요청된 텍스트를 구성합니다.


이 기법은 매우 빠르지만, 약간의 제약이 있습니다. 여러분은 모든 크기와 스타일의 조합에 대해서 개별적인 폰트 비트맵을 생성해야만 합니다. 왜냐하면 비트맵은 잘 스케일링되지 않기 때문입니다. Take for example a game that wants to have 2 different typefaces, say a normal looking sans serif typeface like Arial, and maybe a fancier caligraphy typeface for ye olde books and scrolls and the like. 문체상의( stylistic ) 이유로 여러분은 3 개의 다른 크기를 원할 것입니다. 타이틀/캡션 혹은 툴팁같은 것들 때문에 말이죠. 혹은 다양한 범위의 스크린 해상도를 지원하고자 할 수도 있고, 사람들이 UI 요소들을 읽는데 현미경을 필요로 하기를 원치 않을 수도 있습니다.  이미 우리는 2 * 3 = 6 개의 비트맵을 생성하고 관리해야 합니다. 만약 여러분이 이탤릭체나 볼드체를 원한다고 하면 더 심각해질 수 있습니다.


부호있는 디스턴스 필드 접근법은 taking the sizing out of the equation 을 통해 이러한 짐을 경감시켜주는데 도움을 줍니다. 왜냐하면 디스턴스 필드는 그래픽적 아티팩트가 거의 없이 스케일을 늘리거나 줄일 수 있기 때문입니다.


보너스로 디스턴스 필드 데이터를 사용해서 엣지를 안티 에일리어싱할 수 있습니다. 이는 거리 테스트에 부가적인 항을 추가함으로써 가능한데, 특정 범위 내의 디스턴스 값들에 대해서 페이딩( smoothly ramp from lit to unlit )을 수행합니다. Valve 기사에서는 drop shadows 와 outline 과 같은 몇 가지 다른 효과들에 대해 다룹니다.


Bulldog 에서 필자는 픽셀 쉐이더를 사용해서 부호있는 디스턴스 필드 폰트를 구현했는데, 그것은 디스턴스 필드 데이터를 가지고 노는 것을 꽤 쉽게 만들어 줍니다.


이 쉐이더 코드는 놀랄만큼 단순하며, 단순한 안티 에일리어싱 텍스트는 다음과 같습니다:



delta 는 상수인데, 이것은 문자의 엣지로부터 안티 에일리어싱이 확장되는 거리를 결정합니다. Bulldog 에서 필자가 사용하는 실제 쉐이더 코드는 약간 더 복잡합니다. 왜냐하면 그것은 테두리( border )와 ( 텍스트 박스에서 텍스트를 선택한 경우같이 ) ( 역주 : 색상이 )반전된 문자를 다뤄야 하기 때문입니다. 또한 다양한 폰트 크기에 대해 안티 에일리어싱을 조정해야 하기 때문입니다. 필자는 나중에 부호있는 디스턴스 필드를 사용해서 만들어진 새로운 폰트 시스템에 대한 포스트를 작성할 것입니다. 현재로서는, 여기에서는 다양한 크기로 렌더링된 같은 폰트들에 대한 예제를 보여드리겠습니다:


그림 3: 12, 24, 64 픽셀에서의 폰트 출력 예제.


마지막으로, Bulldog 의 다른 부분에서 보통과는 다른 방식으로 부호있는 디스턴스 필드를 사용해 봤다고 말씀드리고 싶습니다. 하지만 그것은 다음 포스트에서 언급하겠습니다...

원문 : http://www.valvesoftware.com/publications/2007/SIGGRAPH2007_AlphaTestedMagnification.pdf

주의 : 허락받고 번역한 것이 아니므로 언제든 내려갈 수 있습니다.

주의 : 번역이 개판이므로 이상하면 원문을 참조하세요.



Improved Alpha-Tested Magnification for Vector Textures and Special Effects


Chris Green

Valve


그림 1: 64x64 텍스쳐로 인코딩된 벡터 아트. 

(a) 단순한 바이리니어( bilinear ) 필터링.

(b) 알파 테스팅.

(c) 우리의 디스턴스 필드( distance field ) 기법.


Abstract


굴곡지고 선형적인 요소로 조합된 상형문자( glyph )에 대한 진보된 렌더링을 허용하는 단순하고 효율적인 기법을 제시합니다. 디스턴스 필드( distance field )를 고해상도 이미지로부터 생성한 다음, 저해상도 텍스쳐의 채널에 저장합니다. 가장 단순한 케이스에서, 이 텍스쳐는 현대 GPU 들의 알파 테스팅( alpha testing )과 alpha-thresholding 을 사용해서 커스텀 쉐이더를 사용하지 않고 단순하게 렌더링될 수 있습니다. 이는 가장 낮은 사양의 3D 그래픽스 하드웨어 상에서도 사용될 수 있는 기법입니다.


프로그래밍가능한 쉐이딩을 사용하면, 이 기법은 다양한 특수 효과 렌더링을 수행하기 위해서 확장될 수 있는데, 이는 소프트 엣지( soft edges ), 아웃라인( outlining ), 드랍 쉐도우( drop shadow ), 멀티코어 이미지( multi-cored images ), 샤프 코너( sharp corner ) 등을 포함합니다.


1 Introduction


고품질 실시간 3D 렌더링에서는, 텍스쳐 맵의 저장소를 위해서 이용할 수 있는 제한된 메모리를 효율적으로 사용하는 것이 중요합니다. 컴퓨터 게임과 같은 상호작용가능한 응용프로그램에서는, 사용자가 보통 텍스쳐 매핑된 오브젝트를 매우 확대된 상태에서 볼 수 있는데, 이는 큰 해상도로 저장된 텍스쳐 맵을 요구합니다. 그렇지 않으면 그런 시점에서 볼 때 그림 1a 에서 보이는 것처럼 텍스쳐가 뭉개져 보이게 됩니다.


텍스쳐 맵들이 텍스트( text ), 신호( signs ), UI 요소와 같은 "라인 아트( line art )" 이미지들을 표현하기 위해 사용될 때, 이는 납득할만하게 보이기 위한 매우 큰 해상도의 텍스쳐를 사용할 것을 요구하게 됩니다.


이 문제는 나뭇잎( foliage )과 같은 복잡한 오브젝트들을 위한 알파 테스팅되는 이미지 기반 임포스터들에서도 나타납니다. 커버리지( coverage )로부터 파생된 알파채널을 가진 텍스쳐들이 하드웨어의 바이리니어 필터링을 사용해 확대될 때, 그림 1b 에서 보이는 것처럼 보기싫은 "구불구불한 모양( wiggles )"이 나타납니다. 왜냐하면 커버리지 함수( coverage function )는 선형적이지 않기 때문입니다.


이 챕터에서, 우리는 그러한 텍스쳐가 매우 확대될 때 발생하는 아티팩트들( artifacts )을 최소화하기 위해 알파 테스트된 텍스쳐 맵을 생성하고 렌더링는 단순한 기법을 제시합니다. 우리는 컴퓨터 게임 문맥에서의 몇 가지 사용 시나리오들을 설명할 것인데, 3D 렌더링과 UI 요소들을에 대해 모두 다릅니다. 우리의 기법은 그림 1c 에서 보이듯이 고품질 벡터 아트 렌더링을 생성할 수 있습니다.


2 Related work


텍스쳐 매핑 그래픽스 하드웨어를 사용해 벡터 그래픽스를 정확하게 렌더링하기 위한 많은 기법들이 개발되어 왔습니다. [Firsken et al. 2000] 에서는 2차원 상형문자와 3차원 입체 지오메트리( solid geometry )를 표현하기 위해 디스턴스 필드를 사용했습니다. 지역적 다양성( local variations )에 기반해 디스턴스 필드의 해상도를 순응적으로( adaptively ) 제어하기 위해서 쿼드트리( quadtrees )와 옥트리( octrees )가 사용되었습니다. 그러한 오브젝트에 대한 GPU 렌더링에 대해서는 논의된 바가 없기는 하지만, GPU 프로그래밍 모델의 일반성( generality )에서의 최근의 진보는 이 기법을 DirectX10 을 사용해서 구현할 수 있도록 해 줍니다[Blythe 2006].


[Sen 2004] 와 [Tumblin and Choudhury 2004] 에서는 제어가능한 방식으로 샤프 엣지를 추가하기 위해 텍셀 샘플들간의 보간을 제어하기 위한 부가적 데이터가 텍스쳐 맵에 추가됩니다. 라인 아트 이미지와 하드 엣지( hard edge )를 포함하는 사진( photographic ) 텍스쳐들은 모두 그들의 표현을 사용해서 GPU 상에서 직접적으로 렌더링되었습니다.


[Loop and Blinn 2005] 에서는 음의 3차 커브들( implicit cubic curves, 역주 : implicit curve )을 사용하여 상형문자의 경계( boundaries )를 모델링했습니다. 이 때 smooth resolution-independent curves 를 사용하는 벡터 텍스처를 렌더링하기 위해 GPU 를 사용했습니다.


[Qin et al. 2006] 에서는 거리 기반 표현이 사용되었는데, 각 보로노이 영역( Voronoi region, 역주 : Voronoi diagram )에 영향을 주는 "특징( feature )"들의 미리 계산된 집합들을 사용합니다. 이러한 특징들이 주어지면, 픽셀 쉐이더를 사용해 해석적으로( analytically ) 정확한 거리 값을 계산합니다.


이진 on/off 결과를 산출하기 위해 픽셀쉐이더로부터 알파 값 출력이 thresholding 되는 알파-테스팅은 재구축( reconstructed ) 텍스쳐에서 샤프 엣지를 생성하기 위해서 게임에서 광범위하게 사용됩니다. 불운하게도 일반적으로 이를 위한 소스로서 사용되는 이미지는 서브텍셀( subtexel ) 수준에서 바이리니어 보간을 사용해서 재구축되기에는 적절하지 않은 "커버리지" 정보를 포함하기 때문에,  이 텍스쳐들이 확대될 때 축에 정렬되지 않은 엣지들에 대해서는 보통 보기싫은 아티팩트들이 보이게 됩니다.


3 Representation and Generation


스토리지를 최소한으로 유지하면서 단순한 알파 테스팅의 아티팩트들을 극복하기 위해서, 우리는 벡터 텍스처를 디스플레이하기 위한 기법을 찾아냈으며, 다음과 같은 것들을 수행할 수 있습니다 :


    • 프로그래밍가능한 쉐이딩을 수행할 수 없는 시스템을 포함하는 다양한 수준의 그래픽 하드웨어에서 작동합니다.
    • 표준 텍스쳐 매핑에 가깝거나 가능한한 빠르게 실행됩니다.
    • 모든 현대 GPU 들에서 바이리니어 보간 표현의 이점을 취합니다.
    • 적은 변경만을 동반하는 이미 존재하는 복잡한 쉐이더 시스템[Mitchell et al. 2006] 내부의 함수입니다.
    • 약간의 명령만을 픽셀 쉐이더에 추가하므로, 벡터 텍스쳐는 명령 제한을 초과하지 않고 현존하는 쉐이더들 내에서 사용될 수 있습니다.
    • 벡터 형식으로 제공되는 입력 이미지를 요구하지 않습니다.
    • 현존하는 저해상도 8 비트 텍스쳐 포맷을 사용합니다.
    • 알파 테스팅되는 임포스터 이미지들을 직접적으로 대체하기 위해서 사용됩니다.


우리는 고르게 샘플링되는 부호있는 디스턴스 필드 표현( uniformly-sampled signed-distance field representation )을 구현하기로 했습니다. 그리고 거리 함수는 8 비트 채널에 저장됩니다. 이렇게 함으로써, 우리는 내장된 바이리니어 텍스쳐 보간의 이점을 취할 수 있으며, 이는 서브 텍셀들 간의 거리와 매우 고해상도 이미지에 대한 piecewise-linear approximation 을 정확하게 재구축하기 위해 모든 현대 GPU 에서 사용될 수 있습니다. 이 표현은 다른 접근법들과 비교할 수 있게 표현할 수 있는 특징 토폴로지( topology of features )의 관점에서는 제약이 있기는 합니다만, 그것의 성능, 단순함, 우리의 현존하는 렌더링 시스템과의 통합의 편의성들을 고려했을 때 Valve 의 소스 엔진을 위한 올바른 선택이라는 점에서 만족스럽습니다.


기반 아트의 벡터 기반 표현으로부터의 적절한 거리 데이터를 생성하는 것이 가능하지만, 대신에 우리는 고해상도 소스 이미지로부터 저해상도 디스턴스 필드를 생성하기로 했습니다. 일반적인 경우에는, 4096x4096 이미지를 사용해서 그림 2 에서 보이는 것과 같은 64x64 의 저해상도 이미지로 디스턴스 필드 텍스쳐를 생성합니다.


그림 2: (a) 고해상도( 4096x4096 ) 이진 입력이

(b) 저해상도( 64x64 ) 디스턴스 필드를 계산하기 위해 사용됨.


텍스쳐 생성 시점에, 생성기( generator )는 입력으로 고해상도 이진 텍스쳐를 사용하는데, 여기에서 각 텍셀은 "in" 이나 "out" 으로 식별됩니다. 사용자는 대상 해상도와 "spread factor" 를 설정하는데, 이는 0 에서 1 범위로 8 비트 텍스쳐 채널에 부호있는 디스턴스를 매핑하는데 사용됩니다. Spread 요소는 드랍 쉐도우나 아웃라인으로서의 특수 렌더링 속성과 같은 효과의 영역( domain )을 제어하는 데도 사용되는데, 이에 대해서는 4.2 섹션에서 논의하도록 하겠습니다.


각 출력 텍셀들의 경우, 디스턴스 필드 생성기는 고해상도 이미지 내의 관련 픽셀들이 "in" 인지 "out" 인지를 결정하게 됩니다. 부가적으로 생성기는 반대 상태에 있는 가장 가까운 텍셀에 대한 ( 텍셀 단위의 ) 2D 디스턴스를 계산합니다. 이는 주어진 픽셀 주변의 지역적 이웃들을 검사함으로써 수행됩니다. 우리의 단순한 "brute-force" 검색보다 부호있는 디스턴스 필드를 계산하기 위한 더 효율적이고 복잡한 알고리즘들이 있기는 하지만, 8 비트 채널에 제한된 디스턴스 범위가 들어가야 하기 때문에, 적은 이웃들만이 검색되어야 합니다. 이 단순한 brute-force 기법을 위한 실행시간은 무시할만 합니다.


이 부호있는 디스턴스가 계산되고 나면, 우리는 그것을 0 에서 1 범위로 매핑하는데, 0 은 최대 음수 거리를 의미하며, 1 은 최대 양수 거리를 의미합니다. 텍셀값이 0.5 이면 정확한 엣지의 위치를 표현합니다. 그러므로 0.5 는 일반적으로 알파 문턱값( threshold ) 값으로 사용됩니다.


4 Rendering


가장 단순한 경우에, 결과 디스턴스 필드 텍스쳐는 말 그대로 지오메트리가 알파 테스팅을 사용해서 렌더링되는 모든 문맥에 사용될 수 있습니다. Under magnification, this will produce an image with high-resolution ( albeit, aliased ) linear edge, free of the false curved contours ( see Figure 1b ) common with alpha-tested textures generated by storing and filtering coverage rather than a distance field. 디스턴스 필드 표현을 사용하면, 우리는 그냥 알파 테스트 문턱값을 0.5 로 설정해야 합니다. 비용이 많이 드는 정렬 단계를 회피하기 위해서 특정 프리미티브 클래스들을 위해 알파 블렌딩 대신에 알파 테스트를 사용하는 것이 매우 일반적이기 때문에, 이 기법은 성능 부하없이 가시 품질을 즉각적으로 개선할 수 있습니다.


그림 3: 팀 포트리스 2 의 서피스에 적용된 128x128 크기의 

"무단 침입 금지( No trespassing )" 디스턴스 필드 이미지.


그림 3 에서 우리는 팀 포트리스 2 에서 벽 표면에 데칼로 렌더링된 "No Trespassing" 이라는 표지판의 128x128 디스턴스 필드 표현을 소개합니다. 이 데칼의 월드 공간에서 보이는 해상도는 매우 높으며, 확대를 한다고 해도 게임내에서 항상 고해상도가 유지될 것입니다. 우리는 다음 섹션에서 이러한 특별한 데칼 예제를 언급할 것입니다. 왜냐하면 우리는 이러한 방식으로 우리의 벡터 아트를 표현할 때 우리에게 이용가능한 다른 증진법( enhancements )들에 대해 논의할 것이기 때문입니다.


4.1 Antialiasing


만약 주어진 응용프로그램에 대해 알파 블렌딩이 실용적이라면, 같은 디스턴스 필드 표현은 커스텀 프래그먼트 쉐이더를 요청하는 비용으로 그냥 알파 테스팅을 사용하는 것보다 더 좋은 품질의 렌더링을 생성하는데 사용될 수 있습니다. 


그림 4: 256x256 크기의 "No Trespassing" 표지판을 확대.

왼쪽은 하드 엣지 오른쪽은 소프트 엣지.


그림 4 는 거슬리는 에일리어싱 픽셀 엣지를 부드럽게 만드는 단순한 방법을 설명합니다. 두 개의 디스턴스 문턱값인 Distmin 과 Distmax 가 정의되며, 쉐이더는 smoothstep() 함수를 사용해 두 값 사이의 디스턴스 필드 값을 매핑합니다. 픽셀당 스크린공간 도함수( per-pixel screen-space derivatives )를 지원하는 그래픽스 하드웨어상에서, 디스턴스 필드의 텍스쳐 좌표에 대한 도함수는 벡터 아트의 엣지들을 적절히 안티 에일리어싱하기 위해 소프트 영역의 너비를 조절하기 위해 사용될 수 있습니다[Qin et al. 2006]. 텍스처가 축소되면, 에일리어싱 아티팩트를 감소시키기 위해서 소프트 영역을 넓게 만들 수 있습니다. 부가적으로 알파 테스팅되는 나뭇잎을 렌더링할 때, 알파 문턱값은 거리를 사용해 증가될 수 있습니다, 그래서 LOD 튐( popping )을 피하기 위해 거리가 멀어질 수록 나뭇잎은 점진적으로 사라게 됩니다.


4.2 Enhanced Rendering


래스터 하드웨어를 사용해 상쾌한( crisp ? ) 고해상도 안티에일리어싱 벡터 아트를 제공하는 것과 더불어, 우리는 아웃라이닝, 글로우( glows ), 드랍 쉐도우 등과 같은 다른 효과들을 취하기 위해서 디스턴스 필드를 사용하는 추가적인 조작을 할 수 있습니다. 물론 이러한 모든 연산들은 디스턴스 필드에 대한 함수이므로, 그것들은 쉐이더 파라미터를 사용해 동적으로 제어될 수 있습니다.


4.2.1 Outlining


그림 5: 픽셀 쉐이더에 의해 추가된 아웃라인.



두 개의 사용자 지정 디스턴스 값들 사이의 모든 텍셀의 색상을 변경함으로써, 그림 5 의 데칼 예제에서 보이듯이 픽셀 쉐이더를 사용함으로써 단순한 텍스쳐 공간 아웃라이닝이 적욛될 수 있습니다. 확대했을 때 생성된 아웃라인은 꽤 고품질의 엣지를 가지게 됩니다. 물론 아웃라인의 색상과 너비는 그냥 픽셀 쉐이더 상수를 변경함으로써 동적으로 다양해질 수 있습니다.


4.2.2 Glows


그림 6: 픽셀 쉐이더에 의해 추가된 무섭게 빛나는 "외곽 글로우( outer glow )".


알파값이 0.5 와 0 의 문턱값 사이라면, 그림 6 에서 보이듯이 smoothstep 함수를 사용해서 "헤일로( halo )"를 대체하기 위해서 smoothstep 함수를 사용할 수 있는데, 그것의 색상값은 픽셀 쉐이더 상수로부터 옵니다. 이 효과의 동적 속성은 특히 게임에서 강력합니다. 왜냐하면 디자이너들이 글로우 파라미터들을 애니메이션 시킴으로써 특정 게임 상태에 기반해 게임 월드 내의 특정 벡터 조각에 대해 주의( attention )를 줄 수 있기 때문입니다( 체력을 깜박거린다거나 출구 표지를 강조한다거나 하는 등 ).


4.2.3 Drop Shadows


그림 7: 픽셀 쉐이더에 의해 추가된 소프트 드랍 쉐도우.

그림자의 방향, 크기, 투명도, 색상은 동적으로 제어가능함.


단일 거리에 대한 단순한 함수들인 효과들과 더불어, 우리는 그림 7 에 보이는 드랍 쉐도우나 다른 비슷한 효과들을 생성하기 위해 텍스쳐 좌표 오프셋을 사용하여 디스턴스 필드에 대한 이차 룩업( second lookup )을 사용할 수 있습니다.


이러한 단순한 2D 효과들과 함께, 디스턴스 필드를 다른 방식으로 해석해서 디자이너에게 더 많은 옵션들을 제공할 수 있습니다.


4.3 Sharp corners


그림 8: 64x64 로 인코딩된 코너.

왼쪽은 하나의 디스턴스 필드.

오른족은 두 개의 디스턴스 필드에 대한 AND.


앞의 다른 예제들에서 살펴 보았듯이, 단일 부호있는 디스턴스를 사용하여 엣지를 인코딩하는 것은 디스턴스 필드의 해상도가 감소할수록 코너를 "rounds off"합니다[Qin et al. 2006]( 역주 : 코너를 둥글둥글하게 만든다는 의미인듯...). 예를 들어, 그림 2a 의 문자 G 의 하드 코너는 그림 5, 6, 7 에서 보이는 것처럼 더욱 round off 됩니다.


그러나 텍셀과 겹치는 다른 엣지를 표현하기 위해 텍스쳐의 한 채널 이상을 사용함으로써 샤프 코너가 유지될 수 있습니다. 예를 들어, 두 개의 채널을 사용할 때, 두 엣지가 겹치는 것은 픽셀 쉐이더에서 논리 AND 연산을 수행함으로써 정확하게 표현될 수 있습니다. 그림 8 에서, 우리는 이러한 두 개의 엣지 디스턴스들을 단일 텍스쳐의 red 와 green 채널에 저장했으며, 잘 보존된 점모양의 코너가 결과로서 산출됩니다. 이것은 우리 텍스트 상에서 샤프 코너를 표현하기를 원한다면 "No Trespassing" 표지판 상에서도 같은 기법이 적용될 수 있습니다. 현재 상태로는, 우리는 이 텍스트의 둥글둥글한 스타일을 좋아하며, 이 데칼과 팀 포트리스 2 에서의 다른 데칼들을 위해서는 단일 디스턴스 필드를 사용했습니다.


5. Conclusion


이 챕터에서, 우리는 효율적인 벡터 텍스쳐 시스템을 설명했는데, 이는 Half-Life 2 시리즈, Counter-Strike: Source, Day of Defeat : Source 와 같은 게임을 개발하는 데 사용했던 Source 게임 엔진에 통합되었습니다. 이 벡터 텍스쳐 기법은 앞으로 나올 팀 포트리스 2 에도 사용되었는데, 전통적인 텍스쳐 매핑과 비교했을 때 중요한 성능 저하는 없습니다. 우리는 벡터로 인코딩된 이미지들을 우리의 1인칭 3D 뷰의 3D 지오메트리 상에 매핑되는 텍스쳐나 2D 스크린 오우버레이( overlay )들을 위해서 사용할 수 있습니다. 이 기능은 가시 품질을 매우 증진시키며 텍스쳐 메모리를 절약해 줍니다.



References


BLYTHE, D. 2006. The direct3d 10 system. In SIGGRAPH ’06: ACM SIGGRAPH 2006 Papers, ACM Press, New York, NY, USA, 724–734.


FRISKEN, S. F., PERRY, R. N., ROCKWOOD, A. P., AND JONES, T. R. 2000. Adaptively sampled distance fields: a general representation of shape for computer graphics. In SIGGRAPH’00: Proceedings of the 27th annual conference on Computer graphics and interactive techniques, ACM Press/Addison-Wesley Publishing Co., New York, NY, USA, 249–254.


LOOP, C., AND BLINN, J. 2005. Resolution independent curve rendering using programmable graphics hardware. In SIGf Figure 9: HLSL source code for outline, glow/dropshadow, and edge softness. GRAPH ’05: ACM SIGGRAPH 2005 Papers, ACM Press, New York, NY, USA, 1000–1009.


MITCHELL, J., MCTAGGART, G., AND GREEN, C. 2006. Shading in valve’s source engine. In SIGGRAPH ’06: ACM SIGGRAPH 2006 Courses, ACM Press, New York, NY, USA, 129–142.


QIN, Z., MCCOOL, M. D., AND KAPLAN, C. S. 2006. Real-time texture-mapped vector glyphs. In I3D ’06: Proceedings of the 2006 symposium on Interactive 3D graphics and games, ACM Press, New York, NY, USA, 125–132.


RAY, N., NEIGER, T., CAVIN, X., AND LEVY, B. 2005. Vector texture maps. In Tech Report.


SEN, P. 2004. Silhouette maps for improved texture magnification. In HWWS ’04: Proceedings of the ACM SIGGRAPH/EUROGRAPHICS conference on Graphics hardware, ACM Press, New York, NY, USA, 65–73.


TUMBLIN, J., AND CHOUDHURY, P. 2004. Bixels: Picture samples with sharp embedded boundaries. In Rendering Techniques, 255–264.

UE4 에서 Visual Studio 2015 Graphcis Diagnostics 이용하기


예전에 DXSDK 에는 PIX for Windows 라는 디버깅 유틸리티가 포함되어 있었습니다. 하지만 Windows 10 에서 DXSDK 가 Windows SDK 에 통합된 이후로는 이를 이용할 수 없게 되었습니다. 이제는 Visual Studio Graphics Diagnostics 를 사용하게 됩니다.


이 Graphics Diagnostics( 그래픽 진단 ) 기능은 Direct3D SDK Layer 를 통해 Direct3D debug device 생성합니다. 그리고 Graphics Debugging, Frame Analysis, GPU Usage 를 이용할 수 있게 해 줍니다.


Visual Studio 의 툴바의 빈칸에서 마우스 오른쪽을 클릭하면 아래 그림과 같이 칸텍스트 메뉴가 뜹니다( 당연히 Visual Studio 를 설치할 때 Windows 10 SDK 가 설치되어 있어야겠죠! ). 거기에서 "Graphics" 항목에 체크를 해 주시면 됩니다.



그러면 다음과 같은 도구가 뜹니다.



저 카메라 버튼을 누르게 되면 그래픽스 진단 모드가 실행됩니다.


사실 그냥 메인 메뉴에서 실행을 하는 것도 가능합니다. "Alt + F5" 라는 단축키도 지정되어 있군요.



자 이제 실행해 봅시다. 잘 되나요?



안타깝게도 "DX11 feature level 10.0 is required to run the engine" 이라는 에러가 발생하는군요. 필자의 경우에는 NVidia Geforce GTX 980 을 사용하고 있는데 한탄할 노릇입니다. 분명히 프로젝트 세팅에서도 DirectX 11( SM5 ) 을 사용하도록 설정했는데 말이죠...


문제의 메시지를 내 뱉는 코드의 위치는 다음과 같습니다( WindowsDynamicRHI.cpp 의 PlatformCreateDynamicRHI() ).



FD3D11DynamicRHIModule::IsSupported() 메서드 내부에서는 FD3D11DynamicRHIModule::FindAdapter() 라는 메서드를 호출합니다. 문제는 그래픽스 진단을 사용해 에디터를 띄울 때 이 메서드가 제대로 된 어댑터를 찾지 못한다는 것입니다.


그 이유는 FindAdapter() 내부에서 bSkipHmdGraphicsAdapter 가 true 값을 가지기 때문입니다. 결국 이것은 bSkipAdapter 값을 true 로 만들게 되죠.



그래픽스 진단 모드를 실행하게 되면 "Capture Adapter" 라는 이름을 가진 어댑터가 생성되는데, 이 때 bIsMicrosoft 가 true 가 됩니다. CVarExplicitAdapterValue 는 -1 이고, bUseHmdGraphicsAdapter 는 false 이므로 bSkipHmdGraphicsAdapter 가 true 입니다. 결국 이 어댑터를 무시하게 되는 것이죠.


이 문제를 해결하기 위해서 엔진 코드를 수정하는 방법이 있는데, 별로 좋은 방법은 아니라고 봅니다. 그래서 여기에서는 옵션을 사용해서 이를 우회하는 방법을 소개하고자 합니다.


필자는 현재 RenderingTest 라는 프로젝트를 만들었는데, 거기 있는 "Config/DefaultEngine.ini" 파일을 수정함으로써 원래 설정을 덮어 쓰고자 합니다. CVarExplicitAdapterValue 를 강제로 0 으로 만들어 준다면 bSkipHmdGraphicsAdapter 를 false 로 만들 수 있습니다.



이와 관련된 콘솔 변수는 다음과 같습니다.



그러므로 "DefaultEngien.ini""r.GraphicsAdapter" 변수를 지정해 주면 됩니다. 저는 한 개의 그래픽 카드만 가지고 있기 때문에 0 번을 지정했는데, 만약 통합된 내장 그래픽 카드가 있는 상태라면 다른 번호를 지정해야 할 수도 있습니다.



이제 즐겁게 디버깅을 하시면 됩니다.

원문 : https://www.cs.cornell.edu/~srm/publications/EGSR07-btdf.pdf

주의 : 번역이 개판이므로 이상하면 원문을 참조하십시오.

주의 : 허락받고 번역한 것이 아니므로 언제든 내려갈 수 있습니다.



Microfacet Models for Refraction through Rough Surfaces



Bruce Walter

Stephen R. Marschner

Hongsong Li

Kenneth E. Torrance


Program of Computer Graphics, Cornell University

Beijing Institute of Technology




Abstract


미세면 모델은 거친 서피스로부터 반사되는 빛을 모델링하는 데 있어서 매우 성공적이라고 증명되어 왔습니다. 우리는 이 논문에서 미세면 이론에 대해서 리뷰하고 식각 글라스( etched glass, 역주 : etching 은 화학약품을 사용해서 특정 부위만 부식시키는 것을 의미함 )와 같은 거친 서피스를 통과하는 투과( transmission, 전송, 전파 )을 시뮬레이션하기 위해서 확장될 수 있는 방법에 대해서 설명합니다. 우리는 몇 개의 실제 서피스들로부터 가져 온 측정 데이터와 최종 투과 모델을 비교하고 미세면 분산 함수와 그림자-마스킹( shadowing-masking ) 함수를 적절히 선택하는 방법에 대해 논의합니다. 매질을 투과하는 빛을 렌더링하는 것은 적어도 두 개의 인터페이스( interface )를 가로지르는 빛을 트래킹( tracking )할 것을 요구하기 때문에, 좋은 중요도 샘플링( importance sampling ) 방법이 필요합니다. 그러므로 우리는 미세면 모델들을 샘플링하는 함수 및 그것과 연관된 확률 밀도 함수( probability density function )들에 대한 효율적인 책략에 대해서도 설명할 것입니다.


Categories and Subject Descriptos (according to ACM CCS): I.3.7 [Three-Dimensional Graphics and Realism]: Keywords: Refraction, Microfacet BTDF, Cook-Torrance Model, Global Illumination, Monte Carlo Sampling




1. Introduction


반사가능한 매질로의 투과는 유리나 물같은 매우 투명한 매질( media )이나 피부나 대리석같은 반투명한 매질을 포함하는 다양한 재질의 외형을 결정하는 데 있어서 중요한 요소입니다. 매질의 경계가 부드럽다면, 굴절( refraction )에 대한 Snell 의 법칙을 사용해 투과를 쉽게 모델링하게 됩니다. 그러나 경계가 거칠다면, 컴퓨터 그래픽에서 사용할 만한 물리에 기반해 입증된 모델이 부족합니다.


이 논문에서, 우리는 먼저 미세면 이론에 대해서 리뷰한 후, 하프 벡터에 대한 일반화 기법을 사용해 재질 사이의 거친 경계에서 반사( reflection )와 굴절( refraction )을 모델링하는 방법에 대해서 보여 줍니다. 이는 완벽한 분석적( analytic ) BSDF 모델을 제공하는데, 이는 그림 1 에 나온 식각 글라스 글로브( etched glass globe )와 같은 거친 투과성 재질을 시뮬레이션하는데 사용될 수 있습니다. 우리의 목표 중 하나는 구현자들을 위한 완벽하고 자족적인( self-contained, 역주 : 내부적으로 모든 구현이 완비된 ) 참조를 제공하는데 있으며, 그래서 우리는 필요한 모든 공식들을 제공하고 분산, 그림자-마스킹, 중요도 샘플링을 선택하는 것과 같은 실용적 이슈들에 대해서 논의할 것입니다. 전송된 빛은 적어도 두 개의 인터페이스를 통과해야 하는데, 효율적인 렌더링을 위해서는 중요도 샘플링이 매우 중요합니다.


그림 1: 식각( etched ) 세계 지도를 사용한 유리 구.

우리 미세면 굴절 모델을 사용해서 시뮬레이션 됨

(텍스쳐 맵에 의해 러프니스가 곱해진 Beckmann 분산).


또한 우리는 4 개의 실세계 서피스들로부터 가져 온 실측 데이터와 우리의 미세면 모델을 비교함으로써 그것을 입증합니다. 거친 투과는 몇 가지 흥미로운 결과( 에를 들면, 그림 2 를 참조 )를 보여줍니다, such as the strong shift in the peak away from the smooth refraction direction towards grazing angles ( 거친 반사에서 off-specular peaks 와 유사합니다 ). 그리고 이 미세면 모델은 그러한 효과들을 성공적으로 예측할 수 있습니다. 우리는 우리가 GGX 라 부르는 새로운 미세면 분산 함수를 소개하기도 하는데, 그것은 표준 Beckmann 분산 함수보다는 우리의 일부 서피스와 더 가까운 결과를 제공합니다.


그림 2: ( 가루유리 같은) 거친 서피스에 대해서 0, 30, 60, 80 도의 입사각에 대해 측정된 투과 ( ft(i,o,n)|o·n| ).



다음으로 우리는 섹션 3 에서 관련 연구들과 일반화된 미세면 이론들에 대해서 논의할 것입니다. 미세면 ( 부드러운 ) 반사와 굴절에 대한 근사 식들을 섹션 4 에서 소개할 것입니다. 그리고 나서 섹션 5 에서 거친 서피스 반사 모델과 굴절 모델을 제공하고 미세면 분산 함수 및 관련 함수들에 대한 선택에 대해 논의할 것입니다. 섹션 6 에서는 우리의 측정 장치들에 대해서 설명하고 우리의 측정값을 미세면 모델의 값과 비교할 것입니다. 부록 A 에서는 임의의 미세면 분산 함수들에 대한 Smith 의 그림자-마스킹 근사식을 리뷰할 것입니다.


2. Previous Work


미세면 모델은 거친 서피스로부터의 빛 반사를 모델링하기 위해 Cook 과 Torrance [CT82] 에 의해 소개되었으며, 이는 광학 분야의 이전 작업들에 기반합니다[TS67]. 많은 변종들이 제안되었습니다( 예를 들어 [vSK98, KSK01, PK02] ). 미세면 모델들은 그래픽스에서 광범위하게 사용되며, 실제 서피스들을 모델링하는데 있어 효과적임이 증명되었습니다 [NDM05].


Ward [Lar92] 는 Cook-Torrance 모델을 단순화시킨 버전을 소개했는데, 비등방성 재질로부터의 반사를 위해 그것을 확장했습니다. 그는 그의 모델을 샘플링하기 위한 기법을 소개하기도 했는데, Beckmann 분선이 일반적이기는 하지만 정확한 샘플링 가중치를 살펴 보고 싶다면 [Wal05] 를 참조하시기 바랍니다. Lawrence 등은 [LRR04] 에서 fitted separable approximations 를 사용하는 대안적인 샘플링 기법을 제안했습니다.


Schlick [Sch94] 는 프레넬( Fresnel ) 공식에 대한 근사식을 포함하는 Cook-Torrance 모델보다 더 뾰족한 근사식을 생성하기 위해 합리적인 근사식을 사용했습니다.


Ashikhmin 과 Shirley [AS00] 는 정확한 중요도 샘플링을 포함하는 Phong 미세면 분산을 사용하는 비등방성 반사 모델을 소개했습니다. [APS00] 은 임의의 미세면 분산으로부터 에너지 보존 반사 모델을 생성했습니다. 하지만 이 공식은 closed form solutions( 역주 : 이미 확립된 해법을 이용해서 해석적으로 정확한 해를 구하는 방식. 구체적인 공식이나 함수를 제공할 수 있어야 만 함. closed form solution = analytic solution ) 없이 수학적으로 평가한 적분을 포함하고 있습니다.


우리의 연구것과 가장 유사한 것은 Stam [Sta01] 입니다. 그는 굴절에 대한 미세면 모델을 피부의 반사도를 위해 레이어화 된 모델의 일부로서 유도했으며, 굴절을 위해 함수[야코비] 행렬식( Jacobian )을 유도했습니다. 그러나 이전의 작업과는 다르게 Stam 은 중요도 샘플링을 제공하지 않았고 실증 데이터에 대한 검증을 수행하지 않았습니다. 또한 그림자-마스크 항을 빼먹었으며 비표준 Beckmann 분산의 변종을 사용했습니다.


그림자-마스킹 항을 위한 많은 근사식들이 제시되었습니다( 예를 들어 [TS67, San69, APS00] ). 우리는 Smith [Smi67] 에서 가져온 근사식을 사용하는데, 그것은 원래 가우시안 서피스를 위해서 유도되었으며, 나중에 임의의 미세면 분산을 위해서 [Bro80, BBS02] 에서 일반화되었습니다.


반사 모델에 기반한 파동 광학( wave optics )이 제안되었는데( 예를 들어 [HTSG91]), 그것은 미세면 모델보다는 더 광범위한 범위의 서피스들을 시뮬레이션할 수 있지만, 계산비용이 너무 비싸며 괜찮은 중요도 샘플링 함수를 가지고 있지 않습니다.


다양한 거친 서피스 모델들을 위한 투과에 대한 수치 시뮬레이션( numerical simulations )들도 수행되었고 측정된 결과들과 비교되었습니다 [RE75, Ger03, SN91, NSSD90].


표기. 이 연구에서 우리는 단위 벡터와 방향을 표현하기 위해서 굵은 소문자( 예를 들어 i or v ) 를 사용합니다. 차이를 명확하게 하기 위해 정규화되지 않은 벡터들은 화살표와 함께 작성될 것입니다( 예를 들어  ). 우리는 구형 극 좌표계를 사용하는 방향을 기술할 것입니다( 예를 들어 v = (θvv) ). 극 각도 θ 는 항상 ( 역주 : 뷰나 빛의 ) 방향과 미세면 노멀 n( 이는 우리가 논의하는 등방성의 경우에 임의로 선택될 수 있음 ) 과의 각도입니다. 반면에 방위각( azimuthal angle ) φ 는 n 과 수직하는 canonical direction 과의 각도입니다. Although we describe the BSDF in terms of radiance( i.e. light flow ), the equations are identical when handling its dual, importance( i.e. tracing from cameras [Vea96] ).


그림 3: 심볼 테이블.


3. Microfacet Theory


BSDF( Bidireictional Scattering Distribution Function ) 는 서피스에서 빛이 산란하는 방식을 기술합니다. 그것은 i 방향으로 입사한 복사조도( irradiance ) 당 o 방향으로 발생한 산란된 복사휘도( radiance )의 비율로 정의됩니다. 우리는 그것을 함수 fs(i,o,n) 으로 표기하며 로컬 서피스 노멀 n 상에서 그것의 의존성이 두드러집니다. 만약 그것이 반사나 굴절로만 제한된다면, 보통 BRDF 나 BTDF 라 불리는데, 우리 BSDF 는 BRDF fr 항과 BTDF ft 항의 합입니다. Since we want to include both reflection and transmission, we will care that our derivations and equations can correctly handle directions on either side of the surface.


미세면 모델에서 세부적인 마이크로서피스( microsurface, 미세 서피스 ) 는 수정된 산란 함수( BSDF )를 사용해 단순화된 매크로서피스( mcrosurface, 거대 서피스 )로 대체됩니다 ( 그림 4 참조 ). 그 함수는 통합된 마이크로서피스의 지향성 산란( directional scattering )과 일치합니다( 예를 둘 다 멀리서 보면 같은 결과로 보입니다 ). 이는 마이크로서피스의 세부사항이 직접적으로 관찰하기에는 너무 작아서 먼 곳에서 보는 지향성 산란 패턴만이 일치한다고 가정합니다. 일반적으로 기하학적 광학( geometric optics )이라 가정되며, 문제를 단순하게 하기 위해서 단일 산란( single scattering )만이 모델링됩니다. 표면을 두 번( 이상 ) 때리는 파동 효과와 빛은 무시되며, 개별적으로 다뤄져야만 합니다.


그림 4: 마이크로서피스 대 매크로서피스.


특별한 마이크로서피스 설정을 가지고 연구를 하기보다는, 미세면( microfacet ) 분산 함수 D 와 그림자-마스킹 함수 G 에 대한 통계적 측정값과 미세 서피스 BSDF  를 사용해 마이크로서피스를 적절히 기술할 수 있다고 가정합니다.


3.1. Microfacet Distribution Function, D


미세면 노멀 분산 D(m)은 마이크로서피스 상의 서피스 노멀 m 들에 대한 통계적인 분산을 기술합니다. m 을 중심으로 한 극소 입체각( infinitesimal solid angle ) dωm 과 극소 매크로서피스 면적 dA 가 주어지면, D(m)dωmdA 는 지정된 입체각의 내부에 존재하는 노멀을 가진 마이크로서피스의 전체 면적을 의미합니다. 그러므로 D 는 1/스테라디안 단위의 밀도 함수입니다. 이치에 맞는 미세면 분산은 적어도 다음과 같은 속성들을 가져야 합니다:


    • 미세면 분산은 양수 값이어야 합니다:


    • 전체 마이크로서피스 면적은 적어도 그것과 연관된 매크로 서피스의 면적보다는 커야 합니다:


    • 마이크로서피스의 ( 부호있는 ) 사영된 면적은 모든 방향 v 에 대한 매크로서피스의 사영된 면적과 같아야만 합니다:

그리고 v = n 인 특별한 경우에 대해서는



각 미세면 분산들을 위한 공식들에 대해서는 섹션 5.2 에서 논의합니다.


3.2. Shadowing-Masking Function, G


그림 5: 그림자-마스킹 기하학: 같은 마이크로서피스 노멀 m 을 사용하는 세 지점.

두 개는 io 방향에서 보이며, 한개는 ( i 방향에서 ) 차폐됨.

관례상, 우리는 항상 서피스로부터 멀리 떨어진 것을 가리키는 방향들을 사용함

( 역주 : 방향이 표면에 들어 가는 방향이 아니라 표면으로 부터 나오는 방향임을 의미 ).


양방향 그림자-마스킹 함수 G(i,o,m) 은 노멀 m 을 가지는 마이크로서피스가 i 방향과 o 방향에서 얼마만큼 많이 보이는지를 기술합니다( 그림 5 참조 ). 일반적으로 그림자-마스킹 함수는 지표각이나 매우 거친 서피스를 제외하고는 BSDF 의 모양을 결정하는 데 있어서 적은 영향만을 끼치지만, 에너지 보존 법칙을 지킬 필요가 있습니다. 이치에 맞는 그림자-마스킹 함수를 만들려면 다음과 같은 속성들을 가져야 합니다:


    • 그림자-마스킹은 0 에서 1 까지의 값입니다:


    • 두 visibility direction 에 대해서 대칭적입니다:


    • 마이크로서피스의 뒤쪽 면은 결코 매크로서피스의 앞쪽에 있는 방향으로부터 가시적이지 않으며, 다른 경우에도 마찬가지입니다( sidedness agreement ):


그림자-마스킹 함수는 마이크로서피스의 세부사항에 의존하며, 정확한 공식을 만드는 것이 거의 불가능합니다. 더 일반적으로는 다양한 통계적 모델과 단순화된 가설을 사용해서 근사식들이 유도됩니다. 더 많은 논의를 원한다면 섹션 5 와 부록 A 를 참조하세요.


3.3 Macrosurface BSDF Integral


매크로서피스 BSDF 는 마이크로서피스에 대한 통합된 방향성 ( 단일 ) 산란 행동에 맞추기 위해서 설계됩니다. 우리는 마이크로서피스에서 볼 수 있을 만한 모든 부분들에 대한 기여도를 적분( 혹은 합산 )함으로써 이를 계산할 수 있는데, 각각은 부분들은 마이크로서피스 BSDF 인  과 연관된 빛을 스캐터링합니다. D 와 G 의 곱은 마이크로 노멀이 m 인 마이크로서피스에 상응하는 가시 면적을 제공합니다. 또한 우리는 마이크로서피스 상의 첫 번째로 전송된 입사 복사조도에 대해 교정 팩터를 적용한 후에 산란된 복사휘도를 다시 매크로서피스로 재전송할 필요가 있습니다. 왜냐하면 복사조도와 복사후도는 서피스가 사영된 면적에 대해서 상대적으로 계측되기 때문입니다. 매크로서피스 BSDF 에 대한 적분 결과는 다음과 같습니다:



이 적분을 적용하기 위해, 우리는 D, G,  을 위한 공식을 필요로 합니다. 마이크로서피스는 지역적으로 부드럽다고 가정하면,   은 이상적인 ( 거울면 ) 반사와 이상적인 ( Snell's law ) 굴절을 위한 항들의 합이며, Fresnel 항 F 에 의해서 기술되는 상대적인 세기를 가집니다.  을 위한 적절한 공식은 다음 섹션에서 유도될 것입니다.


4. Microsurface Specular BSDFs


모든 BSDF 는 마이크로서피스 BSDF 를 위해서 사용될 수 있습니다. 하지만 대부분의 미세면 모델들은 이상적인 거울면 반사를 가정하는데, 여기에서 마이크로서피스는 작고 평평한 거울들( 즉 미세면 )의 집합처럼 동작합니다. 이 연구에서 우리는 이상적인 반사와 이상적인 굴절을 모두 포함시키고 있습니다.


일반적인 스펙큘러 BSDF 는 i 방향으로부터의 입사 에너지인 ρ 를 단일 스펙큘러 방향 s 로 산란시킵니다( 여기에서 ρ 와 si 와 로컬 서피스 노멀에 대한 함수입니다. 역주: 원문 내용이 이상함. s 는 방향이라고 했는데 ㅡㅡ;; ). 우리는 다음과 같은 스펙큘러 BSDF 공식을 작성할 수 있습니다:



여기에서 δωo(s,o) 는 디랙 델타 함수( Dirac delta function )이며, 그것의 값은 s = o 일 때 무한대이고 그렇지 않을 때 0 입니다. 수학적으로 볼 때 델타 함수들은 함수가 아니라 꽤 일반화된 함수입니다. 그것들은 항상 관련 척도를 가지며( e.g., δωoo 에 대한 입체각 척도입니다 ), 이 척도에 대한 관점에서 적분에 의해 정의됩니다: 주어진 어떤 함수 g() 에 대해,



식 8 에 있는 그런 BSDF 를 사용하기 위해서, 우리는 그것을 마이크로서피스 노멀들과 그것들과 관련된 입체각 척도의 항으로 표현할 필요가 있습니다. 어떤 입사방향과 반사방향이 주어졌다고 가정해 봅시다. 거기에는 에너지를 i 에서 o 로 산란시키는 마이크로서피스 노멀이 적어도 하나는 존재할 것이고, 우리는 그 노멀을 하프 디렉션이라 불리는 h(i,o)로 계산할 것입니다. 그리고 나서 우리는 BSDF 를 hm 사이의 델타 함수의 항으로 재작성할 수 있습니다. 그러나 델타 함수는 적분의 관점에서 정의되기 때문에, 그것의 관련 척도를 변경하는 것은 적분 값을 보전하기 위한 적절한 교정 팩터를 요구합니다. Change of values theorem 을 사용하면, 식 9 는 다음과 동일해 집니다.



여기에서 는 ( 입체각 측정값을 사용해 ) ho 사이의 변환을 위한 야코비안 행렬( Jacobian matrix ) 를 결정하는 절대값입니다( 역주 : 6 자 뒤집어 놓은 것처럼 생긴 ∂ 기호는 편미분 기호입니다 ). 단순함을 위해 보통 야코비안이라 부릅니다.


이 야코비안은 두 공간에서의 작은 변화량( perturbation )들 사이의 크기 관계( magnitude relationship )를 기술합니다. 우리는 o 에 대한 입체각 내의 작은 변화량을 생성하고 h 에서 유도된 입체각 변화량을 찾아냄으로써 그것을 계산할 수 있습니다. o 에서의 변화량을 dωo 라고 표기할 것이고 h 에서의 변화량을 dωh 라고 표기할 것입니다. 야코비안은 다음과 같이 정의됩니다: 극소( infinitesimal ) 변화량에 대한 극한에서 



단위 구 상의 면적과 직접적으로 연관된 입체각과 그런 극소 면적들은 근사적으로는 평평하다고 취급될 수 있습니다. 이는 우리가 그림 6 과 7 에서 반사 및 굴절에 대한 야코비안들을 기하학적으로 계산할 수 있게 해 줍니다. 우리는 o 주변의 극소 입체각 변화량 dωo 를 생성하는데, 그것은 o 를 기반으로 하는 단위 구 상의 극소 면적과 동일합니다. 그리고 나서 이 면적으로 h 를 기반으로 하는 단위 구 상에 사영하는데, 그것은 h 에 대한 유도된 극소 입체각 변화량 dωh 와 동일합니다. 그리고 이 극소 입체각들 사이의 비율은 야코비안과 같습니다. 이 야코비안들은 [Sta01] 에서처럼 ho 와 관련된 공식들로부터 대수적으로 계산될 수 있습니다.


그림 6:  하프 벡터  와 정규화된 하프 디렉션  을 사용하는 이상적인 반사를 위한 기하. 야코비안을 계산하기 위해서, 우리는 정규화된 하프 벡터에서 극소 입체각 변화량 dωh 를 계산하는데, 이는 o 에서의 극소 입체각 변화량 dωo 에 의해서 유도됩니다. 입체각은 그것과 연관된 단위 구들 상의 면적에 직접적으로 비례합니다. Only the 2D incidence plane slice through the full 3D space is shown.



그림 7: 하프 벡터  와 정규화된 하프 디렉션  를 사용하는 이상적인 굴절을 위한 기하. o 에서의 극소 입체각 변화량 dωo 를 취하고 에서의 변화량에 사영하고 나서,  를 위한 단위 구 상에 사영함으로써 야코비안을 계산합니다. Only the 2D incidence plane slice through the full 3D space is shown.


4.1. , Ideal Reflection


이상적인 반사를 위해, 우리는 하프 디렉션을  로 정규화되지 않은 하프 벡터를  로 표기합니다( 우리는 투과의

경우를 위해서는 를 사용할 것입니다 ). 우리는 을 위한 표준 공식을 사용하는데, ( i·n )의 부호를 곱해 준다는 것만 다릅니다( 역주 : 결국 항상 양수값이 나온다는 의미 ). 그래서 우리의 공식은 서피스의 양 측면( 즉 앞이나 뒤 )에 대해서 동작하게 될 것입니다. 반사 하프 디렉션은 io 의 중간에 위치하며, 그것과 그것의 야코비안은 다음과 같습니다:




야코비안에 대한 기하학적 유도는 그림 6 에 설명되어 있습니다. 우리는  이고  이라는 것을 이용하기도 했습니다. i = -o 일 때는 하프 디렉션이 정의되지 않는데요, 이것은 결코 유효한 반사 구성이 될 수 없습니다. 반사의 경우 우리는 ρ 를 프레넬 팩터 F 와 동일하게 설정합니다( 5.1 섹션 참조 ). 식 11 을 사용하면, 반사 마이크로서피스 BRDF 는 다음과 같습니다: 서피스의 양 측면으로부터의 반사를 위해 



야코비안 항 때문에  은 이 감소할 수록 증가하며, 이것이 미세면 모델들에서 예측되고 실제 서피스들에서 관찰되는 off-specular 반사 피크의 중요 원인입니다.


4.2. , Ideal Refraction


투과의 경우 우리는 서피스의 양 측면에서의 굴절률을 필요로 합니다. 서피스의 입사 면과 투과되는 면의 굴절률들을 각각  ( 역주: eta 라 읽음 )와  라고 표기하도록 하겠습니다. 이상적인 굴절은 입사 방향 와 관련한 굴절 방향 o 를 찾기 위해서 Snell 의 법칙을 따르게 됩니다. Snell 의 법칙은 하프 디렉션 를 사용해서 다음과 같이 표현될 수 있습니다:



m 에 수직인 io 성분들의 크기는 그것들과 m 사이의 각도에 대한 sin 값과 같습니다. Snell 의 법칙에 의한 굴절 방향의 경우, 이 성분들은  에서 정확히 취소되며, 결과 방향은 m 과 colinear( 역주 : 같은 라인상에 존재한다는 의미 ) 합니다. 만약 우리가 io 가 서피스의 같은 측면에 존재하는 경우( 역주 : 굴절이 일어나지 않고 반사만 일어나는 경우 )를 배제하면, io 가 서피스 노멀로 m 을 사용할 때의 굴절을 위해서 Snell 의 법칙을 따르는 경우에만 이 될 것입니다. 에는 음수가 존재하는데, 이는 우리가 서피스 노멀이 낮은 굴절률을 가진 매질쪽( 예를 들어 공기 )을 가리킨다는 관례를 따르고 있기 때문입니다. 우리는 서피스의 두 측면이 서로 다른 굴절률을 가진다고 가정합니다; 그렇지 않으면  가 불분명해질 것입니다. 이것과 관련한 야코비안은 다음과 같습니다( 그림 7 참조 ):



우리는 인터페이스에서 흡수되는 빛은 없다고 가정하기 때문에 굴절을 위한 ρ 는 1 에서 프레넬 팩터 F 를 뺀 것입니다. 식 11 을 사용하여, 우리는 마이크로서피스 굴절 BSDF 를 다음과 같이 작성할 수 있습니다:



이 BTDF 는 reciprocity 를 따르지 않음에 주의하십시오. 대신  입니다. 이는 굴절하는 인터페이스의 잘 알려진 속성입니다. 그리고 만약 원한다면 우리는 radiance( 종종 basic radiance 라 불림 ) 가 아니라 을 트래킹함으로써 reciprocity 를 복구할 수 있습니다. 반사에서처럼, BTDF 는 지표각으로 갈수록 증가하는데, 이는 야코비안 항 때문입니다. 이 항은 굴절 로브에서 반사와 유사한 off-specular 피크를 발생시킵니다.


5. BSDF for Rough Surfaces


식 8 을 사용해 마이크로서피스 BSDF 들을 반사와 굴절을 위해서 사용함으로써, 우리는 이제 매크로서피스 반사와 굴절을 위한 BSDF fs 를 작성할 수 있습니다. 이는 BRDF 항과 BTDF 항의 합입니다:



반사항은 다음과 같습니다:



이는 우리가 분모에서 π 대신에 4 라는 팩터를 사용했다는 점만 제외하면 Cook-Torrance BSDF 와 정확히 같습니다. 그러나 원래의 논문은 D 를 위한 다른 정규화를 사용했습니다. 좀 더 최근의 다른 논문들은 4 를 사용하는 우리의 논문에 동의합니다( 예를 들어 [Sta01] ).


굴절항은 다음과 같습니다:



We don't get as much nice cancellation of terms in the refraction component, but it is still easily implemented and evaluated. 이는 거친 유전체( dielectric ) 서피스를 통과하는 반사 및 굴절에 대한 미세면 모델에 대한 기본 BSDF 공식을 완성시킵니다.


5.1. Choosing F, D, and G


식 20 과 21 을 사용하는 것은 F, D, G 항들에 대한 적절한 선택들을 요구합니다. 프레넬 항은 가장 이해하기 쉽습니다. 그리고 정확한 공식을 문헌에서 찾아 볼 수 있습니다. 일반적으로 프레넬 항은 수직 입사시에 작으며( 예를 들어  인 유리를 위해서는 0.04 ), 지표각이나 완전 내부 반사에서는 unity 로 증가합니다. unpolarized( 편극 안 된, 여러 유형으로 진동하는 ) light 를 가진 유전체를 위한 정확하고 편리한 공식은 다음과 같습니다 [CT82]:



만약 g 가 허수( imaginary )라면, 이는 전체 내부 반사를 가리키며 이 경우 F = 1 입니다. F 를 위한 더 값싼 근사식들이 종종 사용되기도 합니다 [CT82, Sch94].


여러 가지 미세면 분산 함수 D 들이 제안되어 왔습니다. 이 논문에서, 우리는 세 가지 유형에 대해서 다룹니다: Beckmann, Phong, GGX. Beckmann 분산은 마이크로서피스에 대한 Gaussian roughness assumption 으로부터 만들어졌으며, 광학 문헌들에서 광범위하게 사용됩니다. Phong 분산은 그래픽스 문헌에서 개발된 순수하게 실증적인 것입니다; 그러나 width 파라미터들을 적절히 선택하면, 그것은 Beckmann 분산과 거의 비슷합니다. GGX 분산은 새로운 것이며, 우리는 투과를 위해 측정된 데이터들과 그것을 더 잘 일치시킬 수 있게 하기 위해서 개발했습니다. 세 분산 유형들을 위한 공식들과 관련 함수들은 이 섹션의 끝 부분에 나옵니다.


그림자-마스킹( shadowing-masking ) 항 G 는 분산 함수 D 와 마이크로서피스의 세부사항에 의존합니다. 그래서 정확한 솔루션을 찾는다는 것이 거의 불가능합니다. Cook 과 Torrance 는 모든 분산 D 를 위해 에너지 보존을 보장하는 평행 그루브( parallel grooves ) 에 대한 1D 모델에 기반하는 G 를 사용했습니다. 그러나 우리는 그것을 사용하는 것을 추천하지 않습니다. 왜냐하면 그것은 1차 미분 불연속성을 가지고 있으며 다른 특징들도 실제 서피스에서는 보이지 않는 것들이기 때문입니다. 대신에, 우리는 Smith 그림자-마스킹 근사식 [Smi67] 을 사용할 것입니다. Smith G 는 원래 Gaussian rough surface 로부터 유도되었지만, 임의의 분산 함수들 [Bro80, BBS02] 를 가진 서피스들을 다루기 위해서 확장되어 왔습니다. 비록 몇몇 사례들에서( 예를 들어 Phong ) 결과 적분들이 단순한 closed form solution( 역주 : analytic solution ) 을 가지고 있지 않긴 하지만 말입니다.


Smith G 는 두 개의 한 방향의( monodirectional ) 그림자 항 G1 들에 대한 개별 곱으로서 양방향 그림자-마스킹을 근사계산합니다:



여기에서 G1 은 [Smi67, Bro80, BBS02] 와 부록 A 에서 기술된 것처럼 미세면 분산 D 로부터 유도됩니다. Smith 는 실제로 두 개의 다른 그림자 함수들입니다: 하나는 마이크로서피스 노멀 m 이 알려졌을 때 하나, 모든 마이크로서피스 노말들에 대한 평균냈을 때 다른 하나. 비록 후자가 문헌들( 예를 들어 [HTSG91] )에서 더 자주 사용되기는 하지만, 마이크로서피스 노멀이 알려진 미세면 모델에서는 전자가 더 적합하며 우리는 이 논문에서 그것을 사용합니다.


5.2. Specific Distributions and Related Functions


그림 8: 왼쪽: Beckmann (red), Phong (blue), GGX(green) 분산 함수 D(m) 들. 각각은 αb = 0.2, αp = 48, αg = 0.2 를 사용합니다. Beckmann 과 Phong 은 GGX 가 더 좁은 피크와 더 강한 테일을 가지는 것에 비하면 거의 비슷합니다. 오른쪽: Beckmann, Phong, GGX 를 위한 Smith 그림자-마스킹 항 G1(v,n) 들. G1 은 지표각에서를 제외하고는 거의 1 입니다. 그리고 GGX 는 더 강한 테일을 가지고 있기 때문에 좀 더 많은 그림자를 가지게 됩니다.


아래에서 우리는 Beckmann, Phong, GGX 분산 D 를 위한 식을 제공합니다( 그림 8 참조 ). 그리고 그것들과 관련한 Smith 그림자 함수 G1 을 제공합니다. 또한 [0, 1) 범위에 있는 두개의 유니폼 랜덤 변수들인 ξ1 ( 역주 ksi 라 읽음. 크시 )과 ξ2 로부터 마이크로서피스 노멀들을 생성하기 위한 샘플링 공식들을 제공합니다. 주어진 샘플링 공식을 사용하여 어떤 m 을 생성하는 것에 대한 확률( probability )는 다음과 같습니다:



θmmn 사이의 각도이며, θvv n 사이의 각도이고, χ+(a) ( 역주: chi 라 읽음. 키 )는 양의 특성( positive characteristic ) 함수( a > 0 이면 1 이고 a <= 0 이면 0 )입니다. 이것들은 모두 하이트필드( heightfield ) 분산들입니다( 즉 m·n <= 0 이면 D(m) = 0 ). 그리고 그것들에 대한 비등방성 변종들이 존재하지만 여기에서는 논의하지 않을 것입니다.


width 파라미터 αb 를 사용하는 Beckmann Distribution:




G1 공식에서 첫 번째 팩터는 sideness agreement 를 포함합니다( 즉 v 는 반드시 매크로서피스나 마이크로서피스에 대해 같은 측면에 존재해야만 합니다 ). 그것은 에러 함수  를 포함하고 있기 때문에, 이 공식은 평가하기에 너무 비쌀 수 있습니다. Shclick [Sch94] 은 더 싼 비례 근사식( rational approximation, 유리 근사식 )을 사용할 것을 제안했지만, 그것은 서로 다른 그림자-마스킹 공식에 기반했습니다. 대신에, 우리는 Smith G1 공식에 대한 다음의 비례 근사식을 제안하는데 0.35% 보다는 작은 상대적 에러를 사용합니다.



샘플링 에 대한 공식은 다음과 같습니다:




width 파라미터 αg 를 사용하는 GGX Distribution:




GGX 분산은 Beckmann 분산과 Phong 분산보다는 더 강한 테일( tail )들을 가집니다. 즉 더 많은 그림자를 가지는 경향이 있습니다. 샘플링 을 위한 공식은 다음과 같습니다:




5.3. Sampling and Weights


BSDF 를 샘플링하기 위해서, 우리는 방향 i 를 가지고 있으며 산란된 방향 o 를 fs(i,o,n)|o·n| 과 거의 일치하는 패턴으로 생성하기를 원한다고 가정합니다. 일반적으로 미세면 BSDF 는 정확하게 샘플링될 수 없습니다. 우리의 접근법은 먼저 마이크로서피스 노멀 m 을 샘플링하고 나서 그것을 사용해서 산란된 방향 o 를 생성할 것입니다. 관련 샘플들에 대한 가중치를 계산하기 위해, 우리는 샘플 방향들에 대한 확률 밀도 po 를 계산할 필요가 있습니다. 결과 가중치는 다음과 같을 것입니다:



여기에서 우리는 결과 가중치에서의 변화를 최소화하기 위한 샘플링을 선택하기 원합니다.


만약 산란된 방향 o 를 생성하기 위해서 확률 pm 으로 미세면 노멀 m 을 선택하고 하프-디렉션 공식( 즉 식 13 이나 16 )을 역으로 계산한다면( invert ), 최종 확률은 하프-디렉션 트랜스폼( transform )의 야코비안을 포함하게 될 것입니다( 예를 들어 [Wal05] 를 참조 ):



5.2 섹션으로부터의 샘플링 공식들을 사용하면, 우리는 과 관련된 샘플링된 미세면 노멀들 m 을 생성할 수 있습니다. 그리고 나서 우리는 프레넬 항 F(i,m) 을 평가하고, 반사인지 굴절인지를 선택하기 위해서 그것을 사용할 수 있습니다. 즉 프레넬 항을 확률로 끌고 들어 오는 것입니다. 반사의 경우, 산란 방향 or 은 다음과 같습니다:




그리고 투과의 경우, 산란된 방향 ot 는 다음과 같습니다:



그리고 다른 경우에는 산란된 방향에 대한 결과 가중치가 다음과 같습니다:



수직 입사시 ( 즉  ), 이는 거의 완벽한 샘플링이 됩니다. 지표각에서, 그것은 여전히 좋은 샘플링이지만 D 와 G 를 어떤 것을 선택했느냐와 파라미터의 값에 따라 수백배까지 높은 샘플 가중치가 생성될 수도 있습니다. 그러한 높은 가중치들이 나올거 같지 않지만( fs 가 매우 작은 곳의 지표각에서의 retroreflection 을 위해서는 최악임 ), 그것들은 그러한 높은 가중치가 결코 발생하지 말아야 한다는 가정을 가진 기법들에서 문제가 됩니다( 예를 들어 대부분의 파티클 트레이싱 기법들 ). 우리는 샘플링 분산을 약간 수정함으로써 최대 가중치를 훌륭하게 줄일 수 있습니다. 예를 들어 Beckmann 분산을 사용할 때, 우리는  에 의해 주어진 약간 넓어진 분산을 대신 샘플링할 수 있습니다. 이는 최대 샘플링 가중치를 대충 4 배 정도 확 줄여줍니다.


6. Measurements


그림 9: 측정 설정: 우리는 우리 샘플들의 뒤쪽에 유리 반구를 둘렀습니다. 

이는 지표각에서도 투과를 관찰할 수 있게 해 줍니다.


( 역주 : 이 섹션은 측정 방법론 및 대상에 대한 내용이 주를 이루고 있고 모르는 개념이 너무 많이 나와서, 귀찮으면 그냥 원문을 그대로 썼습니다 )


우리의 산란 모델을 검증하기 위해서, 우리는 다양한 종류의 거친 유리 서피스들을 통과하는 투과를 측정했습니다. 이 측정을 거친 서피스를 가진 유리 그릇에 조명을 비치고 산란된 빛을 측정하는 단순한 방법을 사용할 수는 없습니다. 왜냐하면 빛은 유리 내부에서 직접적으로 관찰되지 않으며, 내부 반사가 상대적으로 지표각에 가까운 방향으로 산란되는 빛을 방해하기 때문입니다. 그래서 측정할 수 있는 곳으로 빛이 도달하지 않습니다. 동시에 내부적으로 반사되는 빛의 대다수는 내부로부터 거친 스피스를 향한 조명으로 다시 작용할 것이며, 이는 경로에서 벗어난 허용할 수 없는 다량의 빛을 생성하게 됩니다.


전송된 빛을 직접적으로 관찰하기 위해서, 우리는 plano-convex lens( 평면 볼록 렌즈 )를 덧붙임으로써 두 번째 인터페이스를 제거했습니다. 이 렌즈는 샘플의 뒤쪽을 향하는 반구에 가깝습니다( 그림 9 ). 이러한 구성은 [NN04] 의 연구에서 영감을 받았습니다. 샘플은 거친 서피스로부터 빛을 받으며, 구형 서피스를 통해 여러 각도로부터 보입니다. 이 때 장치의 회전 중심은 구형 서피스의 중심에 정렬되기 때문에 뷰 방향은 항상 서피스에 대해 수직입니다. 이러한 방식으로, 산란된 빛은 프레넬 반사 때문에 최소한의 손실로 서피스를 떠나게 됩니다. 또한, 상대적으로 적은 빛만이 샘플의 중심 근처의 영역으로 재반사됩니다. 왜냐하면 반구를 떠나는 경로의 반사는 거의 서피스에 수직이기 때문입니다. 이는 평평한 샘플을 사용했을 때와 비교하면 빛이 경로를 벗어나는 문제를 줄여 줍니다.


우리 설정에서, 100 mm 의 정사각형 샘플이 동일한 굴절률을 가진 접착제를 사용해서 75 mm 의 직경과 75 mm 의 초점 거리를 가진 거의 반구모양인 평면 볼록 렌즈에 부착됩니다. 6 mm 의 두께를 가진 샘플의 경우, 렌즈의 구형 서피스의 중심은 거친 서피스 상에 존재합니다. 하지만 우리 샘플들은 다양한 두께로 구성되어 있기 때문에, 이 기법은 반드시 서피스와 중심 간의 몇 mm 정도의 거리를 감수해야만 합니다.


이 샘플은 6 mm 의 원형 광섬유로부터 610 mm 의 거리에서 조명을 받게 됩니다( 조명 입체각: 0.000076 sr ). 그 광원은 DC 정규 섬유 조명이며, 전체 샘플 서피스 상에 안정적이고 떨리지 않는 조명을 제공합니다. 전송된 빛은 냉각한 CCD 카메라에 의해 감지되는데, 이 카메라는 반구형 면으로부터의 샘플을 보게 됩니다. 이 카메라는 885 mm 의 거리에 있는 f/5.6 의 35 mm 촬영 렌즈를 사용합니다( 수신 입체각: 0.000039 sr ). 측정값은 카메라 이비지의 고정된 사각 영역 안의 픽셀 값들을 평균냄으로써 구해지는데, 이 영역은 거의 3mm x 10 mm 까지의 구형 서피스 상의 면적과 관련이 있습니다.


측정된 면적은 이미지 내의 고정된 면적으로 정의되기 때문에, 측정값은 카메라에 의해 관찰된 복사휘도( radiance )에 대한 비율입니다. Since radiance is preserved ( up to a constant factor ) under refraction, this arrangement produces a signal proportional to the BTDF times the cosine of the incident angle. 이 속성을 가지기 위에서는 앞에서 조명을 비추고 뒤에서 보는 것이 중요합니다; if the sample was flood-illuminated from the hemispherical side, the lens would focus the light into a nonuniform distribution of irradiance that would make the system sensitive to exact alignment between the sphere center and the surface.


우리는 거친 서피스를 가진 네 개의 유리 샘플들을 서로 다른 절차를 통해 측정했습니다. One was commercially produced ground glass created by sandblasting soda-lime glass with 120 abrasive ( ground, 1/16 inch thickness ). One sample was prepared in our lab by acid-etching one side of a plate of soda-lime glass ( etched, 3/16 inch thickness ). The last two are less well characterized: commercially available frosted flass ( frosted, 1/8 inch thickness ) and commercially available antiglare glass for picture framing ( antiglare, 1/16 inch thickness ). All samples had flat polished surfaces on the reverse side except the antiglare glass, which was rough on both sides; we assume that the adhesive fills in the surface so that the extra rough interface is not relevent( and in fact, there is no visible evidence of an air layer ).


측정 결과는 모두 산란된 로브의 피크가 기대했던 굴절 방향과 벗어나는 것을 보여 주었습니다. antiglare glass 에서처럼 러프니스가 낮아지면, 그 피크는 이상적인 반사 각에 가깝지만, 더 거친 샘플들의 경우에는 지표각으로 갈수록 많이 벗어나게 됩니다.


이러한 이유로 이 거친 서피스 BTDF 들의 많은 특징들은 평평한 그릇에서 직접적으로 관찰하기 어렵습니다. 다음에 보여 주듯이, 우리의 미세면 모델들은 이런 행동들을 잘 예측합니다.


6.1. Sample Results


그림 10: 가루( ground ) 유리 샘플. 

위쪽은 BTDF fit 이며 아래쪽은 실증적인 미세면 분산 D 에 대한 fit 임.

Red 라인은 Beckmann 이고 green 라인은 GGX 임.


그림 11: 냉각( frosted ) 유리 샘플. 

위쪽은 BTDF fit 이며 아래쪽은 실증적인 미세면 분산 D 에 대한 fit 임.

Red 라인은 Beckmann fit 이며 green 라인은 GGX fit 임.



네 가지 샘플들 각각에 대해, 우리는 Beckmann 분산과 GGX 분산을 사용해 미세면 BTDF 와 측정된 결과를 맞춰 보았습니다( 그림 12 ). 모든 샘플들에 대해 우리는 굴절률이 1.51 이라 가정했습니다. 이는 우리에게 맞춰야 하는( to fit ) 두 개의 자유 파라미터를 제공합니다: 분산 너비 파라미터( αb 와 αg )와 우리 측정값을 절대 스케일로 매핑하기 위한 전체 스케일링 팩터.


그림 12: 네 샘플을 위해 피팅된 계수( coefficient )들. 우리는 수직 입사에 대한 측정 데이터를 우리 BTDF 를 위해 피팅하는데, Beckmann 미세면 분산과 GGX 미세면 분산을 모두 사용함. 각각의 경우 우리는 분산 width 파라미터와 전체 스케일링 팩터를 모두 피팅함( 왜냐하면 우리가 절대적인 측정값보다는 상대적인 측정값을 가지고 있기 때문임 ).


그림 13: 식각( etched ) 유리 샘플. 

위쪽은 BTDF fit 이며 아래쪽은 실증적인 미세면 분산 D 에 대한 fit 임.

 Red 라인은 Beckmann fit 이며 green 라인은 GGX fit 임.


그림 14: 눈부심방지( antiglare ) 유리 샘플.

위쪽은 BTDF fit 이며 아래쪽은 실증적 미세면 분산 D 에 대한 fit 임.

Red 라인은 Beckmann fit 이며 green 라인은 GGX fit 임.


우리 BTDF 모델을 테스트하기 위해, 각 샘플들을 위한 두 개의 그래프를 보여 줍니다. 첫 번째는 투과되는 각 θo 에 대한 함수인 ft(i,o,n)|o·n| 을 보여 줍니다. 우리는 수직 입사의 경우( θi = 0 )도 보여 주는데, 여기에서 우리는 피팅( fitting )을 수행했으며, 세 개의 부가적인 입사각( θi = 30, 60, 80° )을 사용해서 이러한 각들을 추정하기 위해 모델의 기능을 테스트했습니다.


두 번째 그래프는 데이터로부터 미세면 분산 함수 D 의 점들을 직접적으로 추정합니다. G 항은 지표각에서만을 제외하고는 1 이기 때문에, 우리가 지표각에서 먼 데이터 점들만을 사용하고( 즉 |i·n| > 0.5 이고 |o·n| > 0.5 ) 이 점들에 대해 G(i,o,m) = 1 이라 가정하면, 우리는 그와 관련한 D(ht) 의 값들에 대한 식 21 을 풀 수 있습니다. 또한 매우 낮은 측정값을 가진 점들을 배제할 수 있습니다. 왜냐하면 이 값들은 경로를 벗어난 빛에 의해 쉽게 영향을 받기 때문입니다. 만약 데이터가 미세면 모델과 어울린다면, 이 점들은 서피스의 미세면 분산 함수인 커브와 가까운 곳에 위치할 것입니다. 두 그래프에서 상대적인 측정 데이터와의 비교를 가능하게 하기 위해서 적당한 스케일링 팩터에 의해 모델들이 스케일링되어 있다는 점에 주의하시기 바랍니다.


가루 유리 샘플에 맞는 데이터와 모델은 그림 10 에 나와 있습니다. 우리는 GGX 분산이 그 데이터에 훌륭하게 어울리며 그것이 Beckmann fit 보다 더 낫다는 것을 알 수 있습니다. 유일하고 중대한 차이는 지표각 근처에서 발생하는데, 여기에서 기하 광학의 미세면 가설과 단일 스캐터링이 덜 유효해집니다. Beckmann 분산이 아래쪽 그래프에서 보이듯이 기준( inferred ) 미세면 분산과 일치하지 않는다는 것을 발견했습니다. 그래서 우리는 특별히 GGX 분산을 개발했습니다.


냉각 유리와 식각 유리를 위한 그래프는 그림 1113 에 있습니다. 두 샘플들의 경우에, Beckmann 과 GGX 는 모두 측정된 투과 패턴과 일치하는 타당한 작업을 수행했지만, 아래쪽 그래프에서 보이듯이 실증적인 미세면 분산 함수들과는 일치하는 모델은 없었습니다. 아마도 우리는 Beckmann 과 GGX 사이의 어딘가에 있는 것처럼 행동하는 분산 함수를 찾아야 할 필요가 있을 것 같습니다.


눈부심방지 유리는 다른 샘플들보다는 훨씬 더 낮은 서피스 러프니스를 가지고 있습니다. 그러므로 그림 14 에서 볼 수 있듯이 훨씬 좁은 로브를 가집니다. 그것이 너무 좁기 때문에, 우리는 상대적으로 로브 내에서 적은 샘플들만을 획득하게 되며, 그것의 width 를 추정하는데 더 많은 어려움을 겪습니다. 이 경우에는 Beckmann 과 GGX 가 모두 잘 들어 맞습니다.


우리의 BTDF 모델과 샘플링 기법을 사용해서, 우리는 눈부심방지 유리, 가루 유리, 식각 유리 샘플에 대한 렌더링 시뮬레이션을 했으며 이는 그림 15 에 나와 있습니다. 이 이미지들은 서로 다른 외형을 겹쳐서 보여 주며, 불투명한 패턴 및 디퓨즈 라이트에 대한 기능들을 잘 보여 줍니다. 패턴을 가진 식각 유리 글로브를 위한 시뮬레이션은 그림 1 에 나와 있습니다.


그림 15: 거칠게 만든 사각형의 서피스를 가진 유리 슬라이드에 대한 시뮬레이션.

 눈부심방지 유리, 가루 유리, 식각 유리를 위해 피팅된 분산들을 사용함.


7. Conclusions


이 논문에서, 우리는 미세면 이론에 대한 포괄적인 리뷰를 제공했으며, 거친 서피스를 가진 투과성 재질들을 다루기 위해서 그것이 어떻게 확장될 수 있는지를 보여 주었습니다. 우리는 최종 BTDF 모델들을 측정 데이터와 비교해서 검증했으며, 그것들이 실제 서피스의 굴절 행위를 예측할 수 있음을 보여 주었습니다. 우리는 새로운 미세면 분산 함수( GGX 분산 )를 개발했고, 적어도 어떤 서피스들에 대해서는 그것이 표준 Beckmann 분산보다는 측정 데이터와 더 가깝게 일치한다는 것을 보여 주었습니다. 또한 미세면 모델을 효율적으로 중요도 샘플링하는 방법에 대해서 보여 주었는데, 그것은 굴절된 빛을 렌더링할 때 필수적입니다. 우리는 이 기법들이 피부, 마블, 페인트와 같은 반투명한 재질을 가진 진보된 모델들을 포함하는 더 광범위한 재질들을 시뮬레이션하는 데 있어서 유용하다는 것을 증명할 수 있습니다.


Acknowledgements


This work was supported by NSF grants ACI-0205438, CNS-0615240, and CAPEER CCF-0347303, an Alfred P. Solan Research Fellowship, and Intel.


References


[APS00] ASHIKHMIN M., PREMOZE S., SHIRLEY P. S.: A microfacet-based BRDF generator. In Proceedings of ACM SIGGRAPH 2000 (July 2000), pp. 65–74.


[AS00] ASHIKHMIN M., SHIRLEY P. S.: An anisotropic phong BRDF model. Journal of Graphics Tools 5, 2 (2000), 25–32.


[BBS02] BOURLIER C., BERGINC G., SAILLARD J.: One- and two-dimensional shadowing functions for any height and slope stationary uncorrelated surface in the monostatic and bistatic configurations. IEEE Trans. on Antennas and Propagation 50 (Mar. 2002), 312–324.


[Bro80] BROWN G. S.: Shadowing by non-Gaussian random surfaces. IEEE Trans. on Antennas and Propagation 28 (Nov. 1980), 788–790.


[CT82] COOK R. L., TORRANCE K. E.: A reflectance model for computer graphics. ACM Transactions on Graphics 1, 1 (Jan. 1982), 7–24.


[Ger03] GERMER T. A.: Polarized light diffusely scattered under smooth and rough interfaces. In Polarization Science and Remote Sensing. (Dec. 2003), vol. 5158 of Proceedings of the SPIE, pp. 193–204.


[HTSG91] HE X. D., TORRANCE K. E., SILLION F. X., GREENBERG D. P.: A comprehensive physical model for light reflection. In Computer Graphics (Proceedings of SIGGRAPH 91) (July 1991), pp. 175–186.


[KSK01] KELEMEN C., SZIRMAY-KALOS L.: A microfacet based coupled specular-matte BRDF model with importance sampling. Eurographics Short Presentations (2001).


[Lar92] LARSON G. J. W.: Measuring and modeling anisotropic reflection. In Computer Graphics (Proceedings of SIGGRAPH 92) (July 1992), pp. 265–272.


[LRR04] LAWRENCE J., RUSINKIEWICZ S., RAMAMOORTHI R.: Efficient BRDF importance sampling using a factored representation. ACM Transactions on Graphics 23, 3 (Aug. 2004), 496–505.


[NDM05] NGAN A., DURAND F., MATUSIK W.: Experimental analysis of BRDF models. In Rendering Techniques 2005: Eurographics Symposium on Rendering (June 2005), pp. 117–126.


[NN04] NEE S.-M. F., NEE T.-W.: Polarization of transmission scattering simulated by using a multiple-facets model. Journal of the Optical Society of America A 21 (Sept. 2004), 1635–1644.


[NSSD90] NIETO-VESPERINAS M., SANCHEZ-GIL J. A., SANT A. J., DAINTY J. C.: Light transmission from a randomly rough dielectric diffuser: theoretical and experimental results. Optics Letters 15 (Nov. 1990), 1261–1263.


[PK02] PONT S. C., KOENDERINK J. J.: Bidirectional reflectance distribution function of specular surfaces with hemispherical pits. Journal of the Optical Society of America A 19 (Dec. 2002), 2456–2466.


[RE75] ROGERS J. E., EDWARDS D. K.: Bidirectional reflectance and transmittance of a scattering-absorbing medium with a rough surface. In Thermophysics Conference (May 1975).


[San69] SANCER M. I.: Shadow Corrected Electromagnetic Scattering from Randomly Rough Surfaces. IEEE Trans. on Antennas and Propagation 17 (1969), 577–585.


[Sch94] SCHLICK C.: An inexpensive BRDF model for physically-based rendering. Computer Graphics Forum 13, 3 (1994), 233–246.


[Smi67] SMITH B. G.: Geometrical shadowing of a random rough surface. IEEE Trans. on Antennas and Propagation (1967), 668–671.


[SN91] SÁNCHEZ-GIL J. A., NIETO-VESPERINAS M.: Light scattering from random rough dielectric surfaces. Journal of the Optical Society of America A 8 (Aug. 1991), 1270–1286.


[Sta01] STAM J.: An illumination model for a skin layer bounded by rough surfaces. In Rendering Techniques 2001: 12th Eurographics Workshop on Rendering (June 2001), pp. 39–52.


[TS67] TORRANCE K. E., SPARROW E. M.: Theory for off-specular reflection from roughened surfaces. Journal

of Optical Society of America 57, 9 (1967), 1105–1114.


[Vea96] VEACH E.: Non-symmetric scattering in light transport algorithms. In Eurographics Rendering Workshop 1996 (June 1996), pp. 81–90.


[vSK98] VAN GINNEKEN B., STAVRIDI M., KOENDERINK J. J.: Diffuse and Specular Reflectance from Rough Surfaces. Applied Optics 37 (Jan. 1998), 130–139.


[Wal05] WALTER B.: Notes on the Ward BRDF. Technical Report PCG-05-06, Cornell Program of Computer Graphics, Apr. 2005.


Appendix A: Deriving the Smith Shdowing, G1


( 역주 : 생략, 원문을 참조하세요 )

주의 : 공부하면서 정리한 것이기 때문에 오류가 있을 수 있습니다.


 

PBR Specular D 의 기하학적 의미

 

PBR( Physically Based Rendering )에서 대세가 된 Cook-Torrance 의 스펙큘러 BRDF [1] 는 다음과 같이 정의됩니다.

 

 

 

이 중에서 D 함수는 미세면( microfacet )의 기울기에 대한 분산( Distribution ) 함수입니다. 이 문서에서는 이것의 기하학적 의미에 대해서 다루고자 합니다.

 

하나의 서피스( surface )는 여러 개의 미세면( microfacet )으로 구성되어 있다는 것이 PBR 이론의 근간에 깔려 있습니다. 그리고 서피스를 구성하는 각 미세면들은 서로 다른 노멀( normal )을 가지게 됩니다. 또한 그 미세면들에서는 거울면 반사( mirror reflection, 정반사 )가 발생합니다.

 

많은 문서에서는 이러한 미세면의 노멀을 m 으로 표시하기도 하고 h 로 표시하기도 합니다. 아마도 microfacet normal 과 half vector 의 약자인 것 같습니다. 그림 1 에서는 서피스와 미세면의 관계를 보여 줍니다.

 

그림1 : 미세면으로 구성된 서피스[2].

 

미세면의 노멀을 m 이라 표기하는 것은 이해가 가는 부분이지만 h( half vector )라 표기할 수도 있다는 것은 이해가 안 갈 것입니다. Burley 와 Cook-Torrance [1, 3] 은 공통적으로 하프 벡터( half vector )가 미세면의 노멀을 표현한다고 기술하고 있습니다.

 

이것은 하프 벡터를 사용하는 문맥으로부터 그 의미를 이해하는 것이 좋습니다. 위에서 우리는 미세면이 거울면 반사를 보여 준다고 가정했습니다. 그러면 질문을 뒤집어 보죠. 

 

서피스 내에서, 우리에게 거울면 반사를 보여 줄 수 있는 기울기를 가진 미세면은 얼마나 많을까요?

 

이것이 바로 Specular D 함수를 통해 얻고자 하는 값의 본질입니다. 그림 2 의 가장 왼쪽에 있는 미세면이 나에게 거울면 반사라는 결과를 보여 주려면 어떤 기울기를 가지고 있어야 할까요? 여기에서 n 은 서피스 노멀이고 m 은 미세면 노멀입니다.

 

그림 2: 샘플 미세면.

 

거울면 반사는 "입사각과 반사각이 같은 반사" 입니다. 그러므로 아래 그림처럼 빛 벡터 l 과 뷰 벡터 v 의 절반인 하프 벡터( h )와 미세면 노멀( m )이 일치하는 경우에 거울면 반사가 발생합니다.

 

 

여기에서 추정할 수 있는 것은 뾰족한 미세면이 많다면 retroreflection 의 양이 많아진다는 것입니다. 그냥 대중없이 거칠다면 난반사가 심해질 것이고, 부드럽다면( 즉 mn 과 거의 비슷한 면이 많다면 ) 정반사가 커지겠죠.

 

결국 우리의 질문은 다음과 같이 바뀔 수 있습니다.

 

광원을 향하는 벡터 l 와 관찰자(뷰)를 향하는 벡터 v 를 가지고 있을 때, 그것의 하프 벡터 h 와 동일한 미세면 노멀 m 은 얼마나 존재하나요?

 

하프 벡터 h 와 미세면 노멀 m 의 각도가 0 이 되는 미세면의 분포를 찾는 것이 Specular D 함수의 목적입니다. 그러므로 어떤 문헌들에서는 이런 가정을 깔고 "하프 벡터가 미세면의 노멀이다" 라는 식의 표현을 하게 되는 것입니다.

 

[3] 에서 Burley 는 실측 데이터와 다른 Specular D 함수들을 비교했습니다.

 

그림 3: Burley 가 비교한 분산들.

왼쪽부터 크롬 실측값, GGX, Beckmann.

 

일단 기존의 모델 중에서 가장 나은 것은 GGX( Trowbridge-Reitz 와 같음 ) 였습니다. 하지만 실측값을 보면 타는 듯한 효과와 더 긴 테일( tail )이 보입니다. 그래서 Burley 의 경우에는 이중 스펙큘러 로브를 구현하게 됩니다. 자세한 내용은 해당 기사에서 확인하시기 바랍니다.

 

하지만 실시간 렌더링의 세계에서는 스펙큘러 로브를 두 개씩 계산하는 것이 부담이 됩니다. 그래서 UE4 같은 경우에는 그냥 GGX 를 사용합니다.

 

물론 여러 개의 변종들이 있을 수 있으며, Specular BRDF Reference 에서 이를 확인할 수 있습니다. 참고로 이 문맥에서 "Normal Distribution" 은 정규 분포가 아닙니다. "노멀의 분포"라는 이야기입니다. "Specular D" 와 동일한 말입니다.

 

참고자료

 

[1] Robert L. Cook and Kenneth E. Torrance, "A Reflectance Model for Computer Graphics"( 번역 : http://lifeisforu.tistory.com/349 ).

 

[2] Simon's Tech Blog, "Microfacet BRDF". http://simonstechblog.blogspot.kr/2011/12/microfacet-brdf.html.

 

[3] Brent Burley, "Physically-Based Shading at Disney"( 번역 : http://lifeisforu.tistory.com/350 ).

원문 : https://disney-animation.s3.amazonaws.com/library/s2012_pbs_disney_brdf_notes_v2.pdf

주의 : 번역이 개판이므로 이상하면 원문을 참조하세요.

주의 : 허락받고 번역한 것이 아니므로 언제든 내려갈 수 있습니다.

주의 : 부록은 번역하지 않았으므로 원문을 참조하세요.



Physically-Based Shading at Disney


by Brent Burley, Walt Disney Animation Studios


[Revised Aug 31, 2012. Corrected normalization factor in Equation 4.]


1 Introduction


Tangled( 한국개봉명 : 라푼젤 ) [27] 에서 물리 기반 헤어 쉐이딩을 사용하는 것에 성공한 후에, 우리는 재질의 더 많은 영역에 물리 기반 쉐이딩 모델들을 적용하는 것을 고려하기 시작했습니다. 우리는 물리 기반 헤어 모델을 사용해서 아티스트의 제어를 유지한 채로 가시적인 풍성함의 정도를 더 깊게 할 수 있었습니다. 그러나 여전히 전통적인 "단순(ad-hoc)" 쉐이딩 모델 및 점 광원( punctual light )을 가지고 있는 씬의 나머지 부분과 헤어 라이팅을 통합하는 것은 모험에 가깝다는 것이 증명되었습니다. 우리는 차기작에서는 재질들과 환경들 사이의 라이팅 반응( response )을 더 일관되게 만들면서 재질들의 풍성함은 증가시키기를 원했습니다. 또한 단순화된 아티스트 컨트롤을 통해서 아티스트들의 생산성이 높아지기를 원했습니다.


우리가 연구를 시작했을 때는 어떤 모델을 사용해야 할지 심지어는 우리가 원하는 물리 기반이 어떤 것인지에 대해서 분명하지 못했습니다. 완벽하게 에너지 보존 법칙을 지켜야 하나? 굴절률( Index of refraction )과 같은 물리적인 파라미터들을 선호해야 하나?


디퓨즈( Diffuse )의 경우에는 램버트( Lambert )가 받아들일 수 있는 표준으로 보였고, 스펙큘러( specular )의 경우에는 대부분을 문헌( literature )에서 얻어야 하는 것처럼 보였습니다. Ashikhmin-Shirley ( 2000 ) [3] 와 같은 모델들은 물리적으로 타당하면서 직관적이고 실용적이되는 것이 목표였지만, He et al. ( 1991 ) [12] 와 같은 다른 모델들은 좀 더 포괄적인 물리적 모델을 제공했습니다. 여전히 다른 모델들은 실제 관측 데이터에 더 잘 들어 맞게 하는 것( fitting ) [15, 14, 22, 17, 4 ]을 목표로 하지만, 이것들 중의 일부는 직접적인 조작에 적합합니다. 우리는 몇 개의 모델들을 구현했고 아티스트들은 그것들을 선택하고 조합했습니다. 하지만 우리가 피하고 싶었던 파라미터 폭발( parameter explosion, 역주 : 너무 많은 파라미터를 공급해야 하는 사태 ) 상황으로 다시 되돌아가게 되었습니다.


측정 재질( measured material )에 대한 매우 다양한 연구 중 하나는 Ngan et al. ( 2005 ) [21] 이었는데, 이것은 다섯개의 대중적인 모델들을 비교했습니다. 어떤 모델들은 전반적으로 다른 모델들보다 더 나아졌지만, 흥미롭게도 모델들의 성능들 사이에는 강한 연관성이 존재했습니다 - 어떤 재질들은 모든 모델들에 의해 잘 표현되었지만, 다른 재질들은 전혀 적합하지 않은 것으로 증명되었습니다. 몇 몇 경우에만 부가적인 스펙큘러 로브( lobe )가 도움이 되었습니다. 이는 질문을 하게 만듭니다. 어려운 재질들에서 표현되지 않고 있는 것은 무엇일까?


이 질문에 답하고 BRDF 모델들을 더욱 직관적으로 평가하기 위해서, 우리는 새로운 BRDF 뷰어를 개발했는데, 이는 측정된( measured ) BRDF 와 분석적( analytic ) BRDF 를 모두 출력하고 비교합니다. 우리는 측정된 BRDF 데이터를 보여주기 위한 새롭고 직관적인 방법을 발견했으며, 알려진 모델로 잘 표현되지 않는 흥미로운 특징들을 측정된 재질들에서 찾아냈습니다.


이 코스 노트( course note )에서, 우리는 측정된 재질에 대해 공부하면서 관측한 것들에 대해서 공유하고, 어떤 모델이 측정된 데이터에 맞고 어디에서 그것들이 결핍되어 있는지를 알아내는 것에 대한 통찰력을 공유하고자 합니다. 또한 이 새로운 모델을 작업에 적용한 것과 관련한 경험에 대해서 설명하고, 단순함과 신뢰도를 유지하면서 아티스트들이 사용하기 적합한 수준의 컨트롤을 추가할 수 있었던 방법에 대해 논의하고자 합니다.


2 Microfacet Model


우리는 BRDF 를 정의하고 미세면 모델의 관점에서 측정된 재질들과 비교할 것입니다 [30, 7, 33]. 미세면 모델은, 주어진 빛 벡터 l 과 뷰 벡터 v 사이에서 서피스 반사가 발생할 수 있으려면, l 벡터와 v 벡터 사이에서 반만큼 정렬된 노멀( normal )을 가진 서피스나 미세면들이 존재해야만 한다고 가정합니다. 이 "하프벡터( half vector )"는 보통 미세면 노멀이라 불리는데, 다음과 같이 정의됩니다( 역주 : 모든 미세면의 노멀이라는 의미가 아니라, lv 가 특정 관계에 있을 때 나에게 정반사를 보내줄 수 있는 미세면의 노멀을 이야기하는 것입니다. [PBR Specular D 의 기하학적 의미] 참조 ).



등방성 재질을 위한 미세면 모델의 일반형은 다음과 같습니다:



디퓨즈 항은 알려지지 않은 형태의 함수입니다. 램버트 디퓨즈가 보통 사용되는데 상수 값에 의해 표현됩니다. 스펙큘러 항의 경우, D 는 미세면 분산( 분포 ) 함수이며 스펙큘러 피크( peak )의 모양을 결정합니다. F 는 프레넬( Fresnel ) 반사 계수이며, G 는 기하학적 감쇠 혹은 그림자 팩터( factor, 인자, 요소 )입니다.


θl 과 θvlv 의 입사각인데 노멀에 대해 상대적입니다. θh 는 노멀과 하프벡터 사이의 각도입니다. 그리고 θdl 과 하프벡터( 혹은 대칭적으로는 vh ) 사이의 각도 "차이"입니다( 역주 : 번역이긴 하지만 아래에 참고 이미지를 추가함. 그림 R1 ).


그림 R1: 각도 관계.


미세면 형식으로 명확하게 설명되고 있지 않은 물리적으로 타당성있는 모델들은 대부분 여전히 미세면 모델로 해석될 수 있습니다. 그것들은 분산 함수, 프레넬 팩터, 그리고 기하학적 그림자 팩터들을 고려할 수 있는 부가적인 요소들을 가지고 있기 때문입니다. 미세면 모델들과 다른 모델들과의 실제적인 차이는 그것들이 명시적으로 팩터를 포함하고 있느냐의 여부인데, 이 팩터는 미세면을 유도하는 과정에서 나오게 됩니다. 이 요소를 포함하고 있지 않은 모델들의 경우에는, D 요소와 F 요소를 뽑아낸 후에 그 모델에 를 곱해줌으로써 암묵적으로 그림자 팩터를 결정할 수 있습니다.


3 Visualizing measured BRDFs


3.1 The "MERL 100"


그림 1: MERL 100 BRDFs 의 이미지 슬라이스.


Matusik et al. ( 2003 ) [18] 은 100 개의 등방성 BRDF 재질 샘플들의 집합을 캡쳐했는데, 페인트, 나무, 금속, 섬유, 돌, 플라스틱, 그리고 다른 합성 재질들을 포함하는 광범위한 영역의 재질들을 커버합니다. 이 데이터 집합은 Mitsubishi Electric Research Laboratories 의 www.merl.com/brdf 에서 자유롭게 이용할 수 있으며, 보통 새로운 BRDF 모델들을 평가하기 위해 사용됩니다. 이 BRDF 들에 대한 슬라이스가 그림 1 에 나와 있습니다.


MERL 100 내의 각 BRDF 는 상대적으로 θh, θd, φd 축을 따라서 90 X 90 X 180 크기의 큐브에 조밀하게 샘플링되어 있습니다. 이것들은 θh 축을 제외하고는 1 도씩 증가하는 것과 같습니다. θh 축은 스펙큘러 피크 근처에 데이터 샘플들을 집중시키기 위해서 왜곡되었습니다. 그 측정값은 필요에 의해 필터링되거나 추정됩니다. 그래서 데이터에는 빈 부분( holes )이 존재하지 않습니다. 이는 데이터를 사용하기 쉽다는 점에서 훌륭합니다. 하지만 데이터가 얼마나 정확한지가 명확하지 않습니다. 특히 수평선 근처에서 그렇습니다. 이 때문에 어떤 연구자들은 피팅을 수행할 때 수평선 근처의 데이터를 버려 버립니다. 하지만 그것이 재질의 외형에 중요한 영향을 주는 것을 고려해 보면 여전히 유용합니다.


3.2 BRDF Explorer


그림 2: Disney BRDF Explorer.


MERL 측정 재질을 실험하고 분석적 모델과 비교하기 위해서, 우리는 그림 2 에 보이는 새로운 툴인 BRDF Explorer 를 개발했습니다. github.com/wdas/brdf 에서 오픈 소스로 이용하실 수 있습니다. 그것은 다음과 같은 기능들을 가지고 있습니다:


    • GLSL 로 작성된 여러개의 분석적 BRDF 를 로드할 수 있는 기능.
    • Ngan et al. [21] 에 의해 캡쳐된 비등방성 재질 샘플들을 포함하는 측정된 BRDF 들을 로드할 수 있는 기능.
    • 다중 데이터 플롯( 3d hemispherical view, polar plot, and various cartesian plots ).
    • Computed albedo plot( 즉, directional-hemispherical reflectance ).
    • 노출( exposure ) 제어를 할 수 있는 Image slice view.
    • Importance-sampled IBL 라이팅을 적용한 Lit object view.
    • Lit sphere view.
    • 파라메트릭( parametric ) 모델들을 위한 동적 UI 컨트롤.


이 툴은 측정된 재질들을 현존하는 분석적 모델들과 비교하는 것 뿐만 아니라 새로운 모델을 개발하는 데 있어서도 소중합니다. 놀랍게도 인터랙티브 BRDF 에디터로서 아티스트들에게도 유용하다는 것이 밝혀졌습니다. 이는 모델 파라미터들과 BRDF 공간에 대한 더 깊은 이해를 할 수 있게 해 줍니다.


3.3 Image slice


그림 3: red-plastic 과 specular-red-plastic 을 위한 BRDF 이미지 슬라이스.

"슬라이스 공간" 에 대한 도해도 함께 보여주고 있음.


측정된 재질을 가시화하는 가장 단순하고 직관적인 방법은 그것을 이미지 스택으로 단순하게 보여주는 것입니다. 그리고 우리는 그 데이터에 대한 직관력을 획득하는데 있어서 이것이 매우 강력한 도구임을 발견했습니다. 나중에 알게 된 것이지만, MERL 100 재질들 내에서 모든 흥미로운 특징들은 φd = 90 슬라이스에서 나타납니다. 두 재질 샘플들과 함께 이 공간에 대한 도해가 그림 3 에 나와 잇습니다. 다른 슬라이스들은 그 슬라이스를 대략적으로 그냥 왜곡시킨 버전이며 그림 4 에 나와 있습니다. 이 관측값은 Romerio ( 2008 ) [19] 와 Pacanowsi ( 2012 ) [24] 같은 최근의 연구에서 f(θhd) 형식에 대한 단순화된 등방성 BRDF 모델을 위한 기저로서 사용되어 왔습니다.


그림 4: 하프벡터 주변의 에 대한 방위각( azimuthal ) 회전인 φd 의 다양한 값에 대한 specular-red-plastic 의 슬라이스.

우상단 코너의 검은색 영역은 BRDF 도메인의 일부를 표현하는데, 여기에서는 l 벡터나 v 벡터가 수평선 아래에 존재합니다.


이미지 슬라이스에서, 왼쪽 가장자리는 스펙큘러 피크를 표현하고, 위쪽 가장자리는 프레넬 피크를 표현합니다. 바닥 가장자리를 따라서 빛 벡터와 뷰 벡터가 일치한다는 점에 주목하십시오; 그러므로 바닥 가장자리는 retroreflection 을 표현하게 됩니다. 우하단 코너는 특별히 grazing retroreflection 을 표현합니다. 디퓨즈 반사도는 전체 BRDF 공간에서 나타납니다. 하지만 이미지의 중간은 일반적으로 디퓨즈 반응에 대해 격리되어 있습니다.


그림 3 의 도해는 θl 이나 θv 에 대한 등치선( isoline )을 포함합니다. 많은 디퓨즈 효과들은 이 윤곽( contour )을 따르는 경향이 있습니다. 이 등치선은 φd 가 0 에 근접하면 쭉 펴진다는 점에 주목하십시오. 그리고 θd 슬라이스들을 비교하는 것은 재질 응답에서 어느 부분이 디퓨즈 반사 때문에 생기고 어느 부분이 스펙큘러 반사 때문에 생기는지에 대한 직관을 제공할 수 있습니다. 다른 힌트는 당연히 색상입니다; 가시적인 색조를 산출하는 디퓨즈 반사도는 subsurface scattering 과 absorption 때문에 발생합니다. 반면에 스펙큘러 반사도는 서피스로부터 오며 그것은 ( 서피스가 금속이 아닌 이상 ) 색조를 가지지 않습니다( 서피스가 금속이면 디퓨즈 성분이 존재하지 않습니다 ).


4 Observtions from MERL materials


4.1 Diffuse observations


그림 5: 디퓨즈 색상 변화를 보여주는 재질들.

위쪽 행: 렌더링된 구 상에서 점광원에 대한 반응( response )들;

아래쪽 행: BRDF 이미지 슬라이스들.



디퓨즈 반사도( reflectance )는 서피스로 굴절되고, 산란되고, 부분적으로 흡수되고, 다시 방출되는 빛을 표현합니다. 일부 빛이 흡수되는 것을 고려하면, 디퓨즈 반응은 서피스 색상을 사용해 빛나고, 비금속 재질의 빛나는 부분은 디퓨즈라고 여겨질 수 있습니다.


그림 6: MERL 100 재질의 retroreflective 반응.

왼쪽: 50 개의 부드러운 재질들 ( f(0) > 0.5 );

오른쪽: 50 개의 거친 재질들 ( f(0) < 0.5 ).

θh = 0 근처의 피크( peak )는 스펙큘러 피크이며,

θh = 90 근처의 피크( 혹은 드랍( drop ) )은 grazing retroreflection 을 표현함.


그림 7: red-plastic, specular-red-plastic, Lambertian diffuse 에 대한 점광원 반응.


램버시안( Lambertian ) 디퓨즈 모델은 굴절된 빛이 모든 방향성을 잃어 버릴 정도로 충분히 산란된다고 가정합니다. 그러므로 디퓨즈 반사도는 상수입니다. 그러나 그림 1그림 5 에서의 다양한 이미지 슬라이스에서는 소수의 재질들만이 램버시안 반응을 보이는 것을 볼 수 있습니다. [ 주의 : 램버트 쉐이더는 n·l 요소를 포함하지만, 그것은 라이팅 적분의 일부이지 BRDF 가 아닙니다 ]


그림 6 에서 보이는 것처럼, 많은 재질들은 grazing retroreflection 에서 드랍을 보여줍니다. 그리고 많은 다른 재질들은 피크를 보여 줍니다. 이는 이미지 슬라이스 내의 apparent tinting 때문에 발생하는 디퓨즈 현상인 것으로 보입니다. 특히 이것은 러프니스와 강하게 연관되어 있습니다 - 강한 스펙큘러 피크를 가지는 부드러운 서피스는 shadowed edge 를 가지고, 거친 서피스는 그림자 대신에 피크를 가지는 경향이 있습니다. 이 연광성은 retroreflective response curves 에서 볼 수 있으며, 또한 그림 7 의 렌더링된 구에서도 볼 수 있습니다.


부드러운 서피스를 위한 grazing shadow 는 프레넬 공식에 의해 예측됩니다: 지표각( grazing angle )에서는 서피스로부터 더 많은 에너지가 반사되며, 확산성있게 재방출되기 위한 서피스로 굴절되는 에너지는 적습니다.


Oren-Nayar 모델( 1995 )은 디퓨즈 모양을 평평하게 만드는 거친 디퓨즈 서피스들을 위한 retroreflective increase 를 예측합니다. 그러나 이 retroreflective peak 는 측정된 데이터만큼 강하지 않으며 측정된 거친 재질들은 일반적으로 디퓨즈를 평평하게 보이도록 하지 않습니다. Subsurface scattering 이론으로부터 유도된 Hanrahan-Krueger 모델 ( 1993 )도 디퓨즈 모양의 평탄화를 예측했지만, 그것은 가장자리에서 충분히 강한 피크를 가지지 않습니다. Oren-Nayar 와는 반대로 이 모델은 완벽하게 부드러운 서피스를 가정합니다. Oren-Nayar 모델과 Hanrahan-Krueger 모델이 그림 8 에서 비교되고 있습니다.


그림 8: Lambert, Oren-Nayar, Hanrahan-Krueger 디퓨즈 모델에 대한

BRDF 슬라이스 및 점광원 응답.


Retroreflective peak 외의 추가적인 diffuse variation 들을 그림 5 의 이미지 슬라이스들에서 찾아 볼 수 있습니다. θl / θv 등치선을 따르는 intensity variation 과 color variation 을 볼 수 있습니다. 이는 layered subsurface scattering 때문에 발생하는 것으로 보입니다. 그러나 심지어 layered subsurface scattering 모델이라 할지라도 일반적으로는 서피스가 부드럽고 강한 retroreflective peak 를 생성하지 않는다고 가정합니다.


4.2 Specular D observations


미세면 분산 함수 D(θh) 는 그림 6 에서 보이는 측정된 재질의 retroreflective responses 에서 관찰될 수 있습니다. 이 재질들은 서피스의 러프니스를 나타내는 것으로 보일 수 잇는 피크의 높이에 기반해 두 개의 그룹으로 분리됩니다. 강철( steel )로부터 나오는 가장 높은 피크는 400 이 넘었습니다. 피크가 평탄화된 다음의 커브의 나머지 부분들은 아마도 디퓨즈 반사도에서 기인한 것일 겁니다.


거의 대다수의 MERL 재질들은 테일( tail )을 가진 스펙큘러 로브를 가지고 있는데, 이는 전통적인 스펙큘러 모델들의 테일보다 훨씬 깁니다. 그 예는 그림 9 에 보이는 크롬( chrome ) 샘플입니다. 이 재질에 대한 스펙큘러 반응은 부드럽고 매우 연마된 서피스들을 위해서 일반적입니다. 그러한 서피스들은 몇 도 넓은 스펙큘러 피크와 몇 배 더 넓은 스펙큘러 테일을 가지고 있습니다. 이상하게도 전통적인 Beckmann, Blinn Phong, Gaussian 분산들은 거의 비슷한 너비를 가지고 있지만, 피크나 테일을 잘 표현하지 못합니다.


그림 9: MERL 크롬에 맞는 몇 개의 스펙큘러 분산들.

왼쪽: θh ( 각도 )에 대한 스펙큘러 피크의 로그스케일 그래프;

black = 크롬,

 red = GGX ( alpha = 0.006 ),

 green = Beckmann ( m = 0.013 ),

 blue = Blinn Phong ( n = 12000 ).

오른쪽 : 크롬, GGX, Beckmann 으로부터의 ( clipped ) 점광원 반응들. 


더 넓은 테일에 대한 필요성이 Walter et al. ( 2007 ) [33] 에 의해 소개된 GGX 분산을 위한 동기가 되었습니다; GGX 는 다른 분산들보다는 훨씬 더 긴 테일을 가지고 있지만, 여전히 크롬 샘플의 타는듯한 하이라이트를 캡쳐하는데는 실패합니다. 측정된 재질에 맞추기 위해서 테일 반응을 모델링하는 것의 중요성은 최근 연구인 Löw et al. ( 2012 ) [17] 과 Bagher et al. ( 2012 ) [4] 의 근간이 되기도 했습니다. 이 모델들은 둘 다 부가적인 파라미터를 추가해서 피크와는 별개로 테일을 제어합니다. 테일을 모델링하기 위한 또다른 옵션은 Ngan [21] 에 의해 제안되었던 것처럼 첫 번째 스펙큘러 피크에다가 두 번째의 넓은 스펙큘러 피크를 사용하는 것입니다.


4.3 Specular F observations


그림 10: θd 에 대한 MERL 100 재질들의 정규화된 프레넬 반응들의 그래프.

반응들은 1 도에서 4 도까지의 θh 에 대한 평균이며, 입사 반응은 빠져 있으며,

모양을 비교하기 위해 45 도에서 89 도 까지의 θd 상에서 정규화됨.

점선은 이론적인 프레넬 반응을 의미함.


프레넬 반사 팩터 F(θd) 는 빛 벡터와 뷰 벡터가 서로 멀어질 때 스펙큘러 반사가 증가함을 보여주며, 모든 부드러운 서피스들은 지표각에서 100% 의 스펙큘러 반사에 접근하게 될 것임을 예측합니다. 거친 표면의 경우 100% 의 스펙큘러 반사는 있을 수 없지만, 여전히 스펙큘러가 증가하는 방향으로 반사도가 변합니다.


MERL 재질들에 대한 프레넬 반응을 보여 주는 커브가 그림 10 에 나와 있습니다. 이 커브는 옵셋( offset )이며 그 반응들의 전체 모양을 비교하기 위해서 스케일링된 것입니다. 이는 그림 1 의 이미지 슬라이드들의 위쪽 가장자리에서도 볼 수 있습니다.


특히, 지표각 근처의 커브들의 대부분에서 나타나는 뾰쪽함은 프레넬 효과에 의해서 예상되는 것보다 더 큽니다. 사실 이러한 관측값은 높은 입사각에서 목격되는 "off-specular peak" 를 설명하기 위해 Torrance-Sparrow ( 1967 ) [30] 미세면 모델의 동기가 되었습니다. 미세면 모델의  팩터는 지표각에서 무한대로 갑니다. ( 모델에서든 실세계에서든 ) 이것이 문제가 되지 않는 이유는 지표각 반사도가 미세면의 그림자 효과에 의해 제거되기 때문입니다. G 팩터는 빛 벡터의 그림자를 표현하며, 대칭적으로 뷰 벡터에 대한 마스킹( masking )을 표현합니다. 그리고 지표각 반사도를 억제합니다. 그러나 G 팩터가 그림자를 표현함에도 불구하고, G 와  의 결합은 프레넬 효과를 실질적으로 증폭시킵니다. 


4.4 Specular G ( and albedo ) observations


그림 11: MERL 100 재질들의 알베도 그래프.

왼쪽: 50 개의 부드러운 재질.

오른쪽: 50 개의 거친 재질.


측정된 데이터로부터 G 를 추출하는 것은 어렵습니다. 왜냐하면 D 팩터와 F 팩터에 대한 정확한 평가와 그리고 디퓨즈로부터 스펙큘러를 격리할 것을 요구하기 때문입니다.그러나 G 의 효과는 지향성 알베도( directional albedo ) 상에서의 그것의 효과에서 간접적으로 볼 수 있습니다.


알베도라는 것은 전체 입사 에너지에 대한 전체 반사 에너지의 비율입니다. 넓은 개념에서 그것은 서피스의 색상을 대표하며 모든 파장에 대해 1 보다 작아야 합니다. 알베도는 태양과 같은 단일 방향으로부터 오는 빛으로 생각될 수도 있습니다. 이 경우에 알베도는 입사각에 의존하는 지향성 함수가 되며, 모든 각과 파장에 대해 1 보다 작아야 합니다.


대부분의 재질의 지향성 알베도는 그림 11 에서 보이듯이 처음 70 도 내에서는 상대적으로 평평합니다. 그리고 지표각에서는 서피스 러프니스와 강하게 연관을 맺습니다. 부드러운 재질들의 알베도는 75 도 근처에서 약간 증가했다가 90 도로 가면서 떨어집니다. 거친 재질들의 알베도는 보통 지표각 근처에서 급격하게 증가합니다. 특히, 전체적인 알베도 값들은 매우 낮으며, 일부 재질들만이 0.3 이 넘는 알베도 값을 가집니다.


The grazing retro-reflection exhibited by many rough materials also contributes significantly to this gain, as evidenced by a chromatic tint in the albedo.


그림 12: 몇 개의 스펙큘러 G 모델을 비교한 알베도 그래프.

모든 그래프는 같은 D ( GGX/TR ) 팩터와 F 팩터를 사용함.

왼쪽: 부드러운 서피스 ( α = 0.02 );

오른쪽: 거친 서피스 ( α = 0.5 ).

"no G" 모델은 G 팩터와 를 배제함.


모델링된 G 팩터들을 선정하기 위해서 그림 12 에서 알베도 반응을 보여주는데, 매우 부드러운 서피스와 매우 거친 서피스를 모두 다룹니다. 특히, G 와  를 전체적으로 누락시킴으로써 "No G" 모델이라고 불리는 것의 결과는 지표각에서 전체적으로 어두운 반응을 보여줍니다. 여기에서 중요한 점은 G 함수를 선택하는 것은 알베도에 중요한 영향을 미치며 결국에는 서피스 외형에 중요한 영향을 미친다는 것입니다.


몇몇 스펙큘러 모델들은 좀 더 이치에 맞는 알베도 반응 커브를 생성한다는 분명항 목적을 가지고 개발되었습니다[30, 29, 19, 20, 8, 9, 33, 10, 14]. 이들 중 일부의 경우, 에너지 균형을 유지하기 위해서 알베도를 완전히 평평하게 만들어 버립니다. 그림 11 의 MERL 데이터의 알베도 그래프에 기반해서 보면, 거의 대부분의 재질들이 grazing gain 을 보여주기는 하지만, 이것이 그렇게 비합리적이지는 않습니다. 심지어 grazing gain 의 일부는 non-specular effects 에서 기인합니다.


몇 가지 가정을 단순화하면, Smith [29] 의 기법을 따르는 미세면 분산 D 로부터 그림자 함수를 유도하는 것이 가능합니다. 이는 Walter ( 2007 ) 와 Schlick ( 1994 ) 에 의해서 사용된 접근법입니다. 그림 12 에서 볼 수 있듯이, Walter 의 Smith 모델의 지표각 반사도는 부드러운 서피스들의 경우에는 급격하게 증가합니다. 이러한 효과는 측정된 데이터에서는 볼 수 없는 것입니다. 더 거친 값들의 경우에, 그 반응은 좀 더 이치에 맞게 보입니다. Smith G 는 적은 개수의 함수들만을 위한 분석적 형식을 가지고 있으며, 보통은 tabular integration 이나 다른 근사계산이 사용된다는 점에 주의하시기 바랍니다.


Kurt et al. ( 2010 ) [14] 의 실증적 모델은 다른 접근법을 취하며, 자유 매개변수( free parameters )를 사용하는 데이터 피팅을 제안합니다. 그림 12 는 Kurt 모델을 보여주는데 α = 0.25 를 사용합니다; 다른 α 값은 더 넓은 범위의 알베도 반응을 산출할 수 있습니다. Of concern though is that the Kurt albedo diverges near grazing angles, significantly for rough distributions. 다른 옵션은 그냥 Walter 의 Smith G 유도 함수들 중 하나나 Schlick 의 더 단순한 함수를 사용하고, G 러프니스를 자유 매개변수로 분리하는 것입니다.


4.5 Fabric


MERL 데이터베이스 내의 많은 섬유 샘플들은 지표각에서 스펙큘러 색조를 보여 주며, 비슷한 러프니스를 가진 재질들보다 더 강력한 프레넬 피크를 가집니다. 이러한 예가 그림 13 에 나와 있습니다.


그림 13: 다양한 섬유 샘플들에 대한 BRDF 이미지 슬라이스들.


매우 복잡한 재질 응답을 가지고 있는 섬유들이 많이 있기는 하지만, MERL 섬유들은 상대적으로 모델링하기 편합니다.


4.6 Iridescence


그림 14: color-changing-paint1, 2, 3 에 대한 BRDF 이미지 슬라이스.

위쪽 행: 원래 데이터;

아래쪽 행: 1/max(r,g,b ) 를 픽셀당 적용함으로써 생성한 관련 채도 이미지.


그림 14 에서 세 개의 색상 변조 페인트는 φd 에 대해 최소한의 의존성을 가지는 (θhd) 상의 일관성있는 색상 조각들을 보여 줍니다. This appears to be a completely specular phenomenon given that there's very little reflectance away from the specular peak. 이는 θh 와 θd 에 대한 함수로서의 스펙큘라 색조( hue )를 작은 텍스쳐 맵과 곱합으로써 단순하게 모델링될 수 있습니다.


4.7 Data anomalies


MERL 데이터에서의 일부 변칙들이 그림 15 에 나와 있습니다.


    • 매우 빛나는 재질들 중 일부는, 특히 금속들은, 렌즈 플레어나 비등방성 서피스 스크래치를 연상시키는 대칭적인 하이라이트를 보여 줍니다.
    • 75 도 근처를 지나간 데이터는 외삽된( extrapolated ) 것처럼 보입니다( 역주 : 보외법 혹은 외삽법 : 그래프 등의 자료에서 나와 있지 않은 부분을 그 부분에 가까운 부분에서 이어 나가면서 추정하는 방법. 그 반대가 보간법 혹은 내삽법( interpolation )이라 함. 보간법은 그래프 자료 내의 빈 부분의 값을 그 주변의 값으로 평균내서 추정하는 방법 ).
    • 섬유의 지표각 반응은 보통 이상한 불연속성을 보이는데, 아마도 캡쳐를 하는 동안에 가장자리 근처에서 늘어나거나 접혔기 때문인 것으로 보입니다.
    • 일부 나무들은 θd 를 따라 변조 패턴( modulation pattern )을 보여주는데, 이는 나무결 때문인 것으로 보입니다.
    • Subsurface scattering 효과가 구워집니다.


그림 15: MERL 데이터에서의 변칙. 왼쪽에서 오른쪽으로: steel 의 점광원 반응은 대칭적 하이라이트를 보여줌.

color-changing-paint1 의 채도 그래프는 외삽( extrapolated ) 지표각 데이터를 보여 줌( 모든 재질에서 보임 ).

white-fabric 은 지표각 근처에서 주름을 연상시키는 그림자를 보여줌.

fruitwood-241 은 나무결을 연산시키는 스펙큘러 다양성을 보여줌( 왜곡된 θh 공간에 저장된 것으로 보임 ).


이것은 데이터나 캡쳐 과정에 있어서 심각한 것은 아닙니다. 하지만 전체를 피팅하거나 해석할 때는 주의해야할 필요가 있습니다. 이것은 잠재적으로 왜 어떤 머티리얼들은 피팅하기 어려운가 라는 이전의 질문에 대한 답변의 일부가 되기도 합니다.


5 Disney "principled" BRDF


5.1 Principles


새로운 물리 기반 반사도 모델을 개발하는 도중에, 아티스트들은 우리에게 물리적으로 올바른 쉐이딩 모델이 아니라 아티스트가 손댈 수 있는 쉐이딩 모델이 필요하다고 이야기했습니다.  이 때문에 엄격하게 물리적인 것 보다는 "원칙을 지키는" 모델을 개발하자는 것이 우리의 철학이 되었습니다.


우리의 모델을 개발할 때 따라야만 한다고 결정한 원칙들이 있습니다:


    • 물리적인 파라미터들보다는 직관적인 파라미터들을 사용해야만 합니다.
    • 가능하면 적은 개수의 파라미터들만을 사용해야 합니다.
    • Parameters should be zero to one over their plausible range.
    • Parameters should be allowed to be pushed beyond their plausible range where it make sense.
    • 파라미터들에 대한 모든 조합은 견고해야 하며 가능하면 이치에 맞아야 합니다.


우리는 각 파라미터를 추가할 때 철저하게 회의를 했습니다. 최종적으로 1 개의 색상 파라미터와 10 개의 스칼라 파라미터를 결정했으며, 이에 대해서는 다음 섹션에서 설명할 것입니다.


5.2 Parameters


    • baseColor - 서피스 색상, 보통 텍스쳐 맵들에 의해 공급됨.
    • subsurface - subsurface 근사계산을 사용해 디퓨즈의 모양을 제어.
    • metallic - 금속성( metallic-ness ) ( 0 = 유전체, 1 = 금속 ). 서로 다른 모델들 간에 선형적으로 블렌딩됨. 금속 모델은 디퓨즈 성분을 가지지 않으며, baseColor 와 동일한 입사 스펙큘러에 의해 색조가 정해짐.
    • specular - 입사 스펙큘러의 양. 이는 명시적인 굴절률 대신에 사용됨.
    • specularTint - 입사 스펙큘러의 색조를 baseColor 처럼 만들기 위해서 아티스트가 제어할 수 있도록 양보한 것. 입사각 스펙큘러는 여전히 무색( achromatic )임.
    • roughness - 서피스의 겨칠기. 디퓨즈 반응과 스펙큘러 반응을 모두 제어함.
    • anisotropic - 비등방성의 정도. 이는 스펙큘러 하이라이트의 형상비( aspect ratio )를 제어함. ( 0 = 등방성, 1 = 최대 비등방성 ).
    • sheen - 부가적인 지표각 성분. 주로 옷을 위해서 사용됨.
    • sheenTint - sheen 색조를 baseColor 처럼 만들기 위한 양.
    • clearcoat - 이차적인 특별한 목적을 가진 스펙큘러 로브.
    • clearcoatGloss - clearcoat 의 광택을 제어함( 0 = "새틴( satin, 광택이 곱고 보드라운 견직물 )"의 외형, 1 = "윤기 있는( gloss )" 외형 ).
각각의 파라미터들을 적용해서 렌더링된 예가 그림 16 에 나와 있습니다.

그림 16: BRDF 파라미터들의 효과의 예.

각 행에서 파라미터들은 0 에서 1 까지 다양하며, 다른 파라미터들은 상수값임.


5.3 Diffuse model details


어떤 모델들은 다음과 같은 디퓨즈 프레넬 팩터를 포함합니다:



여기에서 F(θ)는 반사를 위한 프레넬 팩터입니다.


[주의: 반사를 위한 프레넬 법칙에서 Helmholtz reciprocity( 역주 : light 와 eye 의 위치를 바꿔도 같은 식이 성립한다는 법칙 ) 를 보존하기 위해서는 두 번의 굴절을 고려해야 합니다. 하나는 서피스로 들어 가는 것이고 다른 하나는 서피스에서 나오는 것입니다. ]


측정된 데이터 관측에서 봤듯이, 우리의 예전 스튜디오에서 경험했던 것에 의하면, 램버트의 디퓨즈 모델은 보통 가장자리에서 너무 어두워집니다. 그리고 그것을 좀 더 물리적으로 이치에 맞도록 만들기 위해 프레넬 팩터를 추가하게 되면 더 어두워집니다.


우리의 관측에 기반해서, 우리는 디퓨즈 retroreflection 을 위한 새롭고 실증적인 모델을 개발했습니다. 이것은 부드러운 서피스들을 위한 디퓨즈 프레넬 그림자와 거친 서피스를 위해 추가된 하이라이트 사이의 전이입니다. 이 효과에 대한 가능한 설명은 다음과 같습니다. 거친 서피스의 경우에 빛은 미세면에 들어 갔다가 측면으로 나오는데, 이는 지표각에서의 반사를 증가시킵니다. 아무튼 우리 아티스트들이 그것을 좋아합니다. 그리고 그것은 우리의 ad-hoc( 임기응변 ) 모델에서 사용했던 것과 유사한 특징을 가집니다. 이제는 그것이 더욱 이치에 맞고 물리에 기반했다는 것을 제외한다면 말이죠.


우리 모델에서, 우리는 디퓨즈 프레넬 팩터를 위한 굴절률을 무시했습니다. 그리고 입사 디퓨즈가 손실되는 경우는 없다고 가정했습니다. 이는 직접적으로 입사 디퓨즈 색상을 지정할 수 있도록 해 줍니다. 우리는 Schlick Fresnel approximation 을 사용하며 0 이 아니라 러프니스로부터 결정된 특정 값을 지표각 retroreflection 반응에 사용할 수 있도록 수정했습니다.


우리의 기본 디퓨즈 모델은 다음과 같습니다:



여기에서



입니다.


이것은 디퓨즈 프레넬 그림자를 생성하는데, 부드러운 서피스의 경우에는 지표각에서의 입사 디퓨즈 반사도를 0.5 만큼 줄이고, 거친 서피스의 경우에는 그 반응을 0.25 만큼 증가시킵니다. 이것은 MERL 데이터와의 합리적인 매칭을 제공하는 것으로 보이며, 아티스트들도 이에 대해 만족했습니다. 우리 모델에서 다양한 러프니스를 값을 가지고 테스트한 BRDF 이미지 슬라이스가 그림 17 에 나와 있습니다.


그림 17: 다양한 러프니스 값들에 대한 우리 모델의 BRDF 이미지 슬라이스들.


subsurface 파라미터는 기본 디퓨즈 모양과 Hanrahan-Krueger subsurface BRDF [11] 에서 영감을 받은 것의 모양을 블렌딩합니다. 이는 멀리 있는 오브젝트들과 평균 산란 경로 길이( scattering path length )가 작은 오브젝트 상에서의 subsurface 의 외형을 제공하는데 유용합니다; 그러나 이것이 full subsurface transport 를 수행하는 것을 대체하는 것은 아닙니다. 왜냐하면 그것은 그림자나 서피스를 통해 빛을 퍼지게( bleed )하지 않기 때문입니다.


5.4 Specular D details


대중적인 모델 중에서 GGX 가 가장 긴 테일을 가지고 있습니다. 이 모델은 사실 Blinn ( 1977 ) [6] 이 경험적인 데이터와의 매칭을 위해서 자주 사용한 Trowbridge-Reitz ( 1975 ) [31] 분산과 동일합니다. 그러나 이 분산은 여전히 많은 재질들을 위해 충분히 긴 테일을 가지고 있지 못합니다.


Trowbridge 와 Reitz 는 가루 유리( 젖빛 유리, ground glass )에 대한 측정값에 대해 자신들의 분산 함수와 몇 가지 다른 분산 함수들을 비교했습니다. 다른 분산들 중에 Berry ( 1923 ) 의 분산은 비슷한 형식을 가지고 있었지만, 지수( exponent )로 2 대신에 1 을 사용했으며 더 긴 테일을 산출했습니다. 이는 지수 변수를 사용하는 더 일반적인 분산을 제안하며, 그것은 dubbed Generalized-Trowbridge-Reitz 혹은 GTR 입니다:



이 개별 분산들에서, c 는 스케일링 상수이며, α 는 roughness 파라미터인데 값의 범위는 0 에서 1 입니다; α = 0 은 완전히 부드러운 분산( 즉, θh = 0 에서의 델타 함수 )을 생성하며 α = 1 은 완전히 거칠거나 고른 분산을 생성합니다.


그림 18: 다양한 γ 변수를 위한

 θh ( 역주 : 그림에서는 h 가 아니라 d 인데 왜인지 모르겠음 ) 에 대한 GTR 분산 커브.


Preliminary fitting results suggest typical value of γ between 1 and 2. 흥미롭게도 γ = 3/2 인 GTR 은 θ = 2θh 를 위한 Henyey-Greenstein 페이즈 함수와 동일합니다; θh 를 두배로 만들면 반구로부터의 분산을 구로부터의 분산으로 확장하는 것처럼 보일 수 있습니다.


이치에 맞는 미세면 분산은 반드시 정규화되어야만( normalized ) 합니다. 그리고 효율적인 렌더링을 위해 중요도 샘플링을 지원해야만 합니다. 둘다 분산이 반구상에서 적분될 것을 요구합니다. 운이 좋게도 이 함수는 simple closed-form integral 을 가집니다. 정규화 함수와 중요도 샘플링 함수, 그리고 효율적인 비등방성 형식을 유도하는 것은 부록 B 에 나와 있습니다.


우리의 BRDF 의 경우에, 우리는 두 개의 고정된 스펙큘러 로브를 사용하는데, 두 개다 GTR 모델을 사용합니다. 주 로브는 γ = 2 를 사용하며, 보조 로브는 γ = 1 을 사용합니다. 주 로브는 기반 재질을 표현하며 비등방성이거나 금속성일 수 있습니다. 보조 로브는 기반 재질 위의 clearcoat layer 를 표현하므로 항상 등방성이며 비금속입니다.


 roughness 의 경우에, 우리는 α 를 roughness2 로 매핑( mapping )하는 것이 좀 더 개념적으로 선형적인 변화를 산출한다는 것을 발견했습니다. 이 리매핑( remapping )이 없다면, 윤이 나는 재질들을 위해 요구되는 값들이 매우 작고 비직관적이 됩니다. 또한 거친 재질과 부드러운 재질을 보간하는 것이 항상 거친 결과를 산출하게 됩니다. 최종 보간은 그림 16 과 19 에 나와 있습니다.


그림 19: 매우 다른 두 개의 재질을 보간함. 윤이 나는 금색 금속과 파란 고무.


명시적인 굴절률( index of refraction, ior ) 대신에 사용하는 specular 파라미터는 입사 스펙큘러의 양을 결정합니다. 이 파라미터의 정규화된 범위는 입사 스펙큘러 범위인 [0.0, 0.08] 로 리매핑됩니다. 이것은 [1.0, 1.8] 범위의 ior 값과 연관되어 있는데, 이는 대부분의 재질을 포괄합니다. 특히, 파라미터 범위의 중간값은 1.5 인 ior 과 연관되며, 매우 일반적인 값이어서 우리는 이것을 기본값으로 사용합니다( 역주 : specular = 0.5 를 지정하면 ior = 1.5 가 된다는 의미). 이 specular 파라미터는 더 큰 ior 에 도달하기 위해서 범위를 넘어설 수 있지만, 주의깊게 사용해야만 합니다. 실세계의 반사도 값들이 너무 비직관적으로 낮습니다. 그래서 아티스트들이 납득할 수 있는 재질을 만드는 데 도움을 주기 위해서 이러한 파라미터 매핑을 사용합니다.


clearcoat layer 의 경우에, 우리는 ior 을 1.5 로 고정합니다. 이는 폴리우레탄( polyurethane )을 연상시키는데, 아티스트들은 clearcoat 파라미터를 사용해 레이어의 전체 강도를 스케일링할 수 있습니다. 정규화된 파라미터 범위는 [0, 0.25]의 전체 스케일링과 연관됩니다. 이 레이어는 큰 비주얼 임팩트를 가지고 있음에도 불구하고, 상대적으로 적은 양의 에너지를 표현합니다. 그래서 우리는 기반 레이어로부터 어떠한 에너지도 빼지 않습니다( 역주: 에너지 보존 법칙을 지키지 않는다는 의미인듯 ). 이 파라미터가 0 으로 설정되면 clearcoat layer 는 실질적으로 비활성화되며 아무런 비용도 소비하지 않습니다.


5.5 Specular F details


Schlick Fresnel approximation [28] 을 사용하는 것은 우리 목적에 충분히 부합하며, 완전한 프레넬 공식을 사용하는 것보다는 약간 더 단순합니다; 근사계산으로 인한 에러는 다른 팩터들 때문에 발생하는 에러에 비하면 거의 없는 거나 마찬가지입니다.



상수 F0 는 수직 입사시의 스펙큘러 반사도를 표현하며, 이는 유전체( dielectircs )를 위해서는 무채색( achromatic )이며 금속을 위해서는 유채색( chromatic, 즉 색조가 있는 )입니다. 실제 값은 굴절률에 의존하게 됩니다. 스펙큘러 반사는 미세면으로부터 기 때문에 F 는 빛 벡터와 미세면 노멀( 즉, 하프벡터 ) 사이의 각인 θd 에 의존하지 서피스 노멀과의 입사각에 의존하지는 않는다는 것에 주의하십시오.


프레넬 함수는 입사 스펙큘러 반사도와 지표각에서의 unity 를 ( 비선형적으로 ) 보간하는 것처럼 보일 수 있습니다. 그러한 반응은 모든 빛이 반사되는 지표각 입사에서는 무채색이 된다는 것에 주의하십시오.


5.6 Specular G details


우리 모델의 경우에, 우리는 하이브리드 접근법을 택했습니다. Smith 의 그림자 팩터가 주 스펙큘러를 위해서 사용될 수 있다는 점을 고려해 우리는 Walter 가 GGX 를 위해 유도한 G 를 사용합니다. 그러나 반짝거리는 서피스에서의 극단적인 gain 을 줄이기 위해서 roughness 를 리매핑했습니다. G 를 계산하기 위한 목적으로 [0, 1] 범위를 가지는 원래의 roughness 를 선형적으로 스케일링해서 [0.5, 1] 범위로 줄였습니다. 주의: 우리는 앞에서 설명했던 것과 같이 roughness 를 제곱하기 전에 이것을 수행합니다. 그렇기 때문에 최종 αg 값은 ( 0.5 + roughness/2)2 입니다.


이 리매핑은, 측정된 데이터와 우리의 데이터를 비교했을 때, 작은 러프니스 값을 가지는 경우에 스펙큘러가 "너무 세다"라는 피드백을 아티스트들로부터 받았기 때문에 수행되었습니다. 이는 러프니스에 따라서 다양한 결과를 내는 G 함수는 적어도 부분적으로는 물리에 기반한 것이며 이치에 맞는 것처럼 보입니다. clearcoat 스펙큘러의 경우에, 우리는 Smith G 유도를 가지지 않습니다. 그냥 GGX G 를 사용하는데 러프니스를 0.25 로 고정하게 됩니다. 이것이 가장 이치에 맞고 아티스트에게 만족감을 준다는 것을 발견했기 때문입니다.


5.7 Layering vs parameter blending


새로운 모델을 정착시키고 나서, 우리는 그것을 우리 쉐이더에 통합할 방법에 대해서 결정할 필요를 느꼈습니다. 첫 번째 질문은 공간적( spatial )으로 다양할 필요가 있는 파라미터들은 무엇인가였고, 그것에 대한 답은 전부다 였습니다; 만약 아티스트가 단순하게 서피스 상에 다양한 재질을 배치하고 그것들 사이에서 마스킹을 하는 것을 원했다면, 우리는 파라미터들을 전부 블렌딩할 필요가 있었을 것입니다. 또한 그 마스크는 필터링될 것이고, 마스크의 블러링된 가장자리들에서의 재질 반응은 반드시 이치에 맞아야 합니다.


모든 파라미터들을 정규화하고 개념적으로는 선형적이어야 한다는 우리의 설계 원칙의 이점은 재질들이 일반적으로 매우 직관적인 방식으로 보간된다는 것입니다. 이러한 예가 그림 19 에 나와 있습니다.


우리가 보간을 견고하게( robustly ) 수행할 수 있다는 것을 깨닫고 난 후에, 우리는 마스크를 통해 공간적 다양성을 획득할 수 있을지 여부가 궁금해졌습니다. 그 아이디어는 아티스트가 재질 프리셋의 리스트를 선택하고 나서 단순하게 텍스쳐 마스크를 사용해 그것들을 블렌딩하는 것입니다. 이는 현상적으로 성공적임이 밝혀졌으며, 작업과정을 매우 단순화시켜 주었으며, 재질의 일관성을 증진시켜주고, 쉐이더 평가( 역주: 실행의 관점에서 평가인듯. 성능과 관련한 이슈로 보임 )를 극단적으로 효율적으로 만들어 주었습니다. 우리의 쉐이더 UI 는 그림 20 에 나와 있습니다.


그림 20: 재질 레이어를 보여주는 우리 쉐이더 에디터에 대한 스크린 샷.

마스크 표현식 내의 변수들은 공간적으로 다양한 쉐이더 모듈( 일반적으로는 텍스쳐 맵 )을 참조합니다.


6 Production experience on Wreck-It Ralph


우리는 "원칙을 지킨 레이어들"의 쉐이더를 Wreck-It Ralph( 한국개봉명: 주먹왕 랄프 ) 에 적용했으며, 가상적으로는 헤어를 제외한 모든 재질들에 그 쉐이더를 사용했습니다( 헤어는 여전히 Tangled 를 위해 개발된 모델을 사용합니다 ). 다양한 재질들이 그림 21 에 나와 있습니다. 바닥, 카펫, 그리고 다른 입자로된 재질에서 반짝거리는 효과를 생성하기 위해, 스펙큘러 성분에 개별( seperate ) 노멀들이 사용되었다는 것에 주목하십시오.


새로운 재질 모델을 적용하면서, 새로운 sampled area light 와 멋지게 보이는 이치에 맞는 재질들을 만드는데 있어 중요한 IBL 도 소개되었습니다; 만약 여러분이 이치에 맞는 반짝이는 재질을 만들었는데 점광원을 거기에 비추게 된다면, 여러분의 하이라이트는 매우 작은 점으로 보이게 될 것입니다. 그러면 라이트 작업자들은 에어리어 광원에 대한 응답인 것처럼 속이기 위해서 러프니스 값을 올리게 될 것입니다. 그리고 이는 전체적인 물리 기반 쉐이딩 패러다임을 해치게 됩니다. 좋은 소식은 라이트 작업자들이 자신들의 ( 역주 : 빛에 대한 ) 지배력을 높이기 위해서 에어리어 광원과 IBL 을 사용하는 것을 좋아한다는 것입니다. It's also worth nothing that the new material model was both a motivator and an enabler in the switch to sampled lights in that with our previous ad-hoc shading model it world have been to expensive for each reflectance module to perform its own sampled light integration.


Wreck-It Ralph 에서의 성공에 힘입어, 우리의 다음 쇼에서는 새로운 쉐이딩 모델을 수정하지 않고 사용할 계획이며, 이미 사용하고 있기도 합니다.


그림 21: Wreck-It Ralph 의 프로덕션 스틸.


6.1 Look development


단일 BRDF 를 모든 곳에 적용하는 것의 이점은 그것이 재질 에디터의 개발을 단순화해 준다는 것입니다. 우리 "Material Designer" 는 노멀, 오브젝트 ID, 재질 레이어 마스크를 포함하는 g-buffer 를 렌더링합니다. 이러한 채널들을 사용해서 image-based relighting 을 빠르게 수행하면서 모든 BRDF 파라미터를 실시간에( interactively ) 편집할 수 있습니다. 아티스트들은 실시간에 IBL 을 회전시켜서 프로덕션 모델의 전체 문맥에서 모든 파라미터들과 레이어들의 전체 효과를 확인할 수 있습니다.


통합된 모델을 사용하는 것의 다른 이점은 그것이 Material Designer 로부터 저장된 프리셋 집합들로 구성된 매우 단순한 재질 라이브러리를 만들 수 있도록 해 준다는 것입니다. 재질을 라이브러리에서 가져올 수 있으며, 쉐이더를 부가적인 레이어로 추가하고, 마스크를 사용해서 블렌딩할 수 있습니다. 그러므로 Photoshop 의 레이어 스택처럼 레이어를 빠르게 만들 수 있습니다.


재질을 완전하게 평가하기 위해서는 모든 각도에서 빛을 비춰보는 것이 중요합니다. 새로운 재질 모델로 전환하는 것의 일부로서, 우리는 다양한 IBL 을 사용하는 모든 요소들을 검증하기 시작했으며, 모든 턴테이블( turntable )들은 요소 회전과 라이팅 회전을 모두 포함합니다( 역주 : 3D 뷰어에서 빛이나 모델을 돌려볼 수 있음을 의미하는 듯 ).


새로운 쉐이더 시스템을 적용하고 나서 look development 의 생산성이 매우 향상되었으며, 새로운 아티스트들을 교육하는 시간이 훨씬 단축되었고, 더 일관성있게 고품질의 결과를 산출할 수 있게 되었습니다. Notably, most of our look development were able to roll off of the show early due to the lack of the need for material re-do's in lighting. 이는 전례없는 일이었습니다.


6.2 Lighting


앞에서 언급했듯이, 새로운 재질 모델을 사용해서 작업을 하기 위해서는 라이팅에 대한 다양한 접근이 필요했습니다. 이는 큰 학습 곡선을 필요로 했습니다. 또한 물리 기반 모델에 대해 전체적인 타협을 하지 않고서 라이팅에 대한 아티스트의 제어를 추가하는 것은 도전이었습니다.


라이팅에 있어 가장 큰 변화는 IBL 을 로컬 필라이트( local fill light )로 사용하는 것이었습니다. Most IBLs are used with light linking to specific elements in the shot and many have distance cutoffs. 이것들은 재질의 특성들을 대부분 무시해 버리는 이전의 환경맵들에 비하면 클 발전을 포함했습니다. Area lights were also a well received addition.


라이트 작업자들( lighters )에게 있어 가장 큰 도전은 사실적인 빛 인텐서티( intensity ) 값과 폴오프( falloff )를 사용해서 작업하는 것이었습니다. 결국 우리는 비물리 폴오프 컨트롤을 개발했습니다. 주어진 거리에서 원하는 노출을 획득하기 위해서 자동으로 인텐서티를 조절하면서 광원을 가상적으로 더 멀리 떨어져 있게 만드는 것입니다. 하지만 빛의 인텐서티와 폴오프를 제어하는 것은 라이트 작업자에게는 도전으로 남아 있습니다.


라이팅과 관련한 또 다른 도전은 스펙큘러 하이라이트가 이제 톤 매핑( tone mapping )을 요구하게 된다는 사실입니다. 빛나는 재질상의 하이라이트는 수백개나 될 수 있으며, 값을 단순하게 클리핑( clip )하는 것은 차갑게( harsh ) 보일 수 있으며, 다양한 위치에서 각 색상 채널이 클리핑되므로 밴딩이 나타날 수 있으며, 중심부( core )는 항상 하얗게 나오도록 강제될 수 이습니다. 우리는 새로운 글로벌 톤 매핑 연ㅅ나자를 개발했는데, 이는 대부분의 가시 영역을 위한 값을 보존하고 색상과 대비를 유지하면서 최대값( top end )를 끌어 내립니다. 우리는 기본 설정을 가지고 있는데, 이것은 대부분의 경우에 합리적으로 동작하지만 color grading 을 하는 샷( shot )에서는 최종값을 조절합니다.


In the end though, the materials behave predictably which is a huge benefit to lighters and gives them a starting place that is physically plausible.


6.3 Future work


현재 가장 큰 이슈는 직관적으로 제어할 수 있는 subsurface 모델이 부족하다는 것입니다. 이것의 핵심 관점은 BRDF 통합입니다. 이상적으로 보면 BRDF 와 subsurface 모델 사이의 일치점은 존재할 것입니다. 먼 거리의 오브젝트들을 위해서 BRDF 가 사용될 수 있으며 동일한 결과를 산출하게 됩니다. 또한 전체적인 노출을 변경하지 않은 상태에서 subsurface 효과를 오브젝트에 추가하기 위해 아티스트들은 mean-free path 를 0 에서부터 증가시켜야 합니다 - 디퓨즈의 모양만 변해야 합니다( 그리고 diffusion 이 가능하다면 빛은 그림자로 스며들어야( bleed ) 합니다 ).


우리는 옷감의 반사도를 모델링하고자 합니다. 우리는 특별히 복잡한 옷감 모델을 위한 반사도 데이터를 캡쳐함으로써 옷감을 렌더링하기 위한 특별한 쉐이더를 추가할 수 있다는 것을 알고 있습니다. 하지만 다양한 범위의 옷감 재질을 직접적으로 모델링하는 방법에 대해서 연구하고자 합니다. 현재로서는 이 필요성을 충족시켜 줄 수 있는 보여줄 만한 것이 없습니다.


또한 우리 모델에 무지개빛( iridescence )을 추가하라는 요청을 받은 상태입니다. 이전에 언급했던 것처럼 이는 스펙큘러 색상 변조를 추가하는 것만큼 단순합니다.


Acnowledgements


먼저 무엇보다, Chunk Tappan 에게 감사드리고 싶습니다. 그는 새롭게 재질을 파라미터화하기 위해 공동작업을 했으며, 새로운 look development 파이프라인의 선두에 있었습니다. 또한 Christian Eisenacher 에게도 감사드립니다. 그는 Material Designer 작업을 했습니다. Disney BRDF Viewer 작업을 한 Greg Nichols 와 Jared Johnson 에게도 감사드립니다. 그리고 인내심을 가지고 지원해 준 Ralph Look 과 Lighting 팀에게도 감사드리고 싶습니다. 마지막으로 Stephen Hill, Naty Hoffman, 그리고 Pete Shirley 에게 감사드리고 싶습니다. 그들은 소중한 입력( input, 입력 데이터? )을 제공했으며, 특히 Stephen 은 부록 B 의 식 ( 14 ) 에서 projected half-vector 공식을 제안해 주었습니다.


References


[1] Michael Ashikhmin. Distribution-based brdfs. Technical report, 2007.


[2] Michael Ashikhmin, Simon Premoze, and Peter Shirley. A Microfacet-Based BRDF generator. In Sheila Homeyer, editor, Proceedings of the Computer Graphics Conference 2000 (SIGGRAPH-00), pages 65{74, New York, July 23{28 2000. ACMPress.


[3] Michael Ashikhmin and Peter Shirley. An anisotropic Phong BRDF model. Journal of Graphics Tools: JGT, 5(2):25{32, 2000.


[4] M. M. Bagher, C. Soler, and N. Holzschuch. Accurate tting of measured reflectances using a shifted gamma micro-facet distribution. Computer Graphics Forum, 31(4):1509{1518, 2012.


[5] P. Beckmann and A. Spizzichino. The scattering of electromagnetic waves from rough surfaces. MacMillan, 1963.


[6] James F. Blinn. Models of light reflection for computer synthesized pictures. volume 11, pages 192{198, July 1977.


[7] R. L. Cook and K. E. Torrance. A reflectance model for computer graphics. Computer Graphics, 15(3):307{316, 1981.


[8] Arne Dur. An improved normalization for the Ward reflectance model. Journal of graphics, gpu, and game tools, 11(1):51{59, 2006.


[9] Dave Edwards, Solomon Boulos, Jared Johnson, Peter Shirley, Michael Ashikhmin, Michael Stark, and Chris Wyman. The halfway vector disk for brdf modeling. ACM Trans. Graph., 25(1):1{18, January 2006.


[10] David Geisler-Moroder and Arne Dur. A new Ward BRDF model with bounded albedo. Comput. Graph. Forum, 29(4):1391{1398, 2010.


[11] Pat Hanrahan and Wolfgang Krueger. Reflection from layered surfaces due to subsurface scattering. In Proceedings of the 20th annual conference on Computer graphics and interactive techniques, SIGGRAPH '93, pages 165{174, New York, NY, USA, 1993. ACM.


[12] Xiao D. He, Kenneth E. Torrance, Francois X. Sillion, and Donald P. Greenberg. A Comprehensive Physical Model for Light Re

ection. In Computer Graphics (ACM SIGGRAPH '91 Proceedings), volume 25, pages 175{186, July 1991.


[13] Csaba Kelemen, Laszlo Szirmay-Kalos, and Laszlo Szirmay-kalos. A microfacet based coupled specular-matte brdf model with importance sampling. Eurographics Short Presentations, 2001.


[14] Murat Kurt, Laszlo Szirmay-Kalos, and Jaroslav Krivanek. An anisotropic brdf model for fitting and monte carlo rendering. SIGGRAPH Comput. Graph., 44(1):3:1{3:15, February 2010.


[15] Eric P. Lafortune, Sing-Choong Foo, Kenneth E. Torrance, and Donald P. Greenberg. Nonlinear approximation of reflectance functions. In Computer Graphics (ACM SIGGRAPH '97 Proceedings), volume 31, pages 117{126, 1997.


[16] Robert R. Lewis. Making Shaders More Physically Plausible. In Fourth Eurographics Workshop on Rendering, number Series EG 93 RW, pages 47{62, Paris, France, June 1993.


[17] Joakim Low, Joel Kronander, Anders Ynnerman, and Jonas Unger. Brdf models for accurate and efficient rendering of glossy surfaces. ACM Trans. Graph., 31(1):9:1{9:14, February 2012.


[18] Wojciech Matusik, Hanspeter Pster, Matt Brand, and Leonard McMillan. A data-driven reflectance model. ACM Transactions on Graphics, 22(3):759{769, July 2003.


[19] Laszlo Neumann, Attila Neumann, and Laszlo Szirmay-Kalos. Compact metallic reflectance models. Computer Graphics Forum, 18(3):161{172, September 1999. ISSN 1067-7055.


[20] Laszlo Neumann, Attila Neumann, and Laszlo Szirmay-Kalos. Reflectance models by pumping up the albedo function. In Machine Graphics and Vision, pages 3{18, 1999.


[21] Addy Ngan, Fredo Durand, and Wojciech Matusik. Experimental analysis of BRDF models. In Kavita Bala and Philip Dutre, editors, Eurographics Symposium on Rendering, pages 117{126, Konstanz, Germany, 2005. Eurographics Association.


[22] Ko Nishino and Stephen Lombardi. Directional statistics-based reflectance model for isotropic bidirectional reflectance distribution functions. J. Opt. Soc. Am. A, 28(1):8{18, Jan 2011.


[23] Michael Oren and Shree K. Nayar. Generalization of lambert's reflectance model. In SIGGRAPH, pages 239{246. ACM, 1994.


[24] Romain Pacanowski, Oliver Salazar Celis, Christophe Schlick, Xavier Granier, Pierre Poulin, and Annie Cuyt. Rational brdf. IEEE Transactions on Visualization and Computer Graphics, 99(PrePrints), 2012.


[25] Bui-T. Phong. Illumination for computer generated pictures. Communications of the ACM, 18(6):311{317, June 1975.


[26] Fabiano Romeiro, Yuriy Vasilyev, and Todd Zickler. Passive reflectometry. In Proceedings of the 10th European Conference on Computer Vision: Part IV, ECCV '08, pages 859{872, Berlin, Heidelberg, 2008. Springer-Verlag.


[27] Iman Sadeghi, Heather Pritchett, Henrik Wann Jensen, and Rasmus Tamstorf. An artist friendly hair shading system. In ACM SIGGRAPH 2010 papers, SIGGRAPH '10, pages 56:1{56:10, New York, NY, USA, 2010. ACM.


[28] Christophe Schlick. An Inexpensive BRDF Model for Physically-Based Rendering. Computer Graphics Forum, 13(3):233{246, 1994.


[29] B. Smith. Geometrical shadowing of a random rough surface. IEEE Trans. Ant. and Propagation, AP-15(5):668{671, September 1967.


[30] K. Torrance and E. Sparrow. Theory for o-specular reflection from roughened surfaces. J. Optical Soc. America, 57:1105{1114, 1967.


[31] S. Trowbridge and K. P. Reitz. Average irregularity representation of a rough ray reflection. Journal of the Optical Society of America, 65(5):531{536, May 1975.


[32] Bruce Walter. Notes on the Ward BRDF. Technical Report PCG-05-06, Cornell Program of Computer Graphics, 2005.


[33] Bruce Walter, Stephen R. Marschner, Hongsong Li, and Kenneth E. Torrance. Microfacet models for refraction through rough surfaces. In Proceedings of the Eurographics Symposium on Rendering, 2007.


[34] Gregory J. Ward. Measuring and modeling anisotropic reflection. In Edwin E. Catmull, editor, Computer Graphics (SIGGRAPH '92 Proceedings), volume 26, pages 265{272, July 1992.


[35] L. B. Wol, S. K. Nayar, and M. Oren. Improved diuse reflection models for computer vision. International Journal of Computer Vision, 30(1):55{71, October 1998.


Appendix A: Selected of BRDF models used in graphics


생략 : 원문 참조.


Appendix B: GTR Microfacet Distribution


생략 : 원문 참조.


원문 : http://graphics.pixar.com/library/ReflectanceModel/paper.pdf

주의 : 번역이 개판이므로 이상하면 원문을 참조하십시오.

주의 : 허락받고 번역한 것이 아니므로 언제든 내려갈 수 있습니다.


 

A Reflectance Model for Computer Graphics

 

ROBERT L. COOK

Lucasfilm Ltd.

and

KENNETH E. TORRANCE

Cornell University


 

컴퓨터 합성 이미지를 위한 새로운 반사도 모델이 제시됩니다. 이 모델은 같은 장면 내의 다양한 재질과 광원의 상대적인 밝기를 고려합니다. 이는 입사각과 함께 반사도가 변경될 때마다 발생하는 반사되는 빛의 지향성 분포( directional distribution )와 색상 변화에 대해 기술합니다. 특정한 실제 재질로 구성된 오브젝트로부터 반사광의 스펙트럼 에너지 분포( spectral energy distribution )를 획득하기 위한 기법이 제시되며, 스펙트럼 에너지 분포와 관련된 색상을 정확하게 복제하기 위한 방법이 논의됩니다. 이 모델은 금속과 플라스틱의 시뮬레이션에 적용됩니다.

 

Categories and Subject Descriptors: I.3.7 [Computer Graphics]: Three-Dimensional Graphics and Realism--color, shading, shadowing, and texture

 

General Terms: Algorithms

 

Additional Key Words and Phrases: image synthesis, relfectance

 


 

INTRODUCTION

 

컴퓨터 그래픽스에서 사실적인 이미지를 렌더링하는 것은 오브젝트가 빛을 반사하는 방법에 대한 모델을 요구합니다. 반사도( reflectance ) 모델은 반사되는 빛의 색상 및 공간적 분포를 설명해야만 합니다. 이 모델은 surface geometry representation 과 hidden surface algorithm 과 같은 이미지 합성의 다른 관점들과는 독립적입니다.

 

대부분의 실제 서피스들은 이상적인 스펙큘러( 거울같은 ) 반사체나 이상적인 디퓨즈( 램버시안, Lambertian ) 반사체가 아닙니다. Phong [14, 15 ] 은 컴퓨터 그래픽스를 위한 반사도 모델을 제안했는데, 이는 스펙큘러 반사와 디퓨즈 반사에 대한 선형 결합( linear combination )입니다. 스펙큘러 요소는 power 로 증가하는 코사인( cosine ) 함수를 사용함으로써 스펙큘러 방향 주변에서 퍼집니다. 그 다음에 Blinn [5, 6] 은 [23] 의 스펙큘러 반사 모델과 유사한 아이디어를 사용했는데, 이는 서피스 노멀( normal )에 대해 상대적인 지표각( grazing angle )에서 빛이 입사할 때 발생하는 off-specular peaks 를 고려합니다( 역주 : off-specular peak 는 입사각과 반사각이 다른 specular 를 의미합니다. 번역이기는 하지만 원문에는 없는 그림을 추가합니다. 그림 R1 참조 ). Witted [24] 는 완전히 부드러운 서피스( surface )로부터의 이상적인 스펙큘러 반사를 위한 항을 추가함으로써 이 모델들을 확장했습니다( 역주 : Witted Ray Tracing 으로 검색 ). 이러한 모든 모델들은 geometrical optics( ray theory )에 기반합니다.

 

그림 R1: Off-specular reflection 의 예: 지표각에 가까워질 수록 specular 의 방향( M ) 이 반사각과 달라지는 모습을 보여줌.

 

앞에서 말한 모델들은 반사를 세 가지 요소로 구성된 것으로 취급합니다: 앰비언트( ambient ), 디퓨즈( diffuse ), 스펙큘러( specular ). 앰비언트 요소는 환경으로부터 고르게 입사해서 서피스에 의해 모든 방향으로 동일하게 반사한다고 가정하는 빛을 표현합니다. 디퓨즈 성분과 스펙큘러 성분은 특정 광원으로부터 오는 빛과 관련이 있습니다. 디퓨트 성분은 모든 방향으로 동일하게 산란하는 빛을 표현합니다. 스펙큘러 성분은 하이라이트( highlight )를 표현하는데, 빛이 미러 방향 주변에 집중되어 있습니다. 스펙큘러 요소는 광원의 색상으로 간주되었습니다; Fresnel 공식은 각도 별로 다양해지는 스펙큘러 인텐서티( intensity )를 획득하기 위해서 사용되었지만, 색상에 대한 것이 아닙니다. 앰비언트 요소와 디퓨즈 요소는 재질의 색상으로 간주되었습니다. 최종 모델은 즉정 유형의 재질에 대해 사실적인 모양을 보여주는 이미지를 산출합니다.

 

이 논문은 이전 모델들보다 더 일반적인 거친 서피스를 위한 반사도 모델을 제시합니다. 이는 geometrical optics 에 기반하며, 다양한 범위의 재질들, 서피스 조건들, 라이팅 상황들에 적용할 수 있습니다. 이 모델의 중심은 반사율에 대한 정의인데, 이는 광원의 인텐서티와 사이즈에 대한 오브젝트의 밝기와 관련이 있습니다. 이 모델은 반사되는 빛에 대한 지향성 분포( directional distribution )와 스펙트럼 조합( spectral composition )을 예측합니다. 스펙트럼 에너지 분포로부터의 RGB 값을 계산하는 방법에 대해 기술합니다. 새로운 반사도 모델은 금속과 플라스틱의 시뮬레이션에 적용되는데, 이전의 모델들을 사용해서 렌더링된 이미지들이 종종 플라스틱처럼 보이는 이유에 대해서 설명하고, 이 플라스틱 외형을 피할 수 있는 방법에 대해 설명합니다.

 

THE REFLECTANCE MODEL

 

광원, 서피스, 관찰자가 주어질 때, 반사도 모델은 관찰자에게 도달하는 반사광의 인텐서티와 스펙트럼 조합에 대해 기술합니다. 반사광의 인텐서티는 광원의 인텐서티와 사이즈, 그리고 재질의 반사 능력과 서피스 특성에 의해 결정됩니다. 반사광의 스펙트럼 조합은 광원의 스펙트럼 조합과 서피스의 파장 선별 반사( wavelength-selective reflection, 역주 : 우리가 알고 있는 albedo 를 의미하는 듯함 )에 의해 결정됩니다. 이 섹션에서는 적절한 반사도 정의를 소개하고 그것을 일반적인 반사도 모델과 결합시킬 것입니다. 그림 1 은 이 모델에서 사용되는 심볼들에 대한 요약을 포함합니다.

 

그림 1: 심볼 요약.

 

그림 2에는 반사에 대한 기하학적 구조가 나와 있습니다. 관찰자는 서피스상의 점 P 를 바라보고 있습니다. V 는 관찰자 방향에 대한 단위 벡터입니다. N 은 서피스의 단위 노멀입니다. L 은 지정된 광원 방향의 유닛 벡터입니다. HV L 사이의 각을 이등분한 곳의 정규화된 벡터입니다. H 는 다음과 같이 정의됩니다.

 

 

이것은 광원에서 관찰자를 향해 거울같이 빛을 반사하는 가상의 서피스에 대한 단위 노멀입니다. α 는 H 와 N 사이의 각도이며, θ 는 H 와 V 사이의 각도입니다. 그래서 cos(θ) = V˙H = L˙H 입니다.

 

그림 2: 반사의 기하구조.

 

빛의 입사빔( beam )의 에너지는 단위 시간과 반사하는 서피스의 단위 면적 당 에너지로 표현됩니다. 입사광의 인텐서티는 이와 유사하지만, 단위 사영 면적과 단위 입체각에 대해서 표현됩니다 [20, 8]. ( 입체각은 광원의 사영된 면적을 광원으로부터의 거리의 제곱으로 나눈 것이며, 멀리 있는 광원을 위한 상수로 취급될 수 있습니다. ) 입사광에서의 에너지는 다음과 같습니다.

 

 

거울이나 거울에 가까운 것들을 제외하고, 입사빔은 광범위한 각도로 반사됩니다. 이런 이유로, 주어진 방향에서의 반사 인텐서티는 입사 인텐서티뿐만 아니라 입사 에너지에도 의존하게 됩니다. ( 작은 입체각 내의 ) 다른 방향으로부터의 입사 에너지에 대한 주어진 방향에서의 반사 인텐서티의 비율은 양방향 반사도( bidirectional reflectance )라 불립니다. 이 반사율은 반사 연구에 있어서 기본입니다( 부가적인 논의에 대해 알려면 [20, 8]을 참조하십시오 ). 각 광원에 대해, 양방향 반사도 R 은 다음과 같습니다.

 

 

각 광원으로부터 관찰자에게 도달하는 반사 인텐서티는 다음과 같습니다.

 

 

양방향 반사도는 두 개의 요소로 분리될 수 있습니다; 스펙큘러, 디퓨즈. 스펙큘러 요소는 재질의 표면으로부터 반사되는 빛을 표현합니다. 디퓨즈 요소는 ( 재질의 서피스 안으로 파고든 입사광에 의해 발생하는 ) 내부 산란이나 ( 서피스가 충분히 거칠면 발생하는 ) 다중 서피스 반사로부터 기인합니다. 만약 재질이 균질하지 않다면 스펙큘러 요소와 디퓨즈 요소는 서로 다른 색상을 가질 수 있습니다. 그래서 양방향 반사도는 다음과 같습니다.

 

 

개별 광원에 의한 직접 조명과 더불어, 오브젝트는 배경이나 앰비언트 조명에 의해 조명을 받을 수 있습니다. 특정 광원으로부터 직접 비춰지는 것이 아닌 모든 빛은 앰비언트 조명으로 뭉뚱그려집니다. 앰비언트 조명의 특정 방향으로부터 관찰자를 향해 반사되는 빛의 양은 적지만, 전체 반구상에서 오는 빛을 합치면 이것의 효과는 커집니다. 따라서, 앰비언트( 혹은 hemispherical-directional ) 반사 Ra 를 소개하는 것이 편리합니다. 이 반사는 양방향 반사도 R 의 적분이며, 즉 Rs 와 Rd 의 선형결합입니다. 단순함을 위해, 우리는 Ra 가 뷰 방향에 대해 독립적이라 가정합니다. 추가적으로 우리는 앰비언트 조명이 고르게 입사한다고 가정합니다. 앰비언트 조명 때문에 생기는 반사 인텐서티는 다음과 같이 정의됩니다.

 

 

f 항은 ( 코너와 같은 ) 근처에 있는 오브젝트들에 의해 차폐되지 않는 조명을 비추는 반구의 양( fraction, 비율? )입니다 [25]. 이는 다음과 같이 주어집니다.

 

 

여기에서 적분은 빛을 비추는 반구의 비차폐 영역에 대해서 수행됩니다.

 

관찰자에게 도달하는 빛의 전체 인텐서티는 모든 광원으로부터의 반사 인텐서티의 합에 모든 앰비언트 조명으로부터의 반사 인텐서티를 더한 것입니다. f = 1 이라고 가정하면, 이 논문에서 사용된 기본 반사도 모델은 다음과 같습니다.

 

 

이 공식은 씬에 조명을 비추는 서로 다른 인텐서티와 사영 면적을 가진 광원들의 효과를 고려합니다. 예를 들어, 어떤 조명빔( illuminating beam )과 동일한 인텐서티( Ii )와 조명 각( N˙L )을 가지지만 두 배 큰 입체각( dωi )을 가진 조명빔은 서피스를 두 배 밝게 만듭니다. 다른 빔보다 두 배의 인텐서티를 가지지만 같은 조명각과 입체각을 가진 조명빔도 서피스를 두 배 밝게 만듭니다.

 

이 논문은 환경 내의 다른 오브젝트들로부터 오는 빛에 대한 반사를 고려하지 않습니다. 이 반사는 서피스가 완전히 부드럽다면 [24] 나 [6] 에서처럼 계산될 수 있습니다. 하지만 이러한 순수한 거울면 반사라하더라도 파장에는 종속적입니다.

 

위의 반사도 모델은 묵시적으로 몇 가지 변수들에 의존합니다. 예를 들어, 인텐서티는 파장에 의존하며, s 와 d 는 재질에 의존하며, 반사도는 이런 변수들과 함께 반사 기하구조 및 서피스 러프니스( roughness )에 의존합니다. 다음 두 섹션들은 반사도 모델의 지향성 의존 및 파장 의존을 고려합니다.

 

DIRECTIONAL DISTRIBUTION OF THE REFLECTED LIGHT

 

앰비언트 및 디퓨트 요소들은 모든 방향으로 동일하게 빛을 반사합니다. 그러므로 Ra 와 Rd 는 관찰자의 위치에 의존하지 않습니다. 반대로 스펙큘러 요소는 다른 것보다 특정 방향으로 더 많은 빛을 반사합니다. 그래서 Rs 는 관찰자의 위치에 의존합니다.

 

스펙큘러 요소가 각에 따라 퍼지는 것은 서피스가 미세면( microfacet )으로 구성되었고 각 미세면들은 거울면 반사를 수행한다는 가정에 의해 설명됩니다 [23]. 노멀이 H 방향인 미세면만이 L 에서 V 로의 반사에 대한 스펙큘러 요소에 기여합니다. 이 스펙큘러 요소는 다음과 같습니다.

 

 

프레넬( Fresnel ) 항 F 는 빛이 부드러운 미세면으로부터 반사되는 방식을 설명합니다. 그것은 입사각과 파장에 대한 함수이며, 다음 섹션에서 설명됩니다. 기하학적 감쇠( geometrical attenuation ) 요소 G 는 다른 미세면에 의해 그림자가 드리워지거나 마스킹되는 미세면을 고려합니다. 그리고 이는 [5, 6, 23 ] 에 세부적으로 설명되어 있습니다. 간단하게 말하자면, 그것은 다음과 같습니다.

 

 

미세면의 기울기 분포 함수 D 는 H 방향을 바라보는 미세면들의 양( fraction )을 표현합니다. Blinn [5, 6]에 의해 다양한 미세면 기울기 분포 함수들이 고려되었습니다. 그가 기술한 공식 중 하나는 Gaussian 모델입니다 [23].

 

 

여기에서 c 는 임의의 상수입니다.

 

Blinn 에 의해 언급된 것과 더불어, 다른 미세면 기울기 분산 모델들을 이용하는 것도 가능합니다. 특히 서피스로부터의 적외선과 레이더 산란( scattering of radar )을 위한 모델들을 이용할 수 있으며, 그것들은 가시 파장들에 적용될 수 있습니다. 예를 들어 Davies [9] 는 완벽한 전도체로 구성된 거친 표면으로부터 반사되는 전자기 복사의 공간적 분포에 대해 기술했습니다. Bennett 와 Porteus [3] 는 이 결과를 실제 금속에 대해 확장했으며, Torrance 와 Sparrow [22] 는 그것들이 비금속에도 적용됨을 보여주었습니다. Beckmann [2] 은 이러한 모든 재질들을 망라하는 포괄적인 이론을 제공했으며, 이는 부드러운 표면으로부터 매우 거친 표면까지를 포함하는 넓은 범위의 서피스 상태들에 적용됩니다. 거친 서피스의 경우, Beckmann 분포 함수는 다음과 같습니다.

 

 

이 분포 함수는 Blinn 에 의해 언급된 세 가지 함수와 그 형태가 비슷합니다. Beckmann 함수의 이점은 임의의 상수를 사용하지 않고도 반사도의 절대량을 제공한다는 것입니다; 단점은 그것이 더 많은 계산을 요구한다는 것입니다.

 

모든 미세면 기울기 분포 함수 내에서 스펙큘러 요소의 퍼짐( spread )은 root mean square ( rms ) 기울기 m 에 의존합니다. 작은 m 값은 미세면 기울기가 작다는 것을 의미하며 반사 각도 주변에서 매우 지향성있는 분포를 제공합니다. 이는 그림 3 에 나와 있는데요, 3a 는 Beckmann 분포 모델이고 3b 는 Gaussian 모델입니다. 큰 m 값은 뾰족한 미세면 기울기를 나타내는데 퍼져나가는 형태의 분포를 제공합니다. 3c3d 는 각각 Beckmann 과 Gaussian 모델을 보여줍니다. 두 모델의 유사성에 주목하십시오.

 

그림 3: (a) Beckmann 분포 m = 0.2, (b) Gaussian 분포 m = 0.2,

(c) Beckmann 분포 m = 0.6, (d) Gaussian 분포 m = 0.6.

 

SPECULAR COMPOSITION OF THE REFLECTED LIGHT

 

앰비언트, 디퓨즈, 스펙큘러 반사도는 모두 Ra, Rd, Rs 의 F 항에 의존하는데, 이것들은 재질의 적절한 반사도 스펙트럼들에서 획득될 수 있습니다. Ra 가 Rs 와 Rd 의 선형 결합으로 제한됨에도 불구하고 비균일한 재질은 세 반사도 각각에 대한 서로 다른 반사도 스펙트럼들을 가집니다.

 

[10, 17-19] 에서 수 천개의 재질들을 위한 반사도 스펙트럼들이 측정되고 수집되어 왔습니다. 반사도 데이터는 보통 수직 입사( normal incidence )에서의 조명에 대한 것입니다. 이 값들은 보통 연마된 서피스들을 위해 측정되었으며, 거친 서피스를 위한 양방향 반사도를 획득하기 위해서는 1/π 를 곱해야만 합니다 [20]. 대부분의 재질들은 가시범위 내의 적은 개수( 10 ~ 15 )의 파장들에서만 측정되었습니다. 그래서 중간의 파장들을 위한 값들은 보간되어야만 합니다( 간단한 선형 보간으로도 충분한 것으로 보입니다 ). 수직 입사를 위한 구리 거울의 가시 파장을 위한 반사도 스펙트럼은 그림 4a 에 나와 있습니다. 반사도 스펙트럼을 선택하는데 있어, 주의깊게 고려해야 할 것은 어떤 조건에서 측정이 이루어졌느냐 입니다. 예를 들어 어떤 금속들은 시간을 두고 산화막을 만들수 있는데, 이는 색상을 급격하게 변화시킵니다 [1].

 

반사광의 스펙트럼 에너지 분포( spectral energy distribution )는 입사광의 스펙트럼 에너지 분포에 서피스의 반사도 스펙트럼을 곱함으로써 구해집니다. 이것의 예가 그림 4b 에 나와 있습니다. 태양의 스펙트럼 에너지 분포와 CIE( 국제 조명 위원회 ) 표준 빛( standard illuminants )은 [7]에서 이용할 수 있습니다. CIE 표준 빛 D6500 의 스펙트럼 에너지 분포는 구름낀 날의 태양빛을 근사계산한 것으로, 이는 그림 4b 의 위쪽 커브입니다. 아래쪽 커브는 CIE 표준 빛 D6500 을 수직 입사했을 때 구리 거울로부터 반사된 빛의 스펙트럼 에너지 분포를 보여 줍니다. 이것은 그림 4a 의 반사도 스펙트럼에다가 위쪽 커브를 곱함으로써 획득된 것입니다.

 

그림 4: (a) 수직 입사에 대한 구리 거울에 대한 반사도. 파장의 단위는 micrometer.

(b) 위쪽 커브: CIE 표준 빛 D6500 의 스펙트럼 에너지 분포.

아래쪽 커브: D6500 에 의해 비춰지는 구리 거울로부터 반사된 빛의 스펙트럼 에너지 분포.

 

 

일반적으로, Rd 와 F 는 반사 기하구조에 따라 다양해집니다. 편의를 위해, 우리는 반사하는 서피스에 대한 노멀 방향으로 비추기 위한 양방향 반사도로 Rd 를 취합니다. 이는 합리적입니다. 왜냐하면 서피스 노멀에 대해 70 도 정도 안쪽에서는 반사도가 입사각에 대해 약간만 변하기 때문입니다 [21]. 우리는 F 에 대한 지향성 의존성( directional dependence )을 허용합니다. 그러나 이는 입사 방향과 반사 방향이 지표각 근처에 있을 때 색상 변화를 일으킵니다.

 

반사도 F 는 프레넬 공식으로부터 이론적으로 구해질 수 있습니다 [21]. 이 공식은 완전히 부드러운 거울같은 서피스에 대한 반사도를 굴절률( n )( index of refraction ) 항, 서피스에 대한 소광계수(k)( 흡광계수, extinction coefficient ), 조명각( θ )( angle of illumination )으로 표현합니다. 일반적으로 n 와 k 는 파장에 따라 다양하지만, 그것들의 값은 흔히 알려져있지 않습니다. 반대로 수직 입사시 경험적으로 측정된 반사도 값은 흔히 알려져 있습니다.

 

F 의 스펙트럼과 각에 대한 다양성을 획득하기 위해서, 우리는 실용적인 타협안을 수용했습니다. 만약 n 과 k 가 알려져 있다면, 우리는 프레넬 공식을 사용합니다. 만약 그렇지 않고 일반 반사도가 알려져 있다면, 우리는 프레넬 공식을 연마된 서피스를 위해서 측정된 일반 반사도에 맞춥니다. 비금속의 경우 k = 0 인데, 이것은 우리에게 굴절률 n 에 대한 추정치( estimate )를 제공합니다. 금속의 경우 k 는 일반적으로 0 이 아닌데, 우리는 k 를 0 으로 설정하고 일반 반사도로부터 n 을 위한 효과적인 값을 얻습니다. 그러면 F 에 대한 각 의존성을 프레넬 공식으로부터 이용할 수 있습니다. 앞의 방법은 수직 입사를 위한 F 의 정확한 값을 산출하며, 그것의 각 의존성에 대한 좋은 추정치를 제공합니다. 이는 소광계수 k 에 약하게 의존할 뿐입니다.

 

이 방법을 설명하기 위해서, 비편광( unpolarized ) 입사광과 k = 0 을 위한 프레넬 공식은 다음과 같습니다.

 

 

여기에서

 

 

입니다.

 

( [5] 에서 이와 유사한 표현식은 1/2 요소를 빼먹었습니다. ) 수직 입사시, θ = 0; 그래서 c = 1, g = n 입니다. 그리고

 

 

입니다.

 

n 에 대해서 풀면 다음 공식이 나옵니다.

 

 

이런 방식으로 결정된 n 값은 다른 입사각에서의 반사도 F 를 획득하기 위해서 원래의 프레넬 공식을 대체하게 됩니다. 이 방법은 반사도의 스펙트럼 및 지향성 의존성을 획득하기 위해서 다른 파장들에 대해서 반복될 것입니다.

 

파장과 입사각 상에서의 반사도에 대한 의존성은 반사광의 색상은 입사각에 따라 변경된다는 것을 내포합니다. 구리에 대한 반사도 스펙트럼들은 그림 5a 에 나와 있습니다. 입사각( θ )는 π/2 에 접근하기 때문에, 반사광의 색상은 광원의 색상에 접근합니다( since the reflectance F approaches unity ). 구리로부터 흰색 빛( CIE 표준 빛 D6500 )의 반사와 관련된 색상들은 그림 5b 에서 θ 에 대한 함수로서 나타납니다. 프레넬 공식으로부터의 색상 변화는 θ 가 π/2 에 접근했을 때만 중요하다는 것이 분명해집니다( 즉, VL 사이의 각이 π 에 접근할 때 ). 

 

색상 변화에 대한 계산은 계산적으로 비쌉니다. 그것은 두 방식 중의 하나를 사용해 단순화될 수 있습니다; 룩업 테이블( lookup table )을 생성하거나 다음 근사계산을 사용. 평균 일반 반사도와 연관된 n 의 값을 위해서 먼저 F 의 값들이 계산됩니다. 다음으로 이 값들은 θ = 0 일 때와 θ = π/2 일 때의 색상 사이를 보간하기 위해서 사용됩니다. θ = π/2 일 때의 색상은 광원의 색상과 동일한데 그 이유는 Fπ/2 는 모든 파장에서 1.0 이기 때문입니다. 예를 들어 수직 입사시 색상의 red 요소가 Red0 이라 하고 입사광의 색상의 red 요소가 Redπ/2 라고 합시다. 그러면 다른 각도에서 색상의 red 요소는 다음과 같습니다.

 

 

Green 요소와 blue 요소도 비슷하게 보간됩니다. 그림 5c 는 입사각에 대한 함수로서 구리의 색상을 추정하기 위해 근사계산 방법을 사용하는 효과를 보여 줍니다. 이 근사계산 방법은 완전한( 하지만 더 비싼 ) 방법( 그림 5b )의 결과와 비슷한 결과를 산출합니다. 앞의 근사계산은 반사광의 스펙트럼 에너지 분포가 알려지지 않았고 RGB 값들에 대한 추정치를 모두 가지고 있는 경우에는 항상 사용되어야 합니다.

 

그림 5: (a) 파장과 입사각에 대한 함수로서 구리 거울의 반사도.

(b) 입사각에 대한 함수로서 구리의 색상.

(c) 이 논문에서 논의된 기법으로 근사계산된 것으로서의 구리의 색상.

 

DETERMINING THE RGB VALUES

 

컴퓨터 함성 씬이 사실적이 되도록 하기 위해서는, 컬러 텔레비전 모니터를 통해 합성 씬을 보고 있는 관찰자의 색상 감각이 실세계에서 관련 씬을 보고 있는 관찰자의 색상 감각과 거의 비슷해야만 합니다. 이 비슷한 색상 감각을 생성하기 위해서, 반사광의 스펙트럼 에너지 분포를 특정 모니터를 위한 적절한 RGB 값으로 변환하기 위해서 3색 색상 복제 법칙( the law of trichromatic color reproduction )이 사용됩니다.

 

모든 색상 감각은 삼차원 색상 공간에서의 위치로 일관성있게 기술될 수 있습니다. 그런 색상 공간들 중 하나는 XYZ 공간이라 불립니다.이 공간에서의 점은 세 개의 좌표로 지정되는데, 이는 색상의 XYZ 3자극( tristimulus ) 값들입니다. 각각의 스펙트럼 에너지 분포는 XYZ 색상 공간의 점, 즉 3자극 값들과 연관되어 있습니다. 만약 두 개의 스펙트럼 에너지 분포가 같은 삼자극 값들과 연관되어 있다면, 그것들은 같은 색상 감각을 생성하고 이는 metamer( 조건 등색을 나타내는 색 )라 불립니다. The red, green and blue phosphors of a monitor can be illuminated in proportions to produce a set of spectral energy distributions which define a region of XYZ space called the gamut of the monitor( 역주 : Understanding the Color Gamut of an LCD monitor 참조 ). 그러면 목표는 반사광의 스펙트럼 에너지 분포의 metamer 인 스펙트럼 에너지 분포를 생성하는 인광물질 조명의 비율을 찾는 것입니다.

 

이 비율은 반사광의 스펙트럼 에너지 분포와 연관된 XYZ 3자극 값들을 계산하고 나서 이 3자극 값들을 가지고 스펙트럼 에너지 분포를 생성하는 RGB 값들을 계산함으로써 결정됩니다. 이를 위해, 반사광의 스펙트럼 에너지 분포는 모든 파장에서 ( [7]에서 가져온 ) XYZ 매칭 함수들과 곱해집니다. 그리고 나서 최종적인 스펙트럼들은 XYZ 3자극 값들을 획득하기 위해서 적분됩니다. 이 XYZ 값들은 광원 유형과 서피스 재질의 조합별로 미리 계산될 수 있는데, 이는 특정 인광물질 집합과 모니터 화이트 포인트( white point, 모니터에서 가장 흰색이 이상적으로 보이게 맞추는 상태 )를 위한 RGB 선형 휘도( luminance )에 대한 행렬 곱셈을 통해 변환될 수 있습니다. 그리고 나서 이 선형 휘도들은 RBG voltages 로 변환되는데, 이 때 모니터의 비선형성과 시청 환경 효과들을 고려하게 됩니다. 이 방법에 대한 더 정확한 설명을 원한다면 [13] 을 참조하십시오.

 

모니터는 주어진 색도( chromaticity )를 복제할 수 있는 최대 휘도를 가집니다. 이 최대값보다 큰 휘도를 표현하는 모든 XYZ 값들은 모니터 gamut 의 권한 밖입니다. 그런 색상은 모니터 내에서 어떤 휘도로도 복제될 수 없기 때문에, 그것은 반드시 모니터 gamut 내의 비슷한 색상에 의해 근사계된되어야 합니다. 이 색상은 매우 다양한 방식으로 선택될 수 있습니다; 이 논문을 위해, 우리는 같은 hue 를 유지하고 필요하면 채도를 감소시키는 것이 적절하다고 결정했습니다. 이를 위해 3자극 XYZ 값들은 색상 공간으로 변환되는데, 그것의 위치는 주요 파장( dominant wavelength )과 순도( purity )에 의해 지정됩니다. 그리고 나서 주요 파장( 그리고 거의 hue )은 색상이 모니터 gamut 내부에 놓일 때까지 유지되는 반면 순도는 감소합니다. 그리고 나서 최종 색상은 XYZ 공간으로 다시 변환됩니다. ( 주요 파장과 순도에 대한 논의를 위해서는 [12] 를 참조. )

 

APPLICATIONS

 

이 섹션은 두 개의 특별한 재질인 금속과 플라스틱에 대해 반사도 모델을 적용하는 것에 대해 논의합니다. 가장 고려해야 할 점은 재질의 균일성입니다. 서피스 위와 아래가 다른 재질로 구성된 것처럼 서로 다른 재질로 구성된 물질은 비균질하며, 이는 스펙큘러 요소와 디퓨즈 요소가 다른 색상으로 나오게 만듭니다.

 

일반적인 플라스틱은 투명하거나 흰 substrate( 기질, 도장되지 않은 표면, 접착 기면 )를 가지는데, 내부에 안료 입자들을 포함합니다 [11]. 즉 서피스로부터 직접적으로 반사되는 빛은 광원으로부터의 색상을 약간 수정하게 됩니다. 모든 색상 변경은 서피스 재질의 반사도의 결과입니다. 재질을 뚫고 들어 가는 빛은 안료와 상호작용하게 됩니다. 그러므로 내부 반사는 색이 들어 간 골고루 분포된 디퓨즈 반사를 증가시킵니다.

 

그래서 플라스틱은 색상이 있는 디퓨즈 요소와 흰 스펙큘러 요소를 사용해서 시뮬레이션 될 것입니다. 이는 그냥 Phong 과 Blinn 에 의해 사용된 모델일 뿐이며, 많은 컴퓨터 그래픽스 이미지들이 플라스틱처럼 보이는 심각한 스펙큘러 요소들을 가지고 있게 되는 이유입니다. 그림 6a 는 구리 색상 플라스틱 꽃병을 시뮬레이션한 것을 보여 줍니다. 이 그림은 다음 파라미터들을 사용해서 생성되었습니다.

 

 

그림 6: (a) 구리 색상 플라스틱 꽃병. (b) 구리 꽃병.

 

금속은 전도체입니다. 전자기파 충돌( impinging electromagnetic wave )은 서피스 근처의 전자의 활동을 활발하게 만들 수 있습니다. 이는 순차적으로 전자기파 재방출( reflection )을 유도합니다. 약간 깊은 침투( depth penetration )가 있는데, 이 깊은 침투는 소광계수( extinction coefficient ) k 의 값을 증가시키면서 감소됩니다. 결과적으로 금속으로부터의 반사는 본질적으로 서피스에서 발생합니다 [17]. 그러므로 내부 반사들은 디퓨즈 요소에 기여하지 않습니다. 이는 비금속에서는 중요할 수 있습니다. rms( root mean squre ) 러프니스 기울기 m 이 작을 때, 다중 서피스 반사들 또한 무시되고 전체 디퓨즈 요소들이 사라지게 됩니다. 그림 6b 는 구리 꽃병을 시뮬레이션한 것을 보여 줍니다. 이 그림은 다음 파라미터들을 사용해서 생성되었습니다.

 

 

 

rms 기울기에 대한 두 값들이 사실적인 거친 서피스 마무리를 위해 사용되었다는 점에 주목하십시오. 스펙큘러 반사도 요소는 구리 색상을 가집니다. 그림 6b 의 구리 꽃병은 그림 6a 에서 보이는 꽃병의 플라스틱 외형을 보여주지 않습니다. 이는 사실적인 비플라스틱 외형을 취하기 위해서 필요한 스펙큘러 요소의 색상을 올바르게 취급했다는 것을 보여 줍니다.

 

그림 7 은 다양한 재질로 구성된 꽃병들을 보여 줍니다. 모든 경우에 스펙큘러 요소와 디퓨즈 요소들은 같은 색상을 가집니다( 즉 Rd = F0/π ). 모든 꽃병에 대한 조명 조건은 그림 6a6b 를 위한 조명 조건과 동일합니다. 6 개의 금속들은 반사도 스펙트럼을 제외하고는 그림 6b 와 같은 파라미터들을 사용해서 생성되었습니다. 6 개의 비금속들은 Table I 에 보이는 파라미터들을 사용해서 생성되었습니다.

 

 

그림 7: 다양한 꽃병들.

 

그림 8 은 다양한 재질과 서피스 조건으로 구성된 시계를 보여 줍니다. 그것은 단일 광원으로부터 빛을 받습니다. 시계의 외부 밴드는 금으로 구성되었고, 내부 밴드는 스테인리스강으로 구성되었습니다. 외부 밴드의 연결부위 상의 패턴은 더 거친 서피스로 구성되어 있는데, 경계보다는 내부가 더 거칩니다. LED 는 표준 red 640 nanometer LED 입니다. 그리고 그것들의 색상은 같은 주요 파장을 가진 색상을 사용해서 근사계산되었습니다.

 

그림 8: 시계.

 

CONCLUSION

 

다음과 같이 결론을 내릴 수 있습니다.

 

  1. 스펙큘러 요소는 보통 재질의 색상이며, 광원의 색상이 아닙니다. 앰비언트, 디퓨즈, 그리고 스펙큘러 요소는 재질이 비균질할 경우에 서로 다른 색상이 될 수 있습니다.
  2. 양방향 분포의 개념은 같은 장면에서의 다양한 광원 및 재질을 시뮬레이션하기 위해 필요합니다.
  3. Blinn 에 의해 사용된 미세면 기울기 분포 모델들은 광학 문헌에서의 다른 것들과 매우 유사하며 계산하기 쉽습니다. 하나 이상의 미세면 기울기 분포 함수들이 서피스를 표현하기 위해 조합될 수 있습니다.
  4. 프레넬 공식은 지표각에서의 스펙큘러 요소의 색상 변화를 예측합니다. 이 색상 변화를 계산하는 것은 근사계산 방법이나 룩업 테이블을 사용하지 않는다면 계산적으로 비쌉니다.
  5. 특정 재질에서 반사된 빛에 대한 스펙트럼 에너지 분포는 광원의 스펙트럼 에너지 분포 재질의 반사도 스펙트럼과 함께 반사도 모델을 사용해서 획득할 수 있습니다. 3색 색상 복제 법칙을 사용해서 이 스펙트럼 에너지 분포를 특정 모니터에 적합한 RGB 값들로 변환할 수 있습니다.
  6. 페인트를 칠한 오브젝트나 플라스틱과 같은 특정 유형의 재질들은 같은 색상으로 표현되지 않는 스펙큘러 요소와 디퓨즈 요소를 가집니다. 금속들은 광원과 금속의 반사도에 의해서 결정되는 색상을 가진 스펙큘러 요소를 가집니다. 디퓨즈 요소들은 보통 금속에서는 무시됩니다.
ACKNOWLEDGEMENT
 
이 연구는 Cornell University 의 Program of Computer Graphics 에서 수행되었습니다. 이 논문을 만드는데 있어서 귀중한 기여를 해 준 Gray Meyer 에게 감사드립니다. 그의 색상 소프트웨어와 모니터들에 대한 photometric measurements 는 스펙트럼 에너지 분포를 RGB 값들로 정확하게 변환하는 것을 가능하게 해 줬습니다. 또한 연구의 각 단계마다 유용한 논의와 가치있는 제안을 해 준 Dr. Donald Greenberg 에게 감사드립니다. ( 그림 8 의 ) 시계는 Stuart Sechrest 와의 공동노력의 결과입니다.
 
REFERENCES
 
1. BARKMAN, E. F. Specular and diffuse reflectance measurements of aluminum surfaces. In Appearance of Metallic Surfaces, ASTM Special Tech. Publ. 478, American Society for Testing and Materials, Philadelphia, 1970, pp. 46-58.
 
2. BECKMANN, P. AND SPIZZICHINO, A. The Scattering of Electromagnetic Waves from Rough Surfaces. MacMillan, New York, 1963, pp. 1-33, 70-98.
 
3. BENNETT, H. n., AND PORTEUS, J.O. Relation between surface roughness and specular reflectance at normal incidence. J. Opt. Soe. Am., 51, 2 (1961), 123-129.
 
4. BLINN, Z. F., AND NEWELL, M. E. Texture and reflection in computer generated images. Commun. ACM 19, 10 (Oct. 1976), 542-547.
 
5. BLINN, J.F. Models of light reflection for computer synthesized pictures. Computer Gr. 11, 2 (1977), 192-198.
 
6. BLINN, J.F. "Coniputer Display of Curved Surfaces." Ph.D. dissertation, Univ. of Utah, Salt Lake City, 1978.
 
7. CIE INTERNATIONAL COMMISSION ON ILLUMINATION Official recommendations of the international commission on illumination. Colorimetry (E-1.3.1), Publ. CIE 15, Bureau Central de la CIE, Paris, 1970.
 
8. COOK, R.L. "A Reflection Model for Realistic Image Synthesis." Master's thesis, Cornell Univ., Ithaca, 1981.
 
9. DAVIES, H. The reflection of electromagnetic waves from a rough surface. Proceedings of the Institution of Electrical Engineers 101 (1954), 209-214.
 
10. GUBAREFF, G. G., JANSSEN, J. E., AND TORBORG, R.H. Thermal Radiation Properties Survey: A Review of the Literature. Honeywell Research Center, Minneapolis, 1960.
 
11. HUNTER, R.S. The Measurement of Appearance. Wiley, New York, 1975, pp. 26-30.
 
12. JUDD, D. B. AND WYSZECKI, G. Color in Business, Science, and Industry. Wiley, New York, 1975, pp. 170-172.
 
13. MEYER, G. W. AND GREENBERG, D.P. Perceptual color spaces for computer graphics. Computer Gr. 14, 3 (1980), 254-261.
 
14. PHONG, B.T. "Illumination for Computer Generated Images." Ph.D. dissertation, Univ. of Utah, Salt Lake City, 1973.
 
15. PHONG, B.T. Illumination for computer generated pictures. Commun. ACM 18, 6 (June 1975), 311-317.
 
16. PORTEUS, J.O. Relation between the height distribution of a rough surface and the reflectance at normal incidence. J. Opt. Soc. Am. 53, 12 (1963), 1394-1402.
 
17. Purdue University, Thermophysical Properties of Matter, vol. 7: Thermal Radiative Properties of Metals, Plenum, New York, 1970.
 
18. Purdue University, Thermophysical Properties of Matter, vol. $: Thermal Radiative Properties of Nonmetallic Solids, Plenum, New York, 1970.
 
19. Purdue University, Thermophysical Properties of Matter, vol. 9: Thermal Radiative Properties of Coatings, Plenum, New York, 1970.
 
20. SIEGEL, R. AND HOWELL, J.R. Thermal Radiation Heat Transfer. McGraw-Hill, New York, 1980, pp. 64-73.
 
21. SPARROW, E. M. AND CESS, R.D. Radiation Heat Transfer. McGraw-Hill, New York, 1978, pp. 64-68.
 
22. TORRANCE, K. E. AND SPARROW, E.M. Biangular reflectance of an electric nonconductor as a function of wavelength and surface roughness. Journal of Heat Transfer 87, series C (1965), 283-292.
 
23. TORRANCE, K. E. AND SPARROW, E. M. Theory for off-specular reflection from roughened surfaces. J. Opt. Soc. Am. 57, (Sept. 1967), 1105-1114.
 
24. WHITTED, T. An improved illumination model for shaded display. Commun. ACM 23, 6 (June 1980), 343-349.
 
25. WHITTED, T. Private communication.

 

원문 : https://cdn2.unrealengine.com/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf

주의 : 번역이 개판이므로 이상하면 원문을 참조하세요.

주의 : 허락받고 번역한 것이 아니므로 언제든 내려갈 수 있습니다.

주의 : 실력이 딸려 우리말로 번역하기 애매한 것들은 원문을 그대로 보여줄 것입니다. 좋은 제안이 있으면 알려 주십시오.

주의 : 2013 년 시그래프 문서입니다. 변경사항이 없을 것 같지만 일단 참고하세요.



Real Shading in Unreal Engine 4


by Brian Karis, Epic Games


그림 1: UE4: Infiltrator demo


Introduction


일년 전쯤에, 우리는 쉐이딩 모델을 개선하고 물리 기반 재질 워크플로우를 좀 더 받아들이기로 결심했습니다. 이는 부분적으로는 좀 더 사실적인 이미지를 렌더링하고자 하는 열망에서 비롯된 것이지만, 좀 더 물리에 기반한 접근을 통해 머티리얼을 생성하고 머티리얼 레이어링( layering )을 사용하는 방법에 관심이 있기도 했습니다. 아티스트들은 이것이 워크플로우 및 품질에 막대한 증진을 주게 될 것이라고 느꼈으며, 나는 다른 스튜디오에서 이것들의 이점들을 이미 본 상태였습니다. 그 스튜디오에서 우리는 오프라인에서 조합된 머티리얼 레이어들을 전환하는 단계를 거쳤었습니다.  One of our technical artists here at Epic experimented with doing the layering in the shader with promising enough results that this became an additional requirement.


이러한 방향성을 지원하기 위해서는, 우리는 머티리얼 레이어링이 단순하고 효율적일 필요가 있음을 알고 있었습니다. 완벽한 타이밍에 Wreck-It Ralph 를 위해 사용된 물리 기반 쉐이딩 및 재질 모델과 관련한 Disney 의 프리젠테이션 [2] 이 나왔습니다. Brent Burley 은 매우 작은 머티리얼 파라미터 집합을 사용해도 오프라인 필름 렌더링을 위해서도 충분할 수 있다고 설명했습니다. 그는 대부분의 샘플링된 머티리얼과 거의 일치하는 매우 실용적인 쉐이딩 모델을 보여 주기도 했습니다. 그들의 연구는 우리에게 영감과 기반이 되어 주었으며, 그들의 "원칙들"처럼 우리는 우리만의 시스템을 위한 목표를 정의하기로 결심했습니다:


Real-Time Performance


    • 가장 먼저, 동시에 많은 광원들을 사용할 수 있도록 효율적일 필요가 있습니다.


Reduced Complexity


    • 가능하면 적은 개수의 파라미터들만이 존재해야 합니다. 파라미터들이 많아지면 결정 장애가 오고 시도를 많이 해야 하며 에러가 발생합니다. 혹은 단일한 의도를 가진 효과를 변경하기 위해서 많은 값들을 요구하는 서로 연결된 속성들이 필요합니다.
    • 우리는 IBL( image-based lighting )과 analytic light source 들을 서로 교환가능하도록 사용할 필요가 있습니다. 그래서 파라미터들은 모든 광원 유형에서 상수적으로 동작해야만 합니다.


Intuitive Interface


    • 우리는 단순하고 이해하기 쉬운 값들을 선호합니다. 굴절률( index of refraction )과 같은 물리적인 것들은 별로입니다.


Perceptually Linear


    • 우리는 마스킹을 통해 레이어링을 지원하기 원하지만, 픽셀당 한 번만 쉐이딩할 수 있는 여유가 있습니다. 이는 parameter-blended shading 이 쉐이딩된 결과를 블렌딩한 것과 가능한한 가깝게 일치되어야만 함을 의미합니다( 역주 : pixel 을 multi-pass 로 그리지 않고도, multi-pass 로 그린 것과 비슷한 결과를 내야 한다는 의미인듯합니다 ).


Easy to Master


    • 우리는 유전체( dielectrics )와 도체( conductor )에 대한 기술적 이해를 해야할 필요성을 피하고 싶습니다. 또한 물리적으로 이치에 맞는 기본 머티리얼들을 생성하기 위해서 요구되는 노력들을 최소화하기를 원합니다.


Robust


    • 실수로라도 물리적으로 이치에 맞지 않는 머티리얼들을 생성하는 것이 어려워야 합니다.
    • 파라미터들에 대한 모든 조합들은 가능한한 견고하고 이치에 맞야야 합니다.


Expressive


    • 디퍼드 쉐이딩은 우리가 가질 수 있는 쉐이딩 모델의 개수를 제한합니다. 그래서 우리의 기반 쉐이딩 모델은 실세계에서 보일 수 있는 머티리얼들의 99% 를 충분히 다룰 수 있도록 기술적( descriptive )이어야 할 필요가 있습니다.
    • 레이어링 가능한 모든 머티리얼들은 서로를 블렌딩하기 위해서 같은 파라미터 집합을 공유할 필요가 있습니다.


Flexible


    • 다른 프로젝트나 라이센시들은 실사성( photorealism )에 대한 같은 목표를 공유하지 않을 수도 있습니다. 그래서 비실사 렌더링을 충분히 가능하게 할 수 있는 유연성이 필요합니다.


Shading Model


Diffuse BRDF


우리는 Burley 의 디퓨즈 모델을 평가했지만, Lambertian diffuse( 식 1 ) 와의 사소한 차이만을 느낄 수 있었습니다. 그래서 우리는 추가 비용의 타당성을 정당화할 수 없었습니다. 게다가, 더 복잡한 디퓨즈 모델은 image-based lighting 이나 spherical harmonic lighting 을 효율적으로 사용하기 어렵게 만듭니다. 결과적으로, 우리는 다른 선택들을 평가하려는 노력을 들이지 않았습니다.


식 1


여기에서  는 머티리얼의 diffuse albedo 입니다.



Microfacet Specular BRDF


일반적인 Cook-Torrance [5,6] 미세표면 스펙큘러 쉐이딩 모델은 다음과 같습니다:


식 2


세부사항에 대해서 알고자 한다면 [9] 를 참조하십시오.


우리는 Disney 의 모델에서 시작해, 각 항들의 중요성을 더 효율적인 대안들과 비교하면서 평가했습니다. 이는 들리는 것보다는 더 어려운 일이었습니다; 각 항들을 위해 게재된 공식들을 완벽하게 비교하기 위해서는 같은 입력 파라미터들을 사용하는 것이 중요한데, 그렇지 못했습니다.


Specular D



노멀 분포 함수( NDF, normal distribution function, 역주 : 정규 분포가 아니라 노멀 분포임에 주의 )를 위해 Disney 가 GGX/Trowbridge-Reitz 를 선택한 것은 비용을 들일만한 가치가 있었습니다. Blinn-Phong 을 사용하는 것과 비교했을 때 추가적인 비용이 매우 적으며, 더 긴 "꼬리( tail )"에 의해 산출된 뚜렷하고 자연스러운 외관은 우리 아티스트들에게 ( 역주 : 그것의 장점을 ) 어필했습니다. 우리는 Disney 의  에 대한 재파라미터화( reparameterization )를 수용했습니다.


식 3



Specular G



다른 것과 비교했을 때, 우리는 기하학적 스펙큘러 감쇠( specular geometric attenuation ) 항에 대해 많은 옵션들을 평가했습니다. 결국, 우리는 Schlick model [19] 를 사용하기로 했지만,  를 사용하기로 했습니다. 그래서 GGX 를 위한 Smith model [21] 과 더 비슷합니다. 이러한 수정을 통해, Schlick model 은  을 위한 Smith model 과 정확히 일치하게 되며, 이는 [ 0, 1 ] 범위에서의 근사계산에 매우 가깝게 됩니다( 그림 2 참조 ). 또한 우리는 Disney 의 변형을 사용해 제곱하기 전에  를 사용해 러프니스 리매핑을 통해 "hotness" 를 제거하는 것을 선택했습니다. 이러한 조정은 단지 analytic light source 들에 대해서만 사용된다는 것을 기억하는 것이 중요합니다; 만약 이것이 image-based lighting 에 적용된다면, glancing angle 에서의 결과는 더욱 어둡게 되는 결과를 낳을 것입니다.


식 4




그림 2:일 때  Shclick 은 Smith 와 매우 비슷함


Specular F



프레넬( Fresnel )을 위해, Shilick's approximation [19] 을 사용하는 전형적인 선택을 했습니다. 그러나 사소한 변경이 있었습니다: 우리는 Spherical Gaussian approximation [10] 을 사용해 power 를 대체했습니다. 이것이 계산에 있어 약간 더 효율적이며, 그 차이는 인지하기 어렵습니다. 그 공식은 다음과 같습니다:


식 5


여기에서  는 normal incidence( 역주 : 법선과의 각도가 0 일 때 )에서의 스펙큘러 반사( specular reflectance )입니다.



Image-Based Lighting


Image-based lighting 과 함게 이 쉐이딩 모델을 사용하려면, 복사휘도( radiance ) 적분이 필요합니다. 이는 보통 중요도 샘플링( importance samploing )을 사용해서 수행됩니다. 다음 공식은 이 수치 적분( numerical integration )을 설명합니다:


식 6


다음 HLSL 코드는 우리 쉐이딩 모델을 사용하여 이것이 수행되는 방식을 보여 줍니다:



중요도 샘플링을 사용한다 해도, 여전히 많은 샘플들이 취해질 필요가 있습니다. 샘플 카운트는 밉맵 [3] 을 사용함으로써 매우 많이 줄어들 수 있습니다. 그러나 만족할만한 품질을 위해서는 여전히 16 보다는 큰 샘플 카운트가 필요합니다. Local reflection 을 위해서 픽셀당 여러 개의 환경 맵들을 블렌딩해야 하므로, 우리는 실질적으로는 각각에 대해 단지 한 개의 샘플만을 취할 수 있습니다.


Split Sum Approximation


이를 위해 우리는 위의 합( sum )을 두 개의 합으로 분리하여 근사계산할 수 있습니다. 그러면 각각의 합은 미리 계산될 수 있습니다. 이러한 근사계산은 정확히 상수  에 대한 것이며 보통의 환경들에 대해서는 매우 정확합니다.


식 7


Pre-Filtered Environment Map


우리는 서로 다른 러프니스 값들을 위한 첫 번째 합을 미리 계산하고 그 결과를 큐브맵의 밉맵 레벨들에 저장합니다. 이는 매우 많은 게임 산업에서 사용되는 일반적인 접근법입니다[1, 9]. 사소한 차이라고 하면, 우리는 중요도 샘플링을 사용하여 우리의 쉐이딩 모델에 대한 GGX 분산을 환경 맵에 convolve 한다는 것입니다. 그것은 미세표면 모델이므로, 분산의 모양은 표면을 바라보는 각도에 따라 변하고, 우리는 이 각도를 0 이라고 가정합니다. 즉  입니다. 이 등방성 추정( isotropic assumption )은 근사계산의 두 번째 소스이며, 그것은 아쉽게도 우리가 지표각( grazing angle )에서 긴 반사를 획득할 수 없음을 의미합니다. Compared with the split sum approximation, this is actually the larger source of error for our IBL solution. 아래 코드에서 보이듯이, 우리는 에 의한 weighting 이 더 나은 결과를 보여준다는 것을 발견했습니다[각주:1].



Environment BRDF


두 번째 합은 나머지를 모두 포함합니다. 이는 solid-white environment 를 사용해 스펙큘러 BRDF 를 적분하는 것과 동일합니다. 즉 입니다. Schlick 의 Fresnel  을 치환함으로써, 우리는  가 적분밖으로  빠질 수 있다는 것을 발견했습니다.


식 8

 

이는 두 개의 입력들( Roughness 와 cosθv )과 두 개의 출력들( scale 과 F0 에 대한 bias )을 남기는데, 그것들은 모두 다 편리하게 [0, 1] 범위를 가진다. 우리는 이 함수의 결과를 미리 계산해서 그것을 2D look-up texture( LUT )[각주:2]에 저장합니다.


그림 3: 2D LUT


이 작업을 마무리하고 나서, 우리는 우리의 해법과 거의 동일한 현존하는 동시적인 연구가 있다는 것을 발견했습니다. Gotanda 는 3D LUT [8] 를 사용하고, Drobot 은 이를 2D LUT [7]로 최적화했으며, 우리가 한 것과 매우 유사합니다. 추가적으로 - 이 코스의 일부로서 - Lazarov 는 유사한 적분[각주:3]에 대한 한 쌍의 analytical approximations 을 제시함으로써 한 단계 더 나아갔습니다 [11]. 



마지막으로 중요도 샘플링된 레퍼런스들을 근사계산하기 위해서 우리는 두 개의 미리 계산된 합을 곱합니다:

  


그림 4: 상단의 참조 이미지, 중단은 split sum approximation, 

하단은 n = v assumption 을 포함하는 full approximation.

Radially symmetric assumption 은 대부분의 에러를 보여 주지만, combined approximation 은 여전히 참조와 매우 유사합니다.


그림 5: 그림 4 와 같은 비교이지만, 유전체( dielectric )를 가지고 테스트함.


Material Model


우리 머티리얼 모델은 Disney 머티리얼 모델을 단순화한 것입니다. 그런데 실시간 렌더링을 위한 효율성을 높이는 방향으로 진행되었습니다. 파라미터의 개수를 제한하는 것은 G-Buffer 공간을 최적화하는데 매우 중요하며, 텍스쳐 저장공간과 접근을 줄여 주고, 픽셀 쉐이더에서 머티리얼 레이어를 블렌딩하는 비용을 최소화해 줍니다.


다음은 우리의 기본 머티리얼 모델입니다:


BaseColor    단일 색상. 이해하기 쉬운 개념.

Metallic       유전체와 반도체 반사에 대해서 이해할 필요가 없음. 그래서 에러의 가능성이 낮음.

Roughness   그것의 의미가 매우 명확함. 반면에 gloss 는 항상 설명을 필요로 함.

Cavity          small-scale shadowing 을 위해서 사용됨.



BaseColor, Metallic, Roughness 는 Disney 모델과 동일합니다만, Cavity 파라미터는 Disney 모델에는 없고 설명이 좀 필요합니다. Cavity 는 실시간 shadowing 시스템이 다룰 수 있는 것보다 작은 geometry 로부터의 그림자를 식별하기 위해서 사용됩니다. 이런 것은 주로 normal map 에서 제출되는 것 때문에 생기는 geometry 입니다. 예를 들면 바닥 보드 사이의 크랙( crack )이라든가 옷사이의 연결부위 등이 있습니다.


Specular 파라미터가 가장 눈에 띠게 누락됩니다. 우리는 실제로 Infiltrator 데모를 완성할 때까지 이것을 계속적으로 사용해 왔지만, 궁극적으로 우리는 이것을 좋아하지 않았습니다. 먼저, 우리는 "specular" 라는 것이 끔찍한 파라미터 이름이라 느낍니다. 왜냐하면 이는 엄청 헷갈리는 이름이며, 아티스트들이 specular intensity 제어를 roughness 제어로 옮기는데 있어 다소 악영향을 줍니다. 아티스트들과 그래픽스 프로그래머들은 보통 그것의 범위를 망각하고 기본값이 1 이라고 가정하게 되는데, 그것의 실제 기본값은 ( 4% 반사와 관련한 ) Burley 의 0.5 였습니다. Specular 가 효과적으로 사용되었던 경우는 small scale shadowing 의 목적과는 거의 배타적인 경우였습니다. 우리는 굴절률( IOR, index of refraction ) 값이 비금속을 위해서는 중요하지 않다는 것을 발견했으며, 그래서 우리는 최근에 Specular 를 이해하기 더 쉬운 Cavity 파라미터로 변경했습니다. 비금속의  는 이제 상수값이 0.04 입니다.



Disney 모델에서 다음 파라미터들은 기본 머티리얼 모델을 위해서 선택하지 않거나 특별한 경우로 취급됩니다:


Subsurface   shadow map 을 서로 다르게 샘플링합니다.

Anisotropy   많은 IBL 샘플들을 요구합니다.

Clearcoat     두 개의 IBL 샘플들을 요구합니다.

Sheen         Burley 의 표기법에서는 제대로 정의되지 않습니다.


우리는 Elemental 데모의 얼음을 위해 사용된 Subsurface 를 제외하고는 프로덕션에서 이러한 특별한 경우의 모델들을 사용하지 않았습니다. 부가적으로 우리는 피부( skin )를 위한 특별한 쉐이딩 모델을 가지고 있습니다. 나중에 우리는 하이브리드 디퍼드/포워드 접근법을 적용해서 더 많은 특별한 쉐이딩 모델들을 지원하는 것을 고려할 것입니다. 현재 우리는 순수한 디퍼드 쉐이딩 접근법만을 사용하고 있으며, 다른 쉐이딩 모델들은 G-Buffer 에 저장된 쉐이딩 모델 아이디로부터 다이내믹 브랜치를 사용해서 제어됩니다.


Experiences


내가 여러 번 봐 온 상황이 하나 있습니다. 나는 roughness 를 사용하기 시작하는 아티스트들에게 다음과 같이 이야기할 것입니다. "Roughness 를 SpecularColor 를 사용하듯이 사용하세요". 그리고 나는 곧 놀라는 소리를 듣게 될 것입니다: "그게 동작해요!". 그러나 흥미로운 답변이 뒤따를 것입니다: "Roughness 가 뒤집힌 것 같네요". 아티스트들은 그들이 작업한 텍스쳐에서 텍셀이 밝을 수록 스펙큘러 하이라이트가 더 밝아지기를 원한다는 것이 밝혀졌습니다. 만약 이미지가 roughness 를 저장한다면, bright 는 rougher 와 동일시되는데, 이것은 덜 강렬한 하이라이트를 만들게 됩니다.


A question I have received countless time is: "Is Metallic binary?" to witch I'd originally explain the subtleties of mixed of layered materials. 나는 그 때 이후로는 "네!" 라고 그냥 대답하는 것이 최선임을 배웠습니다. 그 이유는 이제 막 배우는 아티스트들은 파라미터들을 절대값으로 설정하는 것을 주저했기 때문입니다; 나는 금속들의 Metallic 값을 0.8 로 설정하는 것이 매우 흔하다는 것을 발견했습니다. 다음에 언급할 머티리얼 레이어들은 Metallic 이 0 이나 1 이 아닌 99% 의 경우를 설명하는 방법이 될 것입니다.


We had some issues during the transition, in the form of materials that could no longer be replicated. 이 머티리얼들의 가장 중요한 집합은 Fortnite 에서 비롯되었습니다. 이 게임은 현재 Epic 에서 제작중입니다. Fortnite 는 non-photorealistic art direciton 을 가지고 있으며, 일부러 디퓨즈 반사와 스펙큘러 반사의 보색( complementary color )를 사용합니다. 이는 물리적으로 타당하지 않으며 우리의 새로운 머티리얼 모델에서 표현될 수 없습니다. 오랜 논의 후에, 우리는 Fortnite 의 품질을 유지하기 위해서 예전의 DiffuseColor/SpecularColor 를 엔진 스위치로서 계속해서 지원하기로 결정했습니다. 왜냐하면 그것은 나중에 개발해야 하기 때문입니다. 그러나 우리는 새로운 모델이 Wrek-It Ralph 에서 Disney 가 사용함으로써 설명했던 것과 같은 비실사 렌더링을 불가능하게 만든다고 느끼지는 않습니다. 그래서 우리는 앞으로의 프로젝트들에서도 이 모델을 사용할 계획입니다.


Material Layering


공유 라이브러리들로부터 가져 온 머티리얼 레이어들을 블렌딩하는 것은 이전의 접근법에 비해 여러 개의 이점들을 제공합니다. 이전의 접근법이라는 것은 머티리얼 파라미터들을 특정 모델을 위해 제작된 텍스쳐로부터 가져온 값으로 지정하는 것을 말합니다:


    • 여러 개의 애셋들을 재사용할 수 있습니다.
    • 단일 애셋에 대한 복잡도를 줄일 수 있습니다.
    • 게임의 외형을 결정하는 머티리얼들을 통합하고 집중제어할 수 있습니다. 이는 아트 디렉션과 기술 디렉션을 쉽게 만듭니다.


새로운 워크플로우를 완전히 받아 들이기 위해서, 우리는 기존 툴에 대해 다시 생각해 볼 필요가 있었습니다. Unreal Engine 은 UE3 초기부터 노드 그래프 기반 머티리얼 에디터를 가지고 있었습니다. 이 노드 그래프는 입력( 텍스쳐, 상수 ), 연산, 그리고 출력 등을 지정하는데, 이것들은 쉐이더 코드로 컴파일됩니다.


머티리얼 레이어링이 이 작업의 대부분을 차지하는 주요 목표이기는 하지만, 놀랍게도 머티리얼 레이어들을 제작하고 블렌딩하는 것을 지원하기 위한 툴쪽에 추가될 필요가 있는 작업들이 매우 적었습니다. UE4 의 머티리얼 에디터에서 노드 그래프의 일부분은 이미 함수로 그룹화될 수 있었으며 다수개의 머티리얼들에서 사용되고 있었습니다. 이 기능은 머티리얼 레이어를 구현하기 위해서 자연스럽게 들어 맞았습니다. 최상위에 있는 고정 함수 시스템이 아니라 노드 기반 에디터 내부에 머티리얼 레이어를 유지하는 것은 레이어들을 프로그래밍가능한 방식으로 매핑하고 합칠 수 있게 해 주었습니다.


워크플로우를 합리화하기 위해서, 우리는 새로운 데이터 타입인 머티리얼 애트리뷰트를 추가했는데, 이는 모든 머티리얼 출력 데이터를 저장합니다. 이 새로운 타입은 다른 타입들과 마찬가지로 머티리얼 함수에서 단일 핀으로서 넘겨지거나( out ) 넘겨받거나( in ) 할 수 있습니다. 그리고 와이어를 통해 전달되거나 직접적으로 출력될 수도 있습니다. 이러한 변화때문에, 머티리얼 레이어들은 이전에 텍스쳐가 그랬던 것처럼 입력으로서 드래깅되거나 합쳐지거나 조작되거나 출력으로 나갈 수 있습니다. In fact, most material graphs tend to be simpler since the adoption of layers as the primary things custom to a particular material are how layers are mapped and blended. This is far simpler than the parameter specific manipulation that used to exist.


개념적으로 선형적인 작은 머티리얼 파라미터 집합을 가졌기 때문에, 쉐이더에서 레이어들을 블렌딩하는 것이 실제로 실용적이 되었습니다. 우리는 이것이 순수한 오프라인 편집 시스템과 비교했을 때 품질을 많이 개선해준다고 느낍니다. 텍스쳐 데이터의 해상도는 극단적으로 높아질 수 있습니다. 왜냐하면 데이터를 다양한 주파수에서 매핑하는 것이 가능하기 때문입니다; 버텍스당 혹은 저주파수 텍스쳐 데이터는 단일( unique )하며, 레이어 블렌드 마스크와 노멀맵, 그리고 구멍( cavity )맵은 메시당 지정되며, 머티리얼 레이어들은 메시의 서피스 상에서 타일링됩니다. 더 발전된 케이스들은 심지어 더 많은 주파수를 사용할 수 있습니다. 쉐이더 비용때문에 실질적으로는 몇 개의 레이어만 사용하도록 제약을 받고 있기는 하지만, 우리 아티스트들은 아직까지는 그 제약으로 인한 문제를 겪은 적이 없습니다.


그림 6: UE4 머티리얼 에디터에서의 단순한 머티리얼 레이어링.


An area that is cause for concern is that the artists in cases have worked around the in-shader layering limitations by splitting a mesh into multiple sections, resulting in more draw calls( 역주 : 여러 부분으로 나뉘어 있는 메시에 대한 레이어링은 드로 콜이 늘어나게 만들 수 있다는 의미인듯 합니다 ). CPU 측 코드 최적화로 인해 UE4 에서의 드로 콜 카운트가 개선되었기를 기대하기는 하지만, 이는 나중에는 문제의 소지가 있어 보입니다. 아직 연구하지 못한 영역은 레이어가 표면을 100% 덮고 있는 경우에 다이내믹 브랜칭( 역주 : if 같은 것 )이 쉐이더 비용을 감소시켜 줄 것이냐는 것입니다.


지금까지 머티리얼 레이어에 대한 우리의 경험은 매우 긍정적입니다. 생산성도 향상되었고 품질도 많이 개선되었습니다. 우리는 레이어를 검색하거나 미리보기하기 더 쉽게 만들어서 머티리얼 레이어 라이브러리에 대한 아티스트 인터페이스를 개선하기를 바랍니다. 또한 현재의 런타임 시스템에다가 오프라인 제작/베이킹 시스템을 추가하는 것을 연구해서 더 많은 개수의 레이어들을 지원하고 더 나은 확장성( scalability )를 제공하고자 합니다.


그림 7: 녹( rust )과 블렌딩한 머티리얼 레이어들


그림 8: 머티리얼 레이어링은 디테일의 다중 주파수들을 활용하는 결과를 산출합니다.


Lighting Model


쉐이딩과 같이 우리는 좀 더 물리에 기반한 라이팅 모델을 만들고 싶었습니다. 우리가 집중한 두 가지 영역은 light falloff 와 일반적으로 area light 라 불리는 non-punctual sources of emission 이었습니다.


Light falloff 를 개선하는 것은 상대적으로 직관적이었습니다: 우리는 물리적으로 정확한 inverse-square falloff 를 채택했으며 사진 밝기 단위를 lumens 로 변경했습니다. 그렇긴 하지만, 우리가 다뤄야 했던 사소한 문제는 이러한 종류의 falloff 는 그것이 0 이 되는 거리가 존재하지 않는다는 것입니다. 그러나 실시간 및 오프라인 계산의 효율성을 위해서 우리는 광원의 영향력이 미치는 한계를 강제로 정할 필요가 있었습니다. 이를 위한 여러 가지 방법들이 존재합니다 [4], but we chose to window the inverse-square function in such a way that the majority of the light's influence remains unaffected, whilst still providing a soft transition to zero. 이는 광원의 반지름을 수정하는 것이 그것의 유효 밝기를 변경하지 않는다는 훌륭한 특징을 가지고 있습니다. 이는 미적 관점에서 라이팅이 잠길때( locked ) 매우 중요할 수 있습니다. 그러나 광원의 크기는 성능상의 이유로 여전히 조절될 필요가 있습니다.


식 9


분모에서 1 은 광원과 가까운 거리에서의 function exploding 을 피하기 위한 것입니다. 물리적인 정확성이 요구되지 않는 경우라면 아티스트가 제어할 수 있는 파라미터로 노출될 수 있습니다.


The quality difference this simple change made, particularly in scenes with many local light sources, means that it is likely the largest bang for buck takeaway.


그림 9: Inverse square falloff 는 더 자연스러운 결과를 산출합니다.


Area Lights



에어리어 광원이 더 사실적인 이미지를 생성하는 일만 하는 것은 아닙니다. 그것들은 물리 기반 머티리얼을 사용할 때 매우 중요하기도 합니다. 우리는 에어리어 광원이 없을 때 아티스트들이 매우 낮은 러프니스 값을 칠하는 것을 직감적으로 피하게 된다는 사실을 알게 되었습니다. 왜냐하면 낮은 러프니스 값은 매우 작은 스펙큘러 하이라이트를 생성하게 되며 이는 매우 부자연스럽기 때문입니다. Essentially, they were trying to reproduce the effect of area lighting from punctual sources[각주:4].


불운하게도 이 리액션은 쉐이딩과 라이팅 사이의 결합을 유도하며, 이는 물리 기반 렌더링의 햄식 원칙 중 하나를 깨게 됩니다: 머티리얼은 그것이 생성되었던 것과 다른 환경에서 사용될 때 수정될 필요가 없어야만 합니다.


에어리어 라이트는 활발히 연구중인 분야입니다. 오프라인 렌더링에서의 일반적인 해법은 광원의 표면에 여러 개의 점 광원을 배치하는 것입니다 - uniform sampling 이나 importance sampling [12] [20] 중 하나를 사용합니다. 이는 실시간 렌더링에서는 비실용적입니다. 가능한 해법들에 대해서 논의하기 전에, 우리의 요구를 정리해 보겠습니다:


일관성있는 머티리얼 외형


    • Diffuse BRDF 와 Specular BRDF 를 사용해 평가되는 에너지의 총량이 확연히 다를 수는 없습니다.

입체각( solid angle )이 0 인것처럼 점광원에 접근합니다


    • 이를 성취하기 위해 쉐이딩 모델의 어떤 관점이라도 잃어버려서는 안 됩니다.


아무 곳에서나 사용할 수 있을만큼 빨라야 합니다


    • 그렇지 않으면, 우리는 앞에서 언급한 "biased roughness" 이슈를 풀 수 없습니다.


Billboard Reflections


빌보드 반사 [13]는 IBL 형식이며, 이는 discrete light source 들을 위해 사용될 수 있습니다. 방출된 빛을 저장하는 2D 이미지는 3D 공간에서 사각형에 매핑됩니다. 환경맵 pre-filtering 과 유사하게, 그 이미지는 다양한 크기의 스펙큘러 분산 콘( cone )들로 pre-filtered 됩니다. 이 이미지로부터 스펙큘러 쉐이딩을 계산하는 것은 콘 트레이싱( cone tracing )의 형식이라고 생각될 수 있습니다. 여기에서 콘은 스펙큘러 NDF 를 근사계산하게 됩니다. 콘의 중심에서 나가는 레이( ray )은 빌보드의 평면과 충돌하게 됩니다. 이미지 공간에서의 충돌지점은 텍스쳐 좌표계로서 사용되며, 충돌지점에서의 콘의 반지름은 적절한 pre-filtered mip level 을 유도하기 위해서 사용됩니다. 슬프게도, 이미지들은 매우 복잡한 에어리어 라이트를 직관적인 방식으로 표현해 주는 반면에, 빌보드 반사는 여러 가지 이유로 우리의 두 번째 요구를 만족시켜 주지 못합니다:


    • 이미지가 평면에서 pre-filetered 되기 때문에, 이미지 공간에서 표현될 수 있는 제한된 입체각이 존재합니다.
    • 평면에 충돌하지 않는 레이가 존재할 때 데이터가 존재할 수 없습니다.
    • 빛 벡터 l 을 모르거나 반사 벡터로 취급됩니다.


Cone Intersection


콘 트레이싱은 pre-filtering 을 요구하지 않습니다; 그것은 분석적으로( analytically ) 수행될 수 있습니다. Oat 의 cone-cone intersection 공식 [15] 를 사용해서 트레이싱 중인 콘과 구의 충돌을 실험해 본 적이 있는데, 그 비용이 너무 비싸서 실용적이지 못했습니다. 현재 Drobot [7] 에 의해 제시된 대안적인 기법은 콘을 쉐이딩 지점을 바라보는 디스크( disk )와 충돌시킵니다. 그리고 나서 NDF 를 근사계산하는 다항식은 충돌 영역 상에서 조각별로 적분( piece-wise integrated )을 수행합니다.


Drobot 의 최신 이론을 사용하면, 이는 흥미로운 연구 영역인 것처럼 보입니다. 하지만 그것의 현재 형식으로는 우리의 요구를 만족시킬 수 없습니다. 콘을 사용하기 때문에, 스펙큘러 분산은 반드시 방사상으로( radially ) 대칭이어야만 합니다. 이는 미세표면 스펙큘러 모델의 핵심적 특징인 늘어난 하이라이트를 배제합니다. 또한 빌보드 반사처럼 쉐이딩 모델에 의해 요구되는 라이트 벡터가 존재하지 않습니다.


Specular D Modification


우리가 작년에 제시한 접근법 [14] 은 광원의 입체각에 기반한 스펙큘러 분산을 수정하는 것입니다. 이것의 기반 이론은 광원의 분산은 그것과 연관된 콘 각도에 대한 D(h) 와 같다는 것을 고려하는 것입니다. 하나의 분산과 다른 분산의 convolving 은 새로운 콘을 유도하기 위해 두 콘의 각도를 더함으로써 근사계산될 수 있습니다. 이를 위해, 식 3 의 α 를 유효한 콘 각도로 변환하고, 광원의 각도를 더합니다. 그리고 그것을 다시 원래대로 변환합니다. 이 α' 는 이제 α 를 대체합니다. 우리는 이를 수행하기 위해서 다음과 같은 근사계산을 사용합니다:


식 10


이것은 효율적이기는 하지만, 이 기법은 안타깝게도 첫 번째 요구를 만족시키지 못합니다. 왜냐하면 큰 에어리어 라이트를 사용해서 빛을 비추면 매우 반짝이는 머티리얼이 거칠게 나오기 때문입니다. 이것은 헷갈릴 수 있습니다. 하지만 이 기법은 스펙큘러 NDF 가 작을 때 -- 예를 들어 Blinn-Phong -- 잘 동작합니다. 그러므로 광원의 분산과 더 잘 들어 맞습니다. 우리가 선택한 ( GGX 에 기반한 ) 쉐이딩 모델에 있어서, 이것은 실행가능하지 않습니다.


그림 10: 왼쪽은 참조. 오른쪽은 specular D modification. 

이 근사계산은 지표각과 연마된 놋쇠 머리와 같은 매끈한 머티리얼에서는 구 모양을 상실하고 거칠어 보이기 때문에 좋지 않습니다.


Representative Point


특정 쉐이딩 지점에 대해 에어리어 라이트로부터 오는 모든 빛을 광원의 서피스 상의 단일 representative point( 대표점 ) 로부터 오는 것으로 취급할 수 있다면, 우리의 쉐이딩 모델이 직접적으로 사용될 수 있습니다. 합리적인 선택은 가장 큰 기여도를 가진 점입니다. Phong 분산에 대해, 이것은 반사 레이에 대해 가장 작은 각도를 가진 광원상의 점입니다.


이 기법은 [16][22] 전에 출간되었지만, 에너지 보존은 전혀 고려되지 않았습니다. 방출된 빛의 원점을 이동시킴으로써, 우리는 라이트의 입체각을 효과적으로 증가시키지만, 부가적인 에너지를 보상하지는 못했습니다. 그것을 교정하는 것은 입체각으로 분할하는 것보다는 약간 더 복잡합니다. 왜냐하면 에너지의 차이는 스펙큘러 분산에 의존적이기 때문입니다. 예를 들어, 거친 머티리얼에 대해 입사하는 빛의 방향을 변경하하면 에너지 변화가 매우 적지만, 매끈한 머티리얼에 대해 방향을 변경하면 에너지 변화가 클 수 있습니다.


Sphere Lights


수평선 위에 존재하는 구형 라이트에 대한 복사조도( irradiance )는 포인트 라이트와 동일합니다 [18]. 비직관적이기는 하지만, 구가 수평선 아래쪽에 걸쳐 있을 때, 우리가 부정확성을 허용한다면, 스펙큘러 라이팅만을 고려할 필요가 있다는 것을 의미합니다. 우리는 반사 레이에 대해 가장 작은 각도를 가지는 점을 찾아내는 것을 근사계산하는데, 이는 레이에 대해 가장 짧은 거리를 가진 점을 찾아 냄으로써 수행됩니다. 구를 다룰 때 이것은 직관적입니다:


식 11


여기에서, L 은 쉐이딩 지점에서 라이트의 중심까지의 벡터이며, sourceRadius 는 라이트 구의 반지름이며, r 은 반사 벡터입니다. 그 레이가 구와 충돌하는 경우에는, 계산된 그 점은 구의 중심에 대해 레이상의 가장 가까운 점일 것입니다. 정규화를 하고 나면, 그것은 동일합니다.



방출된 빛의 중심을 구의 표면으로 움직임으로써, 구의 원호각( subtended angle )에 의해 효과적으로 넓어진 스펙큘러 분산을 얻게 됩니다. 그것은 미세표면 분산은 아니기는 하지만, 이는 정규화된 Phong 분산을 사용해서 최고로 잘 설명될 수 있습니다:


식 12


식 13


여기에서 φrrL 사이의 각도이며, φs 는 구의 원호각의 절반입니다. Ipoint 는 정규화되어 있으며, 이는 반구상에서의 적분의 결과가 1 임을 의미합니다. Isphere 는 명백히 더 이상 정규화되지 않으며, 파워 p 에 의존하며, 적분값은 더 클 수 있습니다.


그림 11: 식 13 에서 설명된 넓어진( widening )효과를 시각화.


이 에너지 증가를 근사계산하기 위해, 우리는 이전에 설명한 specular D modification 에 의해 사용된 것과 같은 추론을 적용합니다. 여기에서 우리는 라이트의 입체각에 기반해 분산을 넓어지게 만듭니다. 우리는 더 넓은 분산을 위한 정규화 요소( normalization factor )를 사용하고 원래의 정규화 요소를 대체합니다. GGX 의 경우에 정규화 요소는  입니다. 대표점 연산에 대한 정규화 근사계산을 유도하기 위해서, 우리는 넓어진 새로운 정규화 요소를 원래의 요소로 나눕니다:


식 14


대표점 기법의 결과는 우리의 요구를 모두 만족시킵니다. 에너지 보존을 올바로 고려함으로써, 머티리얼은 광원 크기를 고려하지 않고 동일하게 동작합니다. 매끈한 머티리얼들은 여전히 뾰족한 스펙큘러 하이라이트를 생성하며, BRDF 에 대한 입력만을 수정했기 때문에 우리 쉐이딩 모델은 영향을 받지 않습니다. 마지막으로 이것은 아티스트들이 원하는 모든 곳에 사용할 수 있을만큼 효율적입니다.


그림 12: 왼쪽은 참조, 오른쪽은 대표점( representative point ) 기법.

에너지 보존이 완벽하지는 않지만, 우리의 근사계산은 참조와 납득이 갈만큼 일치합니다.



Tube Lights


구형 라이트는 전구를 표현하는데 유용하고, 튜브 라이트( 캡슐 )는 우리가 실세계에서 매우 자주 접하는 형광등을 표현하는데 유용합니다. 시작하면서, 우리는 길이를 가지지만 반지름이 0 인, 선형 라이트라고 불리는 튜브 라이트를 해결했습니다. 라인 세그먼트에 대한 복사조도는 세그먼트가 수평선 위쪽에 존재하는 한 분석적으로 적분될 수 있습니다 [16, 17]:


식 15


여기에서 L0 과 L1 은 쉐이딩 지점에서 세그먼트의 끝점까지의 벡터입니다.


우리는 이 공식을 수정해 음의 복사조도, 0 으로 나누기를 방지했고, 길이가 0 일 때 포인트 라이트 falloff 와 일치시켰습니다.


식 16


선형적인 라이트 스펙큘러를 위해, 우리는 다음 공식들에서 t 에 대해 풀 필요가 있습니다:


식 17


Picott [16] 은 r 에 대한 가장 작은 각도를 위해 t 를 발견했습니다:


식 18


구의 경우와 같이, 우리는 가장 짧은 거리가 아니라 가장 작은 각도를 근사계산하고 풀었습니다:


식 19


There are edge cases that aren't properly handled such that this won't always find the closest point but it is little cheaper to calculate and seems to produce just as reasonable of results as Equation 18.


식 18 과 식 19 는 모두 레이 대신에 라인으로서 r 을 취급하기 때문에, 이 두 해법은 라인 세그먼트로부터 멀리 떨어진 곳을 가리키는 레이들을 제대로 다룰 수 없다는 것을 기억해야만 합니다. 이는 완벽하게 평평한 표면에서라 할지라도 한 범에서 다른 점으로 갈 때 갑작스런 변화를 발생시킬 수 있습니다. 이는 반사 레이가 라이트를 향해 가리키고 있다가 멀리 떨어진 곳을 가리키게 될 때 발생할 수 있습니다. 우리는 계산된 점과 각의 끝점들 사이에 있는 점을 선택함으로써 이 문제를 해결할 수 있지만, 그 비용은 비쌉니다. 현재로서는 우리는 아티팩트를 그냥 받아들여야 합니다.


에너지를 보존하기 위해서 우리는 구형 라이트를 위해서 사용했던 것과 같은 개념을 적용합니다. 스펙큘러 분산은 라이트의 지표각에서 넓어지지만, 이번에는 한 차원으로만 넓어집니다. 그래서 우리는 GGX 의 비등방성 버전을 사용합니다 [2]. 비등방성 GGX 를 위한 정규화 요소는 

 입니다. 여기에서 등방성의 경우에는  입니다. 이는 우리에게 다음을 제공합니다:


식 20


우리는 라이트의 원점만을 변경했고 에너지 보존을 적용했기 때문에, 이 연산들은 누적될 수 있습니다. 라인 세그먼트와 구를 사용해서 그렇게 함으로써, 튜브 라이트의 행동에 잘 맞도록 도형들과 모델들에 대한 convolution 을 근사계산합니다. 튜브 라이트의 결과는 아래 그림 13 에 나와 있습니다.


그림 13: 대표점 기법을 에너지 보존과 함께 사용한 튜브 라이트.


우리는 대표점 기법을 에너지 보존 기법과 함께 사용한 것이 단순한 도형에 대해 효율적이며 구와 튜브에 기반해서 미래에는 다른 도형들도 적용하고자 합니다. 특히, 우리는 더욱 복잡하고 다양한 색상을 가진 광원을 표현하기 위해서 텍스쳐를 입힌 쿼드를 적용할 생각입니다.


Conclusion


쉐이딩, 머티리얼, 라이팅의 영역에서 좀 더 물리에 기반한 구현으로 이동하고자 하는 시도는 매우 성공적인 것으로 증명되었습니다. 그것은 최근의 Infiltrator 데모에서의 비주얼에 크게 기여했으며, 우리는 이러한 개선을 앞으로의 프로젝트들에서 사용하려는 계획을 가지고 있습니다. In fact, in cases where it is practical these changes have been integrated into Fortnite, a project well into development before this work began. 우리는 더 많은 유연성과 확장성이라는 목적을 가지고 다양한 모든 씬과 모든 수준의 하드웨어에서 물리기반 접근법의 이점을 취할 수 있게 한다는 목적을 가지고 계속해서 이러한 영역들을 개선해 나가려고 합니다.


Acknowledgements


Epic Games 에 감사드리고 싶습니다. 특히 이 작업에 도움을 준 렌더링 팀의 모두와 방향성 및 피드백을 제공해 주고 결국에는 그것을 사용해 아름다운 것을 만들어 준 아티스트들에게 감사드립니다. Sebastien Legarde 에게 특별한 감사를 드리고 싶은데요, 그는 나의 중요도 샘플링 수학에서의 실수를 찾아 주었으며, 우리 환경 BRDF 의 개발에 도움을 주었습니다. Never underestimate how valuable it can be to have talented licensees around the world looking over the code you write. 마지막으로 가치있는 피드백을 주신 Stephen Hill 과 Stephen McAuley 에게 감사드리고 싶습니다.


Bibliography


[1] AMD, CubeMapGen: Cubemap Filtering and Mipchain Generation Tool. http://developer.amd.com/resources/archive/archived-tools/gpu-tools-archive/cubemapgen/


[2] Burley, Brent, “Physically-Based Shading at Disney”, part of “Practical Physically Based Shading in Film and Game Production”, SIGGRAPH 2012 Course Notes. http://blog.selfshadow.com/publications/s2012-shading-course/


[3] Colbert, Mark, and Jaroslav Krivanek, “GPU-based Importance Sampling”, in Hubert Nguyen, ed., GPU Gems 3, Addison-Wesley, pp. 459–479, 2007. http://http.developer.nvidia.com/GPUGems3/gpugems3_ch20.html


[4] Coffin, Christina, “SPU Based Deferred Shading in Battlefield 3 for Playstation 3”, Game Developers Conference, March 2011. http://www.slideshare.net/DICEStudio/spubased-deferredshading-in-battlefield-3-for-playstation-3


[5] Cook, Robert L., and Kenneth E. Torrance, “A Reflectance Model for Computer Graphics”, Computer Graphics (SIGGRAPH ’81 Proceedings), pp. 307–316, July 1981.


[6] Cook, Robert L., and Kenneth E. Torrance, “A Reflectance Model for Computer Graphics”, ACM Transactions on Graphics, vol. 1, no. 1, pp. 7–24, January 1982. http://graphics.pixar.com/library/ReflectanceModel/


[7] Drobot, Micha l, “Lighting Killzone: Shadow Fall”, Digital Dragons, April 2013. http://www.guerrilla-games.com/publications/


[8] Gotanda, Yoshiharu, “Practical Implementation of Physically-Based Shading Models at tri-Ace”, part of “Physically-Based Shading Models in Film and Game Production”, SIGGRAPH 2010 Course Notes. http://renderwonk.com/publications/s2010-shading-course/


[9] Hoffman, Naty, “Background: Physics and Math of Shading”, part of “Physically Based Shading in Theory and Practice”, SIGGRAPH 2013 Course Notes. http://blog.selfshadow.com/publications/s2013-shading-course/


[10] Lagarde, S´ebastien, “Spherical Gaussian approximation for Blinn-Phong, Phong and Fresnel”, June 2012. http://seblagarde.wordpress.com/2012/06/03/spherical-gaussien-approximationfor-blinn-phong-phong-and-fresnel/


[11] Lazarov, Dimitar, “Getting More Physical in Call of Duty: Black Ops II”, part of “Physically Based Shading in Theory and Practice”, SIGGRAPH 2013 Course Notes. http://blog.selfshadow.com/publications/s2013-shading-course/


[12] Martinez, Adam, “Faster Photorealism in Wonderland: Physically-Based Shading and Lighting at Sony Pictures Imageworks”, part of “Physically-Based Shading Models in Film and Game Production”, SIGGRAPH 2010 Course Notes. http://renderwonk.com/publications/s2010-shadingcourse/


[13] Mittring, Martin, and Bryan Dudash, “The Technology Behind the DirectX 11 Unreal Engine Samaritan Demo”, Game Developer Conference 2011. http://udn.epicgames.com/Three/rsrc/Three/DirectX11Rendering/MartinM_GDC11_DX11_presentation.pdf


[14] Mittring, Martin, “The Technology Behind the Unreal Engine 4 Elemental demo”, part of “Advances in Real-Time Rendering in 3D Graphics and Games Course”, SIGGRAPH 2012. http://www.unrealengine.com/files/misc/The_Technology_Behind_the_Elemental_Demo_16x9_(2).pdf


[15] Oat, Chris, “Ambient Aperture Lighting”, SIGGRAPH 2006. http://developer.amd.com/wordpress/media/2012/10/Oat-AmbientApetureLighting.pdf


[16] Picott, Kevin P., “Extensions of the Linear and Area Lighting Models”, Computers and Graphics, Volume 12 Issue 2, March 1992, pp. 31-38. http://dx.doi.org/10.1109/38.124286


[17] Poulin, Pierre, and John Amanatides, “Shading and Shadowing with Linear Light Sources”, IEEE Computer Graphics and Applications, 1991. http://www.cse.yorku.ca/~amana/research/


[18] Quilez, Inigo, “Spherical ambient occlusion”, 2006. http://www.iquilezles.org/www/articles/sphereao/sphereao.htm


[19] Schlick, Christophe, “An Inexpensive BRDF Model for Physically-based Rendering”, Computer Graphics Forum, vol. 13, no. 3, Sept. 1994, pp. 149–162. http://dept-info.labri.u-bordeaux.fr/~schlick/DOC/eur2.html


[20] Snow, Ben, “Terminators and Iron Men: Image-based lighting and physical shading at ILM”, part of “Physically-Based Shading Models in Film and Game Production”, SIGGRAPH 2010 Course Notes. http://renderwonk.com/publications/s2010-shading-course/


[21] Walter, Bruce, Stephen R. Marschner, Hongsong Li, Kenneth E. Torrance, “Microfacet Models for Refraction through Rough Surfaces”, Eurographics Symposium on Rendering (2007), 195–206, June 2007. http://www.cs.cornell.edu/~srm/publications/EGSR07-btdf.html


[22] Wang, Lifeng, Zhouchen Lin, Wenle Wang, and Kai Fu, “One-Shot Approximate Local Shading” 2006.

  1. 이 weighting 은 단순한 형태로 남겨진 식 7 에는 표현되어 있지 않습니다. [본문으로]
  2. 우리는 R16G16 포맷을 사용합니다. 왜냐하면 해상도가 중요하다는 것을 발견했기 때문입니다. [본문으로]
  3. 그들의 쉐이딩 모델은 서로 다른 D 와 G 함수들을 사용합니다. [본문으로]
  4. This tallies with observations from other developers [7, 8]. [본문으로]

원문 : Moment of inertia, Wikipedia

주의 : 허락받고 번역한 것이 아니므로 언제든 내려갈 수 있습니다.

주의 : 번역이 개판이므로 이상하면 원문을 참조하세요.

주의 : 번역은 소개, 정의, 단순 진자 항목까지 되어 있습니다. 더 많은 정보는 원문에서 확인하시기 바랍니다.



Moment of inertia


이 기사는 회전하는 오브젝트의 질량 관성 모멘트( mass moment of inertia )에 대한 것입니다. 빔의 휨( beam bending )에서의 단면 관성 모멘트에 대해서 알고자 한다면 second moment of area 를 참조하십시오.


강체( rigid body ) 의 질량 관성 모멘트( moment of inertia )는 다른 말로는 각질량( angular mass )이나 회전 관성( rotational inertia ) 이라고도 알려져 있는데, 이는 회전 축에 대한 각 가속도( angular acceleration )를 위해 필요한 토크( torque, 돌림힘 )을 결정하는 텐서( tensor, 긴장 )입니다.  이는 물체( body )의 질량 분포( mass distribution ) 및 선택된 축에 의존하며, 모멘트가 클수록 바디의 회전을 변경하는데 더 많은 돌림힘이 요구됩니다. 이는 extensive( additive ) property[각주:1] 입니다 : 복합시스템의 관성 모멘트는 ( 같은 축에 대해 수집된 ) 그것을 구성하는 서브시스템의 관성 모멘트의 합입니다. 그것의 정의들 중 하나가 축 r 로부터의 거리 관점에서의 질량에 대한 2차 모멘트이며, 전체 질량 Q 에 대한 적분입니다.



평면에서 회전하도록 제약이 걸려있는 물체들에 대해서는, 평면과 수직인 축에 대한 관성 모멘트만 고려해도 충분합니다. 3 차원에서 자유롭게 회전하는 물체들에 대해서는, 그것들의 모멘트들은 대칭 3x3 행렬에 의해 기술될 수 있습니다; 각 물체는 상호 수직적인 축들( mutually perpendicular axes )의 집합을 가지는데, 이 행렬은 대각행렬이며 그 축들에 대한 토크들은 다른 축들과는 독립적으로 작용합니다.


Introduction



물체가 축 주변을 회전하거나 자유롭게 회전할 때, 그것의 각 운동량( angular momentum )을 변경하기 위해서는 토크가 작용해야만 합니다. 각 운동량을 주어진 비율로 변경하기 위해 필요한 토크의 양은 물체의 관성 모멘트에 비례합니다. 관성 모멘트는 표준 단위계에서는 killogram-squre meters( kg ˙ m2 )로 표현되며 imperial 이나 US 단위계에서는 pound-squre feet( lbm ˙ ft2 )으로 표현됩니다.


회전 운동역학( rotational kinetics )에서의 관성 모멘트는 선형 운동역학에서의 질량( 관성 )과 같은 역할을 수행합니다 - 둘다 물체의 움직임을 변경하는데 대한 저항으로써 작용합니다. 관성 모멘트는 회전 축 주변에 질량이 어떻게 분포되어 있느냐에 의존하며, 이는 어떤 축이 주어졌냐에 따라 매우 다양합니다. 점질량의 경우에, 어떤 축에 대한 관성 모멘트는 d2m 으로 주어지는데, 여기에서 d 는 축으로부터의 거리이며 m 은 질량입니다. 확장된 물체( extended body )의 경우에, 관성 모멘트는 작은 조각의 질량에다가 선택된 축으로부터의 거리의 제곱을 곱한 것들의 전체 합일 뿐입니다. 표준적인 모양을 가지고 균일한 밀도를 가진 확장된 물체의 경우에는, 보통 이러한 합은 오브젝트의 차수, 모양, 전체 질량등에 의존하는 간단한 식으로 표현될 수 있습니다.


1673 년에 Christiaan Huygens 는, 복합 진자( compound pendulum )라 알려진, 회전축( pivot )에 매달린 물체의 진동에 대한 자신의 연구에서 이 파라미터를 소개했습니다. 관성 모멘트라는 개념은 Leonhard Euler 에 의해 1765 년에 그의 저서인 Theoria motus corporum solidorum seu rigidorum 에서 소개되었으며, 이는 Euler's second law 에 통합되었습니다.


복합 진자의 자연적 진동 주파수는 진자의 질량에 작용하는 중력으로 인해 발생하는 토크와 관성 모멘트에 의해 정의되는 가속도에 대한 저항의 비율로부터 획득됩니다( 역주 : 문장이 길어서 헷갈리는데, "토크 vs 저항" 이라고 보심 될듯합니다 ). 이 자연적 주파수를 점질량으로 구성된 단순 진자의 주파수와 비교하는 것은 확장된 물체의 관성 모멘트를 위한 수학적 공식을 제공합니다.


관성 모멘트는 강체의 운동량( momentum ), 운동 에너지( kinetic energy ), 뉴턴의 운동 법칙( Newton's laws of motion )에서 모양과 질량을 겹합한 물리적 속성으로서 나타나기도 합니다. 평면적( planar ) 이동과 공간적( spatial ) 이동에서 관성 모멘트가 나타나는 방식에는 흥미로운 차이점이 있습니다. 평면적 이동은 관성 모멘트를 정의하는 단일 스칼라( scalar ) 값을 가지는 반면, 공간적 이동은 같은 계산이 관성 모멘트에 대한 3 x 3 행렬을 산출하며, 이는 관성 행렬 혹은 관성 텐서라 불립니다.


회전하는 플라이휠( flywheel, 기계나 엔진의 회전속도에 안정감을 주기 위한 무거운 바퀴 - 네이버 사전 )의 관성 모멘트는 회전 출력을 부드럽게 만들기 위해 적용되는 토크의 다양성( variation )에 저항하기 위해 기계에서 사용됩니다. 비행기의 장축, 수평축, 수직축에 대한 관성 모멘트는 자신의 날개, 뒷날개( elevator ), 꼬리의 제어면( control surface )에 적용되는 steering forces 가 비행기의 roll, pitch, yaw 에 미치는 영향을 결정합니다.


Definition



관성 모멘트 I 는 주축( principal axis ) 주위의 각속도( angular velocity ) ω 에 대한 계( system )의 각운동량( angular momentum ) L 의 비율로서 정의됩니다.



계의 각운동량은 상수입니다. 그래서 관성 모멘트가 작아질수록 각속도는 증가해야만 합니다. 이는 회전하고 있는 피규어 스케이터가 더 빠른 회전을 위해 바깥으로 뻗은 팔을 당기거나 다이빙 선수가 자신의 몸을 껴안기 형태로 굽힐 때 발생합니다.


회전하는 피규어 스케이터는 팔을 안으로 당김으로써 관성 모멘트를 줄일 수 있습니다.

이는 스케이터가 더 빠르게 회전하게 만드는데, 

그 이유는 각운동량 보존 법칙( conservation of angular momentum ) 때문입니다.



물체의 모양이 변하지 않으면, 그것의 관성 모멘트는 뉴튼의 운동 법칙에서 주축 주변의 각가속도( angular acceleration )에 대한 물체상에 적용된 토크 τ 의 비율로 나타납니다.



단순 진자( simple pendulum )에서 이 정의는 진자의 질량 m 항과 회전 중심으로부터의 거리 r  항으로 관성 모멘트 I 를 위한 공식을 산출합니다.



그러므로, 관성 모멘트는 물체와 그것의 지아메트리( geometry ) 혹은 모양( shape )의 질량 m 과 회전 축으로부터의 거리 r 에 모두 의존합니다.


이 단순한 공식은 임의의 모양을 가진 물체를 위한 관성 모멘트를 정의하기 위해서 일반화됩니다. 점질량 dm 을 축 S 에 대한 수직 거리 r 의 제곱과 곱한것을 모두 더함으로써 이루어집니다.


일반적으로, 질량 m 을 가진 물체가 주어졌을 때, 유효 반지름( effective radius ) k 는 질량 중심을 관통하는 축을 위해서 정의될 수 있으며, 그러한 물체의 관성 모멘트의 값은 다음과 같습니다.



여기에서 k 는 선회 반경( radius of gyration )이라 알려져 있습니다.


Simple pendulum



관성 모멘트는 단순 진자를 사용해서 측정될 수 있습니다. 왜냐하면 그것은 중력에 의해서 발생되는 회전에 대한 저항이기 때문입니다. 수학적으로 볼 때, 진자의 관성 모멘트는 ( 역주 : 끈이 고정된 ) 회전 중심에 대한 진자의 각가속도에 대한 진자의 회전중심에 대해 작용하는 중력 때문에 발생하는 토크의 비율입니다. 단순 진자의 경우, 이는 입자의 질량 m 과 회전축에 대한 거리 r 의 제곱의 곱으로 표현됩니다.



이는 다음과 같이 보일 수 있습니다: 단순 진자의 질량에 적용되는 중력의 힘은 진자 이동 평면에 수직인 축 주변의 토크를 생성합니다. 



여기에서 r 은 거리벡터인데 이는 토크 축에 대한 힘과 수직으로 작용합니다. 여기에서 F 는 질량에 대한 알짜힘( net force )의 탄젠트 요소( tangential component ) 입니다. 이 토크와 연관된 것은 끈의 각가속도 α 와 이 축 주변의 질량입니다. 그 질량은 원으로 제한되므로, 질량에 대한 접선 가속도( tangential acceleration )는 다음과 같습니다.



F = ma 이기 때문에, 토크 공식은 다음과 같습니다:



여기에서 e 는 진자 평면과 수직인 단위 벡터입니다( 두 번째 단계에서 마지막 단계로 가는 것은 BAC-CAB rule( vector triple product )때문인데, 이는 α가 항상 r 에 수직임을 이용합니다 ). I = mr2 이라는 물리량은 회전 중심 주변의 단일 질량에 대한 관성 모멘트입니다.


 I = mr2 은 단순 진자의 각운동량에서도 나타나는데, 여기에서는 회전축 중심의 진자 질량에 대한 속도 vω x r 로부터 계산되는데, 여기에서 ω 는 회전 중심 주변의 질량에 대한 각속도입니다. 이 각운동량은 다음에 의해 주어집니다.



그것과 비슷한 수학이 이전 공식을 유도하는데 사용되었습니다.


이와 유사하게 진자 질량에 대한 운동 에너지( kinetic energy )는 회전축 중심의 진자의 가속도에 의해서 정의됩니다.



이는  I = mr2 물리량은 회전 관성을 정의하기 위해서 물체의 모양과 질량을 결합한 것임을 보여줍니다. 임의의 모양을 가진 물체의 관성 모멘트는 물체 내의 질량 모든 질량 요소들에 대한 mr2 값의 합입니다.

  1. Intensive property 는 측정된 물질의 전체 양에 의존하지 않는 값을 가지는 물리량이며, extensive property 는 하위시스템들을 합산한 만큼의 양을 가지는 물리량을 의미합니다. [본문으로]

'물리_수학_기하학' 카테고리의 다른 글

중력과 수직항력  (10) 2019.07.07
장력( Tension )  (13) 2019.06.26
Matrix major & multiplication  (2) 2018.08.12
[ 번역 ] The Perils of Floating Point  (0) 2018.08.10
[ 번역 ] Depth Precision Visualized  (11) 2017.06.04
[ 번역 ] 캐릭터 애니메이션 : 스켈레톤과 역운동학  (0) 2016.10.01
모멘트( moment )  (22) 2016.01.06
Curve  (0) 2015.10.04
[ 일부 번역 ] CLIPPING USING HOMOGENEOUS COORDINATES  (0) 2013.04.29
Arc length of curve  (0) 2012.09.21

원문 : Other UI Optimization Techniques And Tips

주의 : 번역이 개판이므로 이상하면 원문을 참조하십시오.

주의 : 허락받고 번역한 것이 아니므로 언제든지 내려갈 수 있습니다.



Other UI Optimization Techniques And Tips


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


종종 UI 를 최적화할 명백한 방법이 없을 때도 있습니다. 이 섹션은 UI 성능을 개선하는데 도움을 줄 수도 있지만 구조적으로 "명백"하지는 않은, 유지보수하기는 어려울 수도 있거나 이상한 사이드 이펙트를 가질 수도 있는 몇 가지 제안을 하고자 합니다. 다른 것들은 초기 개발을 단순화하기 위한 UI 에서의 동작들을 위한 우회책들인데, 이는 상대적으로 성능 문제를 쉽게 발생시킬 수 있도록 해 줍니다.


RectTransform-Based Layouts


Layout 컴포넌트는 상대적으로 비쌉니다. 왜냐하면 그것들은 그것이 갱신될 때마다 자식 요소들의 크기와 위치를 재계산해야만 하기 때문입니다( 세부 사항을 원하면 Fundamentals 챕터의 Graphic rebuild 섹션을 참고하십시오 ). 만약 주어진 Layout 에 상대적으로 적고 고정된 개수의 요소들이 존재한다면, Layout 은 상대적으로 단순한 구조를 가지며, RectTransform 기반 레이아웃으로 대체하는 것이 가능할 것입니다.


RectTransform 에 대한 앵커를 할당함으로써, RectTrasnform 의 위치와 크기는 그것의 부모에 기반해 스케일링되도록 만들어질 수 있습니다. 예를 들어 단순한 두 개의 컬럼으로 구성된 레이아웃은 두 개의 RectTransform 들로 만들어질 수 있습니다:


    • 왼쪽 컬럼의 앵커는 X:(0, 0.5), Y(0,1) 이어야 합니다.
    • 오른쪽 컬럼의 앵커는 X(0.5,1), Y(0,1) 이어야 합니다.


RectTransform 의 크기와 위치에 대한 계산은 Transform 시스템 자체에 의해 네이티브 코드에서 수행될 것입니다. 이는 일반적으로 Layout 시스템에 의존하는 것 보다 더 좋은 성능을 냅니다. 또한 RectTransform 기반 레이아웃을 설정한 MonoBehaviour 를 작성하는 것도 가능합니다. 그러나 이는 상대적으로 복잡한 작업이며, 이 가이드가 다루는 영역에서 벗어납니다.


Disabling Canvas Renderers


UI 의 서로 다른 부분을 보여주거나 가릴 때, 보통 UI 의 루트에 있는 게임오브젝트를 enable 시키거나 disable 시킵니다. 이는 disable 된 UI 내의 컴포넌트가 input 이나 유니티 콜백을 받지 않도록 만듭니다.


그러나, 이는 Canvas 로 하여금 자신의 VBO 데이터를 버리도록 만듭니다. Canvas 를 다시 enabling 하는 것은 Canvas( 및 그것의 모든 Sub-Canvas ) 로 하여금 리빌드 절차와 리배칭 절차를 실행하도록 만듭니다. 만약 이러한 일이 자주 발생한다면, 증가된 CPU 사용량이 애플리에이션의 프레임 율을 뚝 떨어뜨릴 수 있습니다.


가능하다면, 이상하기는 하지만, UI 를 자신의 Canvas 나 Sub-canvas 상에 shown/hidden 되도록 배치하고 Canvas 나 Sub-canvas 에 붙어 있는 CanvasRenderer 컴포넌트를 enable/disable 시키는 것은 거의 하지 않는 우회책이 있습니다.


이는 UI 의 메쉬들이 그려지지 않도록 만들지만, 그것들은 메모리 상에 남아 있게 되며 원래의 배칭이 보존됩니다. 더우기 OnEnable 이나 OnDisable 콜백이 UI 계층상에서 호출되지 않을 것입니다.


그러나 이는 UI 의 Graphic 들을 GraphicRegistry 에서 제거하지 않으므로 그것들은 여전히 Graphic Raycast 를 검사하기 위해 컴포넌트의 리스트 상에 제출될 거라는 것에 주의하십시오. 이는 감춰진 UI 내의 어떠한 MonoBehaviour 들도 disable 시키지 않을 것이며, 이러한 MonoBehaviour 들은 여전히 Update 와 같은 유니티 생명주기 콜백들을 받을 것입니다.


이 문제를 피하기 위해서는, 이러한 방식으로 disable 될 UI 상의 MonoBehaviour 들이 유니티 생명주기 콜백들을 직접적으로 구현하지 않지만 UI 의 루트 게임오브젝트 상의 "Callback Manager" MonoBehaviour 로부터 자신들의 콜백을 받도록 해야 합니다. 이 "Callback Manager" 는 UI 가 shown/hidden 될 때마다 통지를 받아서 생명주기 이벤트들이 필요에 따라 전파되거나 전파되지 않도록 보장할 수 있습니다. 이 "Callback Manager" 패턴에 대한 더 많은 설명은 이 가이드의 영역을 벗어납니다.


Assigning Event Cameras


만약 가 월드 공간 카메라 모드나 스크린 공간 카메라 모드로 렌더링하도록 설정되어 있는 Canvas 들과 함께 유니티의 내장 Input Manager 를 사용하고 있다면, 항상 각각에 대해 Event Camera 나 Renderer Camera 속성을 설정하는 것이 중요합니다. 스크립트에서, 이는 항상 worldCamera 속성으로 노출됩니다.


만약 이 속성이 설정되지 않는다면, 유니티 UI 는 Main Camera 태그를 가진 게임 오브젝트에 붙어 있는 Camera 컴포넌트들을 검색함으로써 메인 카메라를 검색할 것입니다. 이 검색은 월드 공간 캔버스나 로컬 공간 캔버스당 적어도 한 번은 발생할 것입니다. GameObject.FindWithTag 는 느린 것으로 알려져 있기 때문에, 모든 월드 공간 캔버스와 카메라 공간 캔버스들은 디자인시나 초기화시에 할당된 Camera 속성들을 가질 것을 강력히 권합니다.


이 문제는 Overlay 캔바스에서는 발생하지 않습니다.

원문 : Optimizing UI Controls

주의 : 번역이 개판이므로 이상하면 원문을 참조하십시오.

주의 : 허락받고 번역한 것이 아니므로 언제든 내려갈 수 있습니다.



Optimizing UI Controls


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


이 섹션은 특정 유형의 UI 컨트롤들을 제출하는 것에 초점을 맞춘 최적화 가이드의 섹션입니다. 대부분의 컨트롤들은 성능 관점에서 상대적으로 유사하지만, 두 가지는 게임이 출시 가능한 상태에 가까워졌을 때 많은 성능 이슈를 일으키므로 특별합니다.


UI Text


유니티의 내장 Text 컴포넌트는 래스터화된 텍스트 글리프( glyph )를 UI 내부에 디스플레이하기 위한 편한 방법입니다. 그러나 일반적으로 알지 못하는 여러 가지 동작이 존재하며, 아직까지 주로 성능 핫스팟이 됩니다. UI 에 텍스트를 추가할 때, 텍스트 글리프는 실제로는 글자 하나당 개별적인 쿼드( quad )로 렌더링된다는 점을 기억해야 합니다. 이러한 쿼드들은 글리프를 둘러싼 빈 공간의 많은 부분을 차지하는 경향이 있습니다. 이는 그것의 모양에 의존하며, 원치않게 다른 UI 요소들의 배칭을 저해하는 텍스트가 배치되는 경우가 많습니다.


Text mesh rebuilds


한 가지 주요 이슈는 UI 텍스트 메쉬를 리빌드하는 것입니다. UI 텍스트 컴포넌트가 변경될 때마다, 그 텍스트 컴포넌트는 실제 텍스트를 디스플레이하기 위해서 사용되는 폴리곤들을 재계산해야 합니다. 이 재계산은 텍스트가 변하지 않더라도 텍스트 컴포넌트나 그것의 부모 게임 오브젝트들이 단순히 disable 되거나 다시 enable 될 때도 발생합니다.


이러한 동작은 점수판이나 통계를 위해 많은 개수의 레이블을 디스플레이하는 UI 에서 문제가 됩니다. 유니티 UI 를 가리거나 보여주는 가장 일반적인 방법은 UI 를 포함하는 게임오브젝트를 enable/disable 시키는 것이며, 많은 개수의 텍스트 컴포넌트를 가지고 있는 UI 는 그것들이 디스플레이될 때마다 원치않는 프레임율 스파이크를 일으키게 될 것입니다.


이 이슈에 대한 잠재적인 우회책을 원한다면, 다음 챕터의 Disabling Canvas Renderes 를 참고하시기 바랍니다.


Dynamic fonts and font atlases


동적 폰트는 전체 문자들의 집합이 매우 많거나 런타임에 앞서 알려지지 았을 때 텍스트를 렌더링하기 편한 방법을 제공합니다. 유니티 구현에서는, 이러한 폰트들은 UI Text 컴포넌트 내에 문자들에 기반해 런타임에 글리프 아틀라스를 빌드합니다.


로드된 각각의 개별 폰트 오브젝트는 자신만의 텍스쳐 아틀라스를 유지할 것입니다. 심지어는 그것이 다른 폰트들과 동일한 폰트 패밀리를 사용한다고 해도 말이죠. 예를 들어, 한 컨트롤 내에서 굵은( bold ) 텍스트를 가진 가진 Arial 을 사용하고, 다른 컨트롤에서 Arial Bold 를 사용하면 동일한 결과를 산출하지만, 유니티는 두 개를 개별적인 텍스쳐 아틀라스에 유지할 것입니다 - 하나는 Arial 을 위해 다른 하나는 Arial Bold 를 위해( 역주 : 하나는 Arial 폰트를 사용하고 텍스트에 굵기 옵션을 준 것이고, 다른 하나는 Arial Bold 폰트를 사용한 것을 의미하는 듯 ).


성능 관점에서 볼 때, 유니티 UI 의 동적 폰트가 개별 크기, 스타일, 문자를 위해 폰트 텍스쳐 아틀라스에 하나의 글리프를 유지한다는 것을 이해하는 것이 중요합니다. 즉, 만약 UI 가 두 개의 텍스트 컴포넌트를 가지고 있고, 둘다 'A' 라는 문자를 디스플레이한다고 하면:


    • 만약 두 Text 컴포넌트가 같은 크기를 공유한다면, 폰트 아틀라스는 그것 안에 하나의 글리프를 가지게 될 것입니다.
    • 만약 두 Text 컴포넌트가 같은 크기를 공유하지 않는다면( 예를 들어 하나는 16 포인트이고 다른 하나는 24 포인트라면 ), 폰트 아틀라스는 서로 다른 크기의 문자 'A' 를 위해 두 개의 복사본을 가지게 될 것입니다.
    • 만약 하나의 Text 컴포넌트는 bold 이고 다른 하나는 그렇지 않다면, 폰트 아틀라스는 굵은 'A' 와 보통 'A' 를 포함하게 될 것입니다.


동적 폰트를 가진 UI Text 오브젝트에 아직 폰트 텍스쳐로 래스터화되지 않은 글리프가 있다면, 폰트 텍스쳐 아틀라스는 반드시 리빌드되어야만 합니다. 새로운 글리프가 현재 아틀라스에 맞다면, 그것이 추가되고 그 아틀라스는 그래픽 디바이스에 다시 업로드될 것입니다. 그러나 현재 아틀라스가 너무 작다면, 시스템은 아틀라스를 리빌드할 것입니다. 이는 두 개의 단계로 수행됩니다.


첫째, 아틀라스는 같은 크기로 리빌드됩니다. 이 때 현재 활성화된 UI Text 컴포넌트에 의해 보이고 있는 글리프만이 사용됩니다. 만약 시스템이 현재 사용중인 글리프들을 새로운 아틀라스에 끼워 맞추는 것에 성공한다면, 그것은 그 아틀라스를 래스터화하고 다음 단계로 진행하지 않습니다.


둘째, 만약 현재 사용중인 글리프 집합이 현재 아틀라스와 같은 크기의 아틀라스에 끼워 맞춰질 수 없다면, 해상도가 더 낮은 쪽을 두 배로 늘린 더 큰 아틀라스가 생성됩니다. 예를 들어 512x512 아틀라스는 512x1024 아틀라스로 확장됩니다.


위의 알고리즘 때문에, 동적 폰트 아틀라스는 한 번 생성되고 나면 크기가 늘어나기만 합니다. Given the cost of rebuilding the texture atlases, 리빌드 동안 반드시 최소화해야 합니다. 이는 두 가지 방식으로 수행될 수 있습니다:


가능할 때마다, 원하는 글리프 셋을 위해서 비-동적 폰트들과 preconfigure support 를 사용하십시오. 이는 일반적으로 제약이 잘 된 Latin/ASCII 문자들과 같은 적은 범위의 크기를 가지는 문자 집합을 사용하는 UI 들을 위해 잘 동작합니다.


만약 전체 유니코드 셋과 같은 극단적으로 큰 범위를 가진 문자들이 지원되어야만 한다면, 폰트는 Dynamic 으로 설정되어야만 합니다. 예측할 수 있는 성능 문제들을 피하기 위해서는, 시작시에 폰트 글리프 아틀라스를 Font.RequestCharactersInTexture 를 통해 적절한 문자들의 집합을 가지도록 미리 준비시키기 바랍니다.


폰트 아틀라스 리빌드는 변경되는 각 UI Text 컴포넌트들을 위해서 개별적으로 발동된다는 것에 주의하십시오. 극단적으로 많은 개수의 Text 컴포넌트들을 띄울 때는, Text 컴포넌트의 내용에서 유일한 문자들을 수집하고 폰트 아틀라스를 미리 준비해야 이득입니다. 이는 글리프 아틀라스가 새로운 글리프가 나타날 때마다 한 번씩 리빌드되지 않고 한 번만 리빌드될 수 있도록 보장해 줄 것입니다.


폰트 아틀라스가 리빌드될 때, 활성화된 UI Text 컴포넌트에 현재 포함되어 있지 않은 모든 문자들은, 그것들이 Font.RequestCharactersInTexture 호출의 결과로서 원래부터 아틀라스에 추가되어 있는 경우라 할지라도, 새로운 아틀라스에 제출되지 않는다는 것에도 주의하시기 바랍니다. 이러한 제한을 우회하기 위해서는, 모든 원하는 문자들이 준비되어 있는 상태로 남아 있도록 하기 위해 Font.textureRebuilt 델리케이트를 구독하고 Font.characterInfo 를 질의하십시오.


Font.textureRebuilt 델리게이트는 현재 문서화되어 있지 않습니다. 그것은 단일 인자를 가진 유니티 이벤트입니다. 이 인자는 그것의 텍스쳐가 리빌드되어 있는 폰트입니다. 이 이벤트의 구독자는 다음 구문을 따라야 합니다:



Specialized glyph renderes


각 글리프 사이에 상대적으로 고정된 위치를 가지고 있는 잘 알려져 있는 글리프의 경우에는, 그들의 글리프를 디스플레이하는 커스텀 컴포넌트를 작성하는 것이 이득입니다. 이것의 예는 스코어 디스플레이가 있습니다.


점수를 위해, 디스플레이 가능한 문자들은 잘 알려진 글리프 셋( 숫자 0 ~ 9 )으로부터 그려지며, 지역에 따라 변하지 않고, 서로 고정된 거리로 보여집니다. 정수를 그것의 숫자로 분리하고 적절한 숫자 스프라이트를 렌더링하는 것은 상대적으로 단순합니다. This sort of specialized digit-display system can be built in a manner that is both allocationless and considerably faster to calculate, animate and display than the Canvas-driven UI Text component.


Fallback fonts and memory usage


큰 문자 셋을 지원해야만 하는 애플리케이션을 위해서는, 폰트 임포터의 "Font Names" 필드에서 많은 폰트들을 리스팅하고자 하는 마음이 듭니다. "Font Names" 필드에 리스팅된 모든 폰트들은 글리프가 주요 폰트 내에 배치될 수 없는 상황에서 대안으로 사용될 수 있을 것입니다. 폴백의 순서는 "Font Names" 필드에서 리스팅된 순서에 의해서 결정됩니다.


그러나 이러한 동작을 지원하기 위해서는 유니티는 "Font Names" 필드에서 리스팅된 모든 폰트들을 메모리에 로드해서 유지할 것입니다. 만약 폰트 문자 셋이 매우 크다면, 폴백 폰트에 의해 소비되는 메모리의 양이 매우 커질 것입니다. 이는 일본어 한자나 중국 문자들과 같은 그림 문자( pictographical ) 폰트를 포함할 때 자주 보이는 현상입니다.


Best Fit and performance


일반적으로, UI Text 컴포넌트의 Best Fit 설정은 절대 사용되어서는 안 됩니다.


"Best Fit" 는 동적으로, 이는 Text 컴포넌트의 바운딩 박스 내에 오우버플로우 없이 디스플레이될 수 있으며 구성 가능한 최소/최대 포인트 크기로 잘린, 가장 큰 정수 포인트 크기로 폰트의 크기를 조정합니다. 그러나 유니티는 디스플레이되고 있는 개별 문자의 크기별로 개별 글리프를 폰트 아틀라스에 렌더링하기 때문에, Best Fit 를 사용하면 다양한 크기의 글리프를 사용하는 아틀라스의 크기를 급격히 넘어서게 될 것입니다.


유니티 5.3 에서는, Best Fit 에 의해 사용되는 크기 검출이 선택적이지 않습니다. 그것은 It generates glyphs in the font atlas for each size increment tested, which further increases the amount of time required to generate font atlases. 이는 아틀라스 오우버플로우를 발생시키는 경향이 있는데, 이는 오래된 글리프가 아틀라스에서 제거되도록 만듭니다. Best Fit 계산을 위한 많은 횟수의 테스트 때문에, 이는 종종 다른 Text 컴포넌트에 의해 사용중인 글리프들을 퇴거시킬 것이고, 적절한 폰트 사이즈가 계산된 후에 적어도 한 번 더 폰트 아틀라스를 리빌드시킬 것입니다. 이러한 특정 이슈는 유니티 5.4 에서 교정되었습니다. 그리고 Best Fit 는 폰트 텍스쳐 아틀라스를 불필요하게 확장하지 않을 것이지만, 여전히 정적으로 크기가 정해진 텍스트보다는 훨씬 더 느립니다.


자주 사용하는 폰트 아틀라스의 리빌드는 런타임 성능을 급격히 떨어뜨릴 것이고 메모리 단편화를 일으킬 것입니다. Best Fit 로 설정된 Text 컴포넌트의 양이 많아질 수록, 이 문제가 악화될 것입니다.


Scroll Views


Fill-rate 문제 다음으로, 유니티 UI 의 스크롤 뷰는 일반적으로 두 번째 가는 런타임 성능 이슈입니다. 스크롤 뷰는 일반적으로 매우 많은 개수의 UI 요소들을 사용해 자신의 칸텐츠를 표현할 것을 요구합니다. 스크롤 뷰를 띄우는 기본적인 두 가지 접근법이 있습니다:


    • 모든 스크롤 뷰 칸텐츠를 표현하기 위해서 충분한 모든 요소들을 채웁니다.
    • 요소들을 풀링하여, 보여지는 칸텐츠를 표현하는 데 필요한 만큼 위치를 재조정합니다.


둘 다 문제를 가진 해결책들입니다.


첫 번째 해결책은 모든 UI 요소들을 인스턴스화기 위해서 필요한 시간을 증가시킵니다. 왜냐하면 표현해야 할 아이템이 늘어날 수록 스크롤 뷰를 리빌드하는 시간이 늘어나기 때문입니다. 한줌의 Text 컴포넌트만을 디스플레이할 필요가 있는 스크롤 뷰처럼, 스크롤 뷰 내에 요구되는 요소의 개수가 적다면, 단순함을 위해 이 기법이 선호됩니다.


두 번째 해결책은 현재 UI 와 레이아웃 시스템 하에서 올바르게 구현하기 위한 코드의 양이 너무 많습니다. 아래에서 나중에 두 가지 가능한 기법에 대해서 논의하도록 하겠습니다. 매우 복잡한 스크롤링 UI 에 대해서, 성능 문제를 피하기 위해서는 몇 가지 종류의 풀링 접근법이 필요합니다.


이러한 이슈들에도 불구하고, 모든 접근법들은 RectMask2D 컴포넌트를 스크롤 뷰에 추가함으로써 개선될 수 있습니다. 이 컴포넌트는 스크롤 뷰 뷰포트 외부에 존재하는 스크롤 뷰 요소들이, Canvas 가 리빌딩될 때 지오메트리가 생성되고 정렬되고 분석되어야 하는, drawable 요소의 리스트에 포함되지 않도록 보장해 줍니다.


Simple Scroll View element pooling


유니티 내장 Scroll View 컴포넌트를 사용하는 것의 자연스러운 이점의 대부분을 보존하면서 스크롤 뷰를 사용하는 오브젝트 풀링을 구현하기 위한 가장 단순한 방법은 하이브리드 접근법을 사용하는 것입니다:


UI 에 요소들을 놓기 위해서, 보이는 UI 요소들을 위한 "placeholder" 로서 Layout Element 컴포넌트를 게임오브젝트와 함께 사용하십시오. 이는 레이아웃 시스템이 스크롤 뷰의 칸텐트를 적절히 계산하도록 해 주고 스크롤바가 적절히 기능하게 해 줄 것입니다.


그리고 나서, 스크롤 뷰의 가시 영역의 보이는 부분에 충분히 맞게 보이는 UI 요소들에 대한 풀을 인스턴스화하고, 이것들을 위치 placeholder 들의 부모로 붙이십시오. 스크롤 뷰가 스크롤링되면, UI 요소들을 재사용해서 뷰에 스크롤된 칸텐트들을 디스플레이하십시오.


이는 배칭되어야 하는 UI 요소들의 개수를 지속적으로 줄이게 될 것입니다. 왜냐하면 배칭 비용은 RectTransform 의 개수가 아니라 Canvas 내의 CanvasRendere 의 개수에 기반해서만 증가할 것이기 때문입니다.


Problems with the simple approach


현재는, UI 요소의 부모가 변경되거나 이웃의 순서가 변경될 때마다, 그 요소와 그것의 하위 요소들은 갱신된 것으로 표시되며 그것들의 Canvas 가 강제로 리빌드됩니다.


그 이유는 유니티가 transform 의 부모를 변경하는 콜백과 이웃의 순서를 수정하기 위한 콜백을 분리하지 않았기 때문입니다. 이 이벤트들은 둘 다 OnTransformParentChanged 콜백을 부릅니다. 유니티 UI 의 Graphic 클래스의 소스( Graphics.cs )에서, 그 콜백이 구현되며 SetAllDirty 메서드를 호출합니다. Graphic 을 갱신함으로써, 시스템은 Graphic 이 다음 프레임에 렌더링되기 전에 그것의 레이아웃과 버텍스들을 리빌드할 수 있도록 만듭니다.


캔버스들에 스크롤 뷰 내의 각 요소에 대한 루트 RectTransform 을 할당하는 것이 가능합니다. 그러면 스크롤 뷰의 전체 칸텐츠가 아니라 부모가 변경된 요소들에 국한해서 리빌드를 할 것입니다. 그러나 이것은 스크롤 뷰를 렌더링하는 데 필요한 드로콜의 개수를 증가시키는 경향이 있습니다. 더우기, 스크롤 뷰 내부의 개별 요소들이 복잡하고 수십개의 Graphic 컴포넌트로 구성되어 있고, 특히 각 요소에 Layout 컴포넌트들이 매우 많다면, 그것들을 리빌드하는 비용은 저사양 디바이스에서 프레임율을 급격하게 떨어뜨리게 될 것입니다.


만약 스크롤 뷰 요소가 가변 크기를 가지지 않는다면, 레이아웃과 버텍스들에 대한 완전한 재계산은 불필요합니다. 그러나 이 동작을 피하는 것은 부모 변화나 이웃 순서 변화 대신에 위치 변화에 기반한 오브젝트 풀링 솔루션을 구현할 것을 요구합니다.


Position-based Scroll View Pools


위에서 언급한 문제들을 피하기 위해서, 오브젝트가 포함된 UI 요소들의 RectTransform 들을 단순하게 이동시킴으로써 오브젝트를 풀링하는 스크롤 뷰를 생성하는 것이 가능합니다. 움직여진 RectTransform 의 크기가 변경되지 않았다면 내용은 다시 빌드될 필요가 없으며, 이는 스크롤 뷰의 성능을 매우 개선하게 됩니다.


일반적으로는 이를 위해 ScrollView 의 커스텀 서브클래스를 작성하거나 커스텀 LayoutGroup 컴포넌트를 작성하는 것이 최선입니다. 후자는 일반적으로 더 단순한 솔루션이며, 유니티 UI 의 LayoutGroup 추상 기저 클래스의 서브클래스를 구현함으로써 성취할 수 있습니다.


커스텀 LayoutGroup 은 밑에 있는 소스 데이터들을 분석해 얼마나 많은 데이터 요소들이 디스플레이되어야 하고 스크롤 뷰의 Content RectTransform 이 적절히 리사이징될 수 있는지 판단합니다. 그리고 나서 그것은 ScrollView change event 들을 구독하고 이를 사용해 그것의 가시적 요소를 적절하게 재배치할 수 있습니다.

원문 : Fill-Rate, Canvases and Input

주의 : 번역이 개판이므로 이상하면 원문을 참조하십시오.

주의 : 허락받고 번역한 것이 아니므로 언제든 내려갈 수 있습니다.



Fill-Rate, Canvases and Input


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


이 챕터는 유니티 UI 를 구조화하는 것과 관련한 여러 이슈들에 대해 논의합니다.


Remediating Fill-Rate Issues


GPU 프래그먼트 파이프라인 상에서 부하를 제거하기 위해서 취해질 수 있는 두 가지 행동이 있습니다:


    • 프래그먼트 쉐이더의 복잡도를 줄이는 것입니다.
      • 더 많은 세부사항을 원한다면 "UI Shaders and low-spec devices" 섹션을 참고하십시오.
    • 샘플링되어야 하는 픽셀의 개수를 줄이는 것입니다.


UI 쉐이더는 일반적으로 표준화되어 있기 때문에, 가장 일반적인 문제는 단순히 fill-rate 용량을 초과하는 것입니다. 이는 대부분 UI 요소들이 매우 많이 겹쳐 그려지거나 화면의 많은 부분을 차지하는 UI 요소들이 많기 때문에 발생합니다. 둘다 높은 수준의 overdraw 를 유발할 수 있습니다.


fill-rate 에 대한 overutilization 을 줄이고 overdraw 를 줄이려면, 다음과 같은 해결책들을 고려해 보십시오.


Eliminating invisible UI


이 기법은, 플레이어에게 보이지 않는 비활성화된 요소들을 단순화하기 위해, 현존하는 UI 요소들을 최소로 재설계하는 것을 요구합니다. 가장 일반적인 경우는 불투명한 백그라운드를 가진 전체화면 UI 를 여는 것입니다. 이 경우 전체화면 UI 아래에 배치된 모든 UI 요소들은 비활성화될 수 있습니다.


이를 위한 가장 단순한 방법은 루트 게임오브젝트나 안 보이는 UI 요소를 포함하는 게임오브젝트들을 비활성화하는 것입니다. 대안적인 해결책을 원한다면 Disabling Canvas Renderer 섹션을 참고하십시오.


Disabling invisible camera output


불투명한 배경을 가진 전체 화면 UI 가 유니티 UI 에서 열려 있다면, 월드 공간 카메라는 여전히 표준 3D 씬을 UI 뒤에다가 렌더링하고 있을 것입니다. 이 렌더러는 전체화면 유니티 UI 가 전체 3D 씬을 가리고 있다는 사실을 인지하지 못합니다.


그러므로, 만약 완전한 전체화면 UI 가 열렸다면, 차폐된 모든 월드 공간 카메라를 비활성화하는 것은 GPU 부하를 줄여주며, 이는 단순히 불필요한 3D 공간 렌더링을 제거함으로써 수행됩니다.


노트: 만약 Canvas 가 "Screen Space - Overlay" 로 설정되어 있다면, 씬에서 활성하된 카메라의 개수를 무시하고 그려질 것입니다.


Majority-obscured cameras


많은 "전체화면" UI 들은 실제로는 전체 3D 월드를 차폐하지 않습니다. 그러나 월드의 일부분만을 보이게합니다. 이 경우에는, 보이는 월드 부분을 렌더 텍스쳐에 캡쳐하는 것이 더 효율적일 수 있습니다. 만약 월드의 보이는 부분이 렌더 텍스쳐에 "캐싱"되면, 실제 월드 공간 카메라가 비활성화될 수 있으며, 캐싱된 렌더 텍스쳐는 3D 월드에 대한 임포스터 버전을 제공하기 위해서 UI 스크린 뒤에 그려질 수 있습니다.


Composition-based UIs


컴포지션을 통해서 UI 를 생성하는 것은 매우 일반적입니다 - 최종 UI 를 생성하기 위해서 표준 백그라운드와 요소들을 합치고 레이어화하는 것입니다. 이 작업은 상대적으로 단순하고 반복적으로 수행하기 쉽지만, 그것은 유니티 UI 가 transparent 렌더링 큐를 사용하므로 성능에 좋지 않습니다.


백그라운드, 버튼, 그리고 버튼 위의 텍스트로 구성된 단순한 UI 를 생각해 봅시다. 텍스트 글리프( glyph ) 내에 포함된 픽셀의 경우, GPU 는 백그라운드 텍스쳐와 버튼 텍스쳐를 샘플링한 후에 최종적으로 텍스트 아틀라스 텍스쳐를 처리합니다. 결국 세 번의 샘플링이 필요합니다. UI 의 복잡도가 커질수록, 백그라운드 위쪽에 레이어화되어야 하는 요소들이 많아지며, 샘플링 개수는 급격하게 증가할 것입니다.


만약 큰 UI 가 fill-rate 한계( bound )에 도달했다는 것이 밝혀지면, UI 의 장식된( decorative )/불변하는( invariant ) 요소들을 그것의 백그라운드 텍스쳐와 머지하는 특별한 UI 스프라이트를 생성하는 것이 최선입니다. 이는 다른 요소 위에 레이어화되어야 하는 요소의 개수를 줄여주지만, 노가다가 필요하며 프로젝트의 텍스쳐 아틀라스의 크기가 증가합니다.


주어진 UI 를 특별한 UI 스프라이트 위에 생성하는 데 필요한 레이어화된 요소들을 압축하는데 있어서의 원칙은 sub-element 들을 위해서 사용될 수도 있습니다. 제품에 대한 스크롤링 팬을 가진 스토어 UI 를 생각해 봅시다. 각 제품의 UI 요소는 경계선, 배경, 가격을 표시하는 아이콘, 이름, 그리고 다른 정보들을 포함합니다.


스토어 UI 는 백그라운드를 필요로 하지만, 제품은 백그라운드 위에서 스크롤링되기 때문에 제품 요소는 스토어 UI 의 백그라운드 텍스쳐에 머지될 수 없습니다. 그러나 경계선, 가격, 이름, 그리고 다른 요소들은 제품의 백그라운드에 머지될 수 있습니다. 아이콘의 크기와 개수에 따라, fill-rate 절약을 고려해 볼 수 있습니다.


레이어화된 요소들을 합치는 것은 몇 가지 단점을 가지고 있습니다. 특별한 요소들을 더 이상 재사용할 수 없으며, 그것을 생성하기 위해서는 추가적인 아티스트 자원을 요구합니다. 새로운 큰 텍스쳐의 추가는 UI 텍스쳐를 저장하는데 필요한 메모리 총량을 증가시킬 것이며, 특히 UI 텍스쳐가 on-demand 로 로드되거나 언로드되지 않는다면 문제는 심각해질 것입니다.


UI Shaders and low-spec devices


유니티 UI 에 의해 사용되는 내장 쉐이더는 마스킹, 클리핑, 그리고 여러 가지 복잡한 연산에 대한 지원을 포함합니다. 이는 복잡도를 증가시키므로, UI 쉐이더는 iPhone 4 와 같은 low-end 장치 상에서의 더 단순한 유니티 2D 쉐이더와 비교했을 때 매우 느립니다.


만약 마스킹, 클리핑, 그리고 다른 "화려한" 기능들이 low-end 장치에서 필요하지 않다면, 최소 UI 쉐이더와 같은 불필요한 연산을 제거하는 커스텀 쉐이더를 만드는 것이 가능합니다.



UI Canvas Rebuilds


어떤 UI 를 디스플레이하기 위해서, UI 시스템은 스크린상에 표현된 각 UI 컴포넌트를 위한 지오메트리를 생성해야 합니다. 이는 동적 레이아웃 코드를 실행하거나 글자를 UI 텍스트 문자열로 표현하기 위해서 폴리곤을 생성한다거나 드로 콜을 최소화하기 위해서 가능한한 많은 지오메트리를 하나의 메쉬로 통합한다거나 하는 일들을 포함합니다. 이것은 여러 단계의 절차로 구성되며, 이 가이드의 시작부분의 Fandamentals 섹션에서 세부적으로 기술하고 있습니다.


두 가지 주요 원인 때문에 Canvas 를 리빌드하는 것은 성능 문제를 일으킬 수 있습니다:


    • 만약 Canvas 상에서 그려질 수 있는 UI 요소의 개수가 너무 많다면, 자체적으로 배치를 계산하는 비용이 매우 비싸집니다. 이는 요소들을 정렬하고 분석하는 비용 때문이며, 이 비용은 요소의 개수에 따라 비선형적으로 증가합니다.
    • 만약 Canvas 가 자주 갱신되면, 상대적으로 적은 변화를 가지는 Canvas 보다 리프레쉬하는데 더 많은 비용을 소비해야 합니다.


이러한 문제들은 모두 Canvas 상의 요소 개수가 증가하기 때문에 심해지는 경향이 있습니다.


중요하게 기억할 점: 그릴수 있는 UI 요소가 변경될 때마다, Canvas 는 배치 빌딩 절차를 재수행해야만 합니다. 이 절차는 그릴 수 있는 UI 요소 전체를 그것이 변경되었는지 여부와 관계없이 다시 분석합니다. UI 오브젝트의 외형에 영향을 주는 모든 변경을 "변경"이라고 하며, 이는 스프라이트 렌더러에 할당된 스프라이트, transform 위치와 스케일, 텍스트 메쉬에 포함된 텍스트 등을 포함합니다.


Child order


유니티 UI 들은 뒤에서 앞으로 생성되는데, 계층 구조 상에서 오브젝트의 순서가 그것의 정렬 순서를 결정합니다. 계층에서 먼저 등장하는 오브젝트는 나중에 등장하는 오브젝트보다 뒤에 있다고 간주됩니다. 배치는 계층을 위에서 아래로 돌면서 빌드되며, 같은 머티리얼과 텍스쳐를 사용하지만 중간 레이어( intermediate layer, 서로 다른 머티리얼을 가진 그래피컬 오브젝트인데, 그것의 바운딩 박스는 배치 가능한 다른 오브젝트와 겹치며 배치 가능한 두 오브젝트 사이의 계층에 배치되어 있습니다 )를 가지지 않는 모든 오브젝트들이 수집됩니다. 중간 레이어들은 배치를 깨게 됩니다.


Unity Frame Debugger 섹션에서 언급했듯이, 프레임 디버거는 중간 레이어들을 위한 UI 를 확인하기 위해 사용될 수 있습니다. 이는 한 오브젝트가 배치 가능한 다른 두 오브젝트 사이에 끼어들고 있는 상황입니다.


이 문제는 텍스트나 스프라이트가 다른 것들 근처에 위치할 때 자주 발생합니다: 텍스트의 바운딩 박스는 인접한 스프라이트와 보이지는 않지만 겹치게 됩니다. 왜냐하면 텍스트 글리프의 대부분의 폴리곤이 투명하기 때문입니다. 이는 두 가지 방법으로 해결될 수 있습니다:


    • 배칭될 수 없는 오브젝트에 의해서 배칭될 수 있는 오브젝트가 방해받지 않도록 요소를 재정렬합니다: 즉, 배칭될 수 없는 오브젝트를 배칭될 수 있는 오브젝트의 위쪽이나 아래쪽으로 움직입니다.
    • 오브젝트의 위치를 수정해서 보이지 않는 겹침을 제거합니다.


이 두 가지 방법은 모두 유니티 프레임 디버거를 활성화시켜서 수행될 수 있습니다. 유니티 프레임 디버거에서 보이는 드로콜의 개수를 관찰함으로써, UI 요소가 겹침으로써 낭비되는 드로콜의 개수를 최소화하는 순서와 위치를 찾는 것이 가능합니다.


Splitting Canvases


사소하기는 하지만, Canvas 를 나누는 것도 일반적으로 좋은 생각입니다. 요소들을 sub-canvas 나 인접한 Canvas 로 옮기는 것입니다.


( 예를 들어, 튜토리얼 화살표처럼 ) UI 의 특정 부분이 그 UI 의 나머지와는 다르게 깊이가 제어되어야 하는 경우에는 인접한 Canvas 로 옮기는 전략을 사용하는 것이 최선입니다.


다른 경우에는, sub-canvas 가 더욱 편리합니다. 왜냐하면 그것은 부모 Canvas 의 디스플레이 세팅을 상속하기 때문입니다.


일견하기에는 UI 를 sub-canvas 들에 하위분할하는 것이 최상이라 생각할 수 있지만, Canvas 시스템은 분리된 Canvas 들을 배치에 합치지 않는다는 점에 주의하십시오. 성능을 고려한 UI 설계는 리빌드 비용을 최소화하는 것과 드로콜을 낭비하는 것을 최소화하는 것 사이의 균형을 요구합니다.


General guidelines


Canvas  는 Canvas 내부의 변경된 요소들을 아무때나 리배칭하기 때문에, 단순하지 않은 Canvas 는 적어도 두 부분으로 분리하는 것이 일반적으로 최상입니다. 더우기 만약 요소들이 동시에 변경될 것을 기대하고 있다면 같은 Canvas 상에 요소들을 같이 배치하려고 시도하는 것이 최상입니다. 그 예로는 프로그레스 바와 카운트다운 타이머를 들 수 있습니다. 이것들은 모두 같은 데이터에 기반하고 있으므로, 동시에 갱신되는 것을 요구할 것이며, 그것들은 같은 Canvas 에 배치되어야 합니다.


정적이거나 변하지 않는 백그라운드나 레이블과 같은 모든 요소들을 한 Canvas 에 배치하십시오. 이것들은 Canvas 가 처음 디스플레이될 때 한 번에 배칭됩니다. 그리고 앞으로는 더 이상 리배칭이 필요하지 않을 것입니다.


"동적인" 요소들을 다른 캔버스에 배치하십시오 - 그것들은 자주 변경되는 것들입니다. 이는 이 Canvas 가 자주 갱신되는 요소들을 리배칭하는 것을 보장할 것입니다. 만약 동적 요소의 개수가 매우 많아진다면, ( 예를 들어 프로그레스 바, 타이머 표시, 움직이는 요소와 같은 ) 지속적으로 변화하는 요소 집합과 가끔 변화하는 요소 집합으로 분리하십시오.


경험적으로 볼 때 이는 좀 더 어렵습니다. 특히 UI 컨트롤들을 프리팹으로 캡슐화할 때 어렵습니다. 대신에 많은 UI 들은 비용이 많이 드는 컨트롤들을 Sub-Canvas 로 옮김으로써 Canvas 를 하위분할하는 정책을 씁니다.


Unity 5.2 and Optimized Bathcing


유니티 5.2 에서는 배칭 코드가 지속적으로 재작성되었으며, 4.6, 5.0, 5.1 과 비교했을 때 더 많은 성능 개선이 있었습니다. 더우기 1 개 이상의 코어를 가진 장치에서, 유니티 UI 시스템은 대부분의 처리를 워커 스레드에 넘길 것입니다. 일반적으로, 유니티 5.2 는 UI 를 수십개의 Sub-canvas 로 공격적으로 분할할 필요성을 제거했습니다. 모빌 장치 상의 많은 UI 들은 이제 2 ~ 3 개의 Canvas 들만 가지고도 좋은 성능을 낼 수 있습니다.


유니티 5.2 에서의 최적화에 대한 더 많은 정보를 원하신다면, 이 블로그 포스트를 참고하십시오.


Input and Raycasting In Unity UI


기본적으로, 유니티 UI 는 Graphic Raycast 컴포넌트를 사용해서 터치나 마우스 이벤트와 같은 입력 이벤트들을 다룹니다. 이는 일반적으로 Standalone Input Manager 컴포넌트에 의해 제어됩니다. 이름 대문에 Standalone Input Manager 가 "universal" 입력 관리 시스템으로 보이는데, 이는 마우스와 터치를 모두 다룰 것입니다.


Erroneous mouse input detection on mobile (5.3)


5.4 전에는 Graphic Raycaster 가 붙은 각각의 활성화된 Canvas 가 마치 터치 입력이 비활성화 되어 있는 것처럼 마우스의 위치를 검사하기 위해 매프레임 레이캐스트를 수행했습니다. 이는 플랫폼을 구분하지 않고 발생했습니다; iOS 와 안드로이드 장치에는 마우스가 없는데 여전히 마우스 위치를 질의하고 UI 요소들이 마우스 포인터 아래에 있는지 확인하려고 시도했습니다.


이는 CPU 시간을 낭비했으며, 유니티 애플리케이션 CPU 프레임 시간의 5% 이상을 소비하는 것이 밝혀졌습니다.


이 이슈는 5.4 에서 해결되었습니다: 5.4 부터는 마우스를 가지지 않은 장치는 마우스 위치를 질의하지 않으면 불필요한 레이케이트를 수행하지 않을 것입니다.


5.4 전 버전을 사용하고 있다면 모빌 개발자들은 자신만의 Input Manager 클래스를 작성할 것을 강력히 권합니다. 이는 유니티의 Standard Input Manager 를 유니티 UI 소스로부터 복사함으로써 단순화될 수 있으며, ProcessMouseEvent 메서드를 그 메서드에 대한 호출과 함께 주석처리해 버리면 됩니다.


Raycast optimization


Graphic Raycast 는 상대적으로 직관적인 구현이며, 이는 "Raycast Target" 설정이 true 인 모든 Graphic 컴포넌트를 돕니다. 각 Raycast Target 에 대해, Raycaster 는 몇 개의 테스트를 수행합니다. 만약 Raycast Target 이 모든 테스트를 통과하면, 히트 리스트에 그것이 추가됩니다.


Raycast implementation details


테스트는 다음과 같은 시점에 수행됩니다:


    • Raycast Target 이 활성화되어 있고, 그려질 때( 예를 들어 지오메트리 )
    • 입력 포인트가 Raycast Target 이 붙어 있는 RectTransform 내에 존재할 때
    • Raycast Target 이 ICanvasRaycastFilter 컴포넌트를 가지고 있거나 ( 깊이 상관없이 ) 그것의 자식일 때, 그리고 그 Raycast Filter 컴포넌트가 레이캐스트를 허용할 때


히트된 Raycast Target 의 리스트는 깊이에 의해 정렬되며, 순서를 바꾸기 위해서 필터링되며, 카메라 뒤에 렌더링되는 ( 예를 들어 스크린에 보이지 않는 ) 요소들을 제거하기 위해서 필터링됩니다.


Graphic Raycaster 는 Graphic Raycast 의 "Blocking Objects" 속성에 각각의 플래그가 설정되어 있으면 3D 나 2D 물리 시스템으로 레이를 캐스트할 수도 있습니다( 스크립트에서 수행하려면, blockingObjects 라는 속성임 ).


만약 2D 혹은 3D 블락킹 오브젝트가 활성화되어 있다면, raycast-blocking 물리 레이어 상에서 2D 혹은 3D 오브젝트 아래에서 그려지는 모든 Raycast Target 은 히트 리스트로부터 제거될 것입니다.


그리고 나서 최종 리스트가 반환됩니다.


Raycasting optimization tips


모든 Raycast Target 들은 Graphic Raycaster 에 의해서 테스트되어야만 한다면, 포인터 이벤트를 받아야만 하는 IU 컴포넌트 상의 "Raycast Target" 만 활성화하는 것이 최상입니다. Raycast Target 의 리스트를 더 작게 만들고 더 얕은 계층이 순회될 수록, Raycast 테스트의 속도가 빨라질 것입니다.


백그라운드와 텍스트가 모두 색상을 변경할 필요가 있는 버튼과 같이, 포인터 이벤트에 응답해야만 하는 다중의 UI 오브젝트들을 포함하는 복합 UI 컨트롤의 경우에는, 복합 UI 컨트롤의 루트에 하나의 Raycast Target 만을 배치하는 것이 더 좋습니다. 그 단일 Raycast Target 이 포인터 이벤트를 받게 되면, 그 이벤트를 관심있는 컴포넌트들에게 전달할 수 있습니다.


Hierarchy depth and raycast filters


각각의 Graphic Raycast 는 raycast 필터를 찾을 때 루트까지 모든 Transform 계층을 순회합니다. 이 연산의 비용은 계층 내의 깊이에 따라 선형적으로 증가합니다. 계층 내의 각 Transform 에 붙어 있는 모든 컴포넌트들이 ICanvasRaycastFilter 를 구현했는지 확인하기 위해 테스트되어야만 하므로, 이는 싼 연산이 아닙니다.


ICanvasRaycastFilter 를 사용하는 CanvasGroup, Image, Mask, RectMask2D 와 같은 표준 유니티 UI 컴포넌트들이 몇 개 있습니다. 그러므로 이 순회 비용은 쉽게 제거되기 힘듭니다.


Sub-canvas and the OverridedSorting property


Sub-canvas 에 있는 overrideSorting 속성은 Graphic Raycast 테스트가 Transform 계층을 올라가는 것을 막습니다. 만약 정렬이나 레이캐스트 검출 이슈없이 이것이 활성화될 수 있다면, 레이캐스트 계층 순회의 비용을 감소시키기 위해서 이것을 사용하십시오.

원문 : Funadamentals of Unity UI

주의 : 번역이 개판이므로 이상하면 원문을 참조하십시오.

주의 : 허락받고 번역한 것이 아니므로 언제든 내려갈 수 있습니다.



Fundametals of Unity UI


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


유니티 UI 시스템을 구성하는 여러 부분을 이해하는 것은 중요합니다. 그 시스템을 구성하는 여러 개의 기본 클래스들과 컴포넌트들이 있습니다. 이 챕터는 먼저 이 기사의 시리즈 전반에서 사용될 몇 개의 개념들을 정의하고, 유니티 UI 의 몇 가지 핵심 시스템의 저수준 동작에 대해 논의할 것입니다.


Teminology


Canvas 네이티브 코드 유니티 컴포넌트인데, 이는 게임의 월드 공간의 상위에 그려질 레이어화된 지오메트리( geometry )를 제공하기 위해 유니티 렌더링 시스템에 의해 사용됩니다.


Canvas 들은 자신의 내부 지오메트리를 배칭( batching )할 책임이 있으며, 적절한 렌더링 커맨드들을 생성하고 이것들을 유니티 그래픽스 시스템에 전달합니다. 이것은 전부 네이티브 C++ 코드에서 수행되며, 이는 rebatch 라든가 batch build 라고 불립니다. 캔버스가 리배칭을 요구하는 지오메트리로 구성되어 있다고 표시되면, 그 캔버스는 갱신되었다( dirty )고 판단됩니다.


지오메트리는 Canvas Renderer 컴포넌트에 의해 Canvas 에 제공됩니다.


Sub-canvas 는 그냥 Canvas 컴포넌트인데, 이는 다른 Canvas  컴포넌트에 내포됩니다. Sub-canvas 들은 그들의 부모의 다른 자식들과는 독립적입니다: 한 자식이 갱신되었다고 해서 부모로 하여금 그것의 지오메트리를 리빌드하도록 강제하지는 않을 것이라는 것입니다.


Graphic 클래스는 유니티 UI C# 라이브러리에 의해 제공되는 기반 클래스입니다. 이것은 Canvas 시스템 상에서 그려질 수 있는 지오메트리를 제공하는 모든 유니티 UI C# 클래스들의 기반 클래스입니다. 대부분의 내장 유니티 UI Graphics 들은 MaskableGrphic 서브 클래스를 통해서 구현됩니다. 이는 IMaskable 인터페이스를 통해 그것들이 마스킹될 수 있도록 해 줍니다. Drawable 의 주요 서브클래스들은 Image 와 Text 입니다. 그것들은 자신의 이름과 동일한 컴포넌트들을 제공합니다.


Layout 컴포넌트는 RectTransform 의 위치와 크기를 제어하며, 일반적으로 자신의 칸텐츠에 대한 상대적인 크기와 위치를 요구하는 복잡한 레이아웃을 생성하기 위해서 사용됩니다. Layout 컴포넌트는 RectTransform 에 의존하며, 이는 그것들에 연관된 RectTransform 의 속성에 영향을 미칩니다. 그것들은 Graphic 클래스에 대해서 종속적이지 않으며, 유니티 UI 의 Graphic 컴포넌트들과는 독립적으로 사용될 수 있습니다.


Graphic 컴포넌트와 Layout 컴포넌트는 모두 CanvasUpdateRegistry 클래스에 의존하는데, 이는 유니티 에디터 인터페이스에는 노출되지 않습니다. 이 클래스는 갱신되어야만 하는 Layout 컴포넌트와 Graphic 컴포넌트의 집합을 추적하는 클래스이며, 그것과 연관된 Canvas 가 willRenderCanvases 이벤트를 호출할 때 필요에 의해 트리거들이 갱신됩니다.


Layout 컴포넌트와 Graphic 컴포넌트에 대한 갱신을 rebuild 라 부릅니다. 이 리빌드 절차에 대해서는 이 문서의 나중에 더 세부적으로 다루도록 하겠습니다.


Rendering Details


유저 인터페이스를 유니티 UI 로 만들 때, Canvas 에 의해 그려지는 모든 지오메트리들은 Transparent 큐에 그려질 것이라는 점을 기억하십시오. 즉, 유니티 UI 에 의해서 생성된 지오메트리는 항상 알파블렌딩을 사용해 뒤에서 앞 순서로 그려질 것입니다. 성능 관점에서 기억해야 할 중요한 것은, 폴리곤으로부터 래스터화된 각 픽셀은 마치 그것이 다른 불투명한 폴리곤에 의해 의해 완전히 가려져 있는 것처럼 샘플링될 것이라는 것입니다. 모바일 장치에서는, 고수준의 overdraw 는 GPU 의  fill-rate 수용량( capacity )를 급격하게 초과할 수 있습니다.


The Batch Building Process (Canvases)


배치 빌딩 절차는 Canvas 가 그것의 UI 요소들을 표현하는 메시들을 결합하고 유니티의 그래픽스 파이프라인에 보내기 위한 렌더링 커맨드들을 생성하는 절차입니다. 이 절차의 결과는 Canvas 가 갱신( dirty )되었다고 표시될 때까지 캐싱되고 재사용됩니다. 이러한 갱신은 그것을 구성하는 메시들 중의 하나가 변경될 때마다 발생합니다.


Canvas 에 의해 사용되는 메시는 Canvas 에 붙어 있는 Canvas Renderer 컴포넌트로부터 획득됩니다. 하지만 Sub-canvas 에 포함된 Canvas Renderer 에서 획득하지는 않습니다.


배치를 계산하는 것은 메시를 깊이값에 의해 정렬하고 겹치는지 혹은 머티리얼을 공유하는지 등을 검사하는 작업들을 요구합니다. 이 연산은 멀티-스레드에서 수행되기 때문에 그것의 성능은 일반적으로 CPU 아키텍쳐가 달라질 때마다 달라지며, 특히 모바일 ( 일반적으로 몇 안 되는 CPU 코어를 가진 ) SoC 와 현대 데스크탑의 ( 보통 4 개 이상의 코어를 가지고 있는 ) CPU 사이에서 큰 차이가 납니다.


The Rebuild Process ( Graphics )


리빌드 절차는 유니티 UI 의C# Graphic 컴포넌트의 레이아웃과 메시가 재계산되는 곳입니다. 이는 CanvasUpdateRegistry 클래스에 의해 수행됩니다. 이것은 C# 클래스이며, 그것의 소스는 Unity's Bitbucket 에서 찾아볼 수 있음을 기억하십시오.


CanvasUpdateRegistry 내에서, 흥미로운 메서드는 PerformUpdate 입니다. 이 메서드는 Canvas 컴포넌트가 WillRenderCanvases 이벤트를 호출할 때마다 호출됩니다. 이 이벤트는 프레임당 한 번 불립니다.


PerformUpdate 는 세 단계의 절차로 실행됩니다:


    • 레이아웃을 리빌드하기 위해서 갱신된 Layout 컴포넌트들이 요청됩니다. 이는 ICanvasElement.Rebuild 메서드를 통해 수행됩니다.
    • 컬링과 클리핑을 수행하기 위해서 등록된 모든 ( Mask 같은 ) Clipping 컴포넌트들이 요청됩니다. 이는 ClippingRegistry.Cull 을 통해 수행됩니다.
    • 그래피컬 요소들을 리빌드하기 위해서 갱신된 Graphic 컴포넌트들이 요청됩니다.


Layout 과 Graphic 을 리빌드하기 위해, 이 절차는 여러 개의 부분으로 나뉩니다. Layout 리빌드는 세 가지 부분으로 실행됩니다( PreLayout, Layout, PostLayout ). 그리고 Graphic 리빌드는 두 가지 부분으로 실행됩니다( PreRender, LatePreRender ).


Layout rebuilds


하나 이상의 Layout 컴포넌트에 포함된 컴포넌트의 적절한 위치를 계산하기 위해서는, 그것들의 적절한 계층적 순서를 적용할 필요가 있습니다. 게임 오브젝트 계층에서 루트와 가까운 Layout 들은 잠재적으로 그것들에 내포되어 있는 다른 Layout 들의 위치와 크기를 수정할 수 있습니다. 그러므로 가장 먼저 계산되어야만 합니다.


이를 위해, 유니티 UI 는 계층 내에서의 깊이를 중심으로 갱신된 Layout 컴포넌트들을 정렬합니다. 계층 구조에서 높은 곳에 있는 아이템( 예를 들어 부모 Transform 이 거의 없는 아이템 )들은 리스트의 앞쪽으로 이동됩니다.


그리고 나서 레이아웃을 리빌드하기 위해서 Layout 컴포넌트들의 정렬된 리스트가 요청됩니다: 여기에서 Layout 컴포넌트에 의해서 제어되는 UI 요소들의 위치와 크기가 실제로 수정됩니다. 개별 요소들의 위치가 Layout 의 영향을 받는 방식에 대한 더 세부적인 내용을 원한다면, 유니티 매뉴얼의 UI Auto Layout 섹션을 참고하십시오.


Graphics rebuilds


Graphic 컴포넌트들이 리빌드될 때, 유니티 UI 는 ICanvasElement 인터페이스의 Rebuild 메서드에 대한 제어를 넘깁니다. Graphic 은 이를 구현하며, 리빌드 절차의 PreRender 스테이지 동안 두 개의 리빌드 단계를 실행합니다.


    • 만약 버텍스 데이터가 갱신되었다고 표시되었다면( 예를 들어, 컴포넌트의 RectTransform 의 크기가 변했다면 ), 메시가 리빌드됩니다.
    • 만약 머티리얼 데이터가 갱신되었다고 표시되었다면( 예를 들어, 컴포넌트의 머티리얼이나 텍스쳐가 변경되었다면 ), 동봉된 Canvas Renderer 의 머티리얼이 갱신됩니다.


Graphic 리빌드는 특정 순서로 처리되지는 않습니다. 그리고 어떠한 정렬 연산도 요구하지 않습니다.

원문 : AssetBundle Usage Patterns

주의 : 번역이 개판이므로 이상하면 원문을 참조하십시오.

주의 : 허락받고 번역한 것이 아니므로 언제든 내려갈 수 있습니다.

주의 : 아래쪽의 일부 섹션들은 현재 제 관심사와 관계가 없어 보여서 번역하지 않았습니다.



AssetBundle Usage Patterns


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


이 문서는 유니티 5 의 애셋, 리소스, 리소스 관리를 다루는 기사 시리즈의 다섯 번째 챕터입니다.


이 시리즈의 이전 챕터에서는 애셋번들의 기초에 대해 다뤘는데, 특히 다양한 로딩 API 의 저수준 동작에 대해 다뤘습니다. 이 챕터는 애셋번들을 실무에서 사용하는 것의 다양한 관점에 대한 문제들과 잠재적 해결책들에 대해 논의합니다.


4.1. Managing Loaded Assets


메모리에 민감한 환경에서 로드된 오브젝트의 크기와 개수를 조심스럽게 제어하는 것은 매우 중요합니다. 유니티는 활성화된 씬에서 오브제트가 제거될 때 자동으로 그것들을 언로드하지 않습니다. 애셋 정리는 특정 시점에 발동되며, 이것은 수동으로 발동될 수도 있습니다.


애셋번들 자체는 매우 주의깊게 관리되어야만 합니다. ( 유니티 캐시에 있거나 AssetBundle.LoadFromFile 에 의해 로드된 ) 로컬 저장소로부터 로드된 애셋번들은 최소한의 메모리 부하를 가지는데, 약 10 ~ 40 KB 를 잘 넘지 않습니다. 이 부하는 매우 많은 개수의 애셋번들이 제출될 때 여전히 문제가 될 수 있습니다.


대부분의 프로젝트들은 유저에게 ( 레벨을 리플레이하는 것과 같은 ) 재경험 칸텐츠를 허용하며, 애셋번들을 로드하거나 언로드해야 하는 시점을 아는 것은 중욯바니다. 만약 애셋번들이 부적절하게 언로드되면, 그것은 메모리상에서 오브젝트가 중복되도록 만들 수 있습니다. 애셋번들을 부적절하게 언로드하는 것은 특정 환경에서 원치않는 동작을 유발할 수도 있는데, 이는 텍스쳐가 없어진다던가 하는 상황을 만듭니다. 이런 일이 왜 일어나는지 이해하려면, Asset, Objects, and Serialization 챕터의 Inter-Object references 섹션을 참고하십시오.


애셋과 애셋번들을 관리할 때 가장 중요한 것은 AssetBundle.Unload 의 인자를 true 로 공급하느냐 false 로 공급하느냐에 따라 다른 동작을 한다는 것을 이해하는 것입니다.


이 API 는 호출되고 있는 애셋번들의 헤더 정보를 언로드합니다. 인자는 이 애셋번들로부터 인스턴스화된 모든 오브젝트를 언로드할지 여부를 지정합니다. 만약 true 라면, 애셋번들로부터 생성된 모든 오브젝트들은 즉시 언로드됩니다 - 심지어 활성화된 씬에서 현재 사용중일지라도 말이죠.


예를 들어, 머티리얼 M 이 애셋번들 AB 로부터 로드되고, M 이 현재 활성화된 씬에서 사용주이라고 가정해 보겠습니다.


만약 AB.Unload(true) 가 호출되면, M 은 씬에서 제거되며 파괴되고 언로드될 것입니다. 그러나 AB.Unload(false) 가 호출되면 AB 의 헤더 정보가 언로드되지만, M 은 씬에 남아 있게 되고 여전히 자신의 기능을 수행할 것입니다. AssetBundle.Unload(false) 호출은 M 과 AB 간의 링크를 끊습니다. 만약 AB 가 나중에 다시 로드된다면, AB 에 포함된 오브젝트들에 대한 새로운 복사본이 메모리에 로드될 것입니다.


만약 AB 가 나중에 다시 로드된다면, 애셋번들의 헤더 정보의 새로운 복사본이 다시 로드될 것입니다. 하지만 M 은 AB 의 새 복사본으로부터 로드되지 않습니다. 유니티는 AB 와 M 의 새로운 복사본 사이의 어떠한 링크도 만들어 주지 않습니다.


만약 AB.LoadAsset() 을 호출해 M 을 다시 로드한다면, 유니티는 M 의 예전 복사본을 AB 안의 데이터의 인스턴스인 것처럼 해석하지 않을 것입니다. 그러므로 유니티는 M 의 새로운 복사본을 로드하고 씬에는 M 에 대한 동일한 두 개의 복사본이 존재하게 될 것입니다.


대부분의 프로젝트의 경우에, 이러한 동작은 원치않는 동작입니다. 대부분의 프로젝트들은 AssetBundle.Unload(true)를 사용해야 하며 오브젝트들이 중복되지 않는다고 확신하기 위한 기법을 써야 합니다. 두 개의 기법이 있습니다:


    1. 애플리케이션 생명주기 동안에 일시적인 애셋번들이 언로드되는 잘 정의된 지점을 가지고 있어야 합니다. 이러한 예로는 레벨이 전환되는 시점이나 로딩 스크린이 나오고 있는 동안이 있습니다. 이는 단순하고 가장 흔한 선택입니다.
    2. 개별 오브젝트들에 대한 참조 카운트를 유지하고, 애셋번들에서 생성된 오브젝트가 더 이상 사용되지 않을 때 애셋번들을 언로드하는 것입니다.


먄약 애플리케이션이 AssetBundle.Unload(false) 를 사용해야만 한다면, 개별 오브젝트들은 두 가지 방식으로 언로드될 수 있습니다:


    1. 원치않는 오브젝트에 대한 모든 참조를 제거하는데, 이는 씬과 코드에서 모두 이루어져야 합니다. 이 작업이 끝나면 Resources.UnloadUnusedAllsets 를 호출합니다.
    2. 씬을 non-additively 로 로드합니다. 이는 현재 씬에 있는 모든 오브젝트들을 파괴하고 Resources.UnloadUnusedAssets 를 자동으로 호출할 것입니다.


만약 프로젝트가 오브젝트가 로드되거나 언로드되는 동안 사용자로 하여금 대기하게 만들 수 있는( 게임 모드나 레벨이 전환되는 사이와 같은 ) 잘 정의된 지점을 가지고 있다면, 이 지점들은 필요한 만큼 많은 오브젝트들을 언로드하고 새로운 오브젝트들을 로드하는데 사용되어야 합니다.


이를 위한 가장 단순한 방법은 분리된 청크의 프로젝트를 씬에 패키징하는 것입니다. 그리고 나서 씬의 모든 종속성과 함께 씬을 애셋번들로 빌드합니다. 그리고 나서 애플리케이션은 씬 "로딩"에 들어 가는데, 이전 씬에 포함된 모든 애셋번들을 완전히 언로드하고, 새로운 씬을 포함하는 애셋번들을 로드합니다.


이것이 가장 단순한 플로우이기는 하지만, 어떤 프로젝트들은 좀 더 복잡한 애셋번들 관리를 요구합니다. 보편적인 애셋번들 설계 패턴이라는 것은 존재하지 않습니다. 각 프로즈게트의 데이터는 서로 다릅니다. 오브젝트들을 애셋번들로 그룹화하는 방법을 결정할 때, 일반적으로 가장 좋은 것은 동시에 로드되거나 업데이트되어야만 하는 오브젝트들을 애셋번들로 묶는 것입니다.


예를 들어, 롤플레잉 게임을 생각해 봅시다. 개별 맵과 컷씬들은 씬에 의해 애셋번들로 그룹화될 수 있습니다. 하지만 어떤 오븢게트들은 대부분의 씬에서 필요할 것입니다. 애셋번들은 초상화, 인게임 UI, 서로 다른 캐릭터 모델 및 텍스쳐를 제공하기 위해서 빌드도리 수 있습니다. 나중에 언급한 오브젝트들과 애셋들은 애플리케이션 시작시에 로드되어 애플리케이션 생명주기 동안 로드된 상태를 유지하는 애셋번들의 2차 집합으로 그룹화될 수 있습니다.


애셋번들이 언로드된 다음에 유니티가 애셋번들로부터 오브젝트를 다시 로드해야 하는 경우에 다른 문제가 발생할 수 있습니다. 이 경우에, 리로드는 실패할 것이며, 유니티 에디터의 계층에서는 (Missing) 오브젝트로 나타날 것입니다.


이 상황은, 모바일 앱이 중단되었을 때나 사용자가 PC 를 lock 했을 때 같이, 유니티가 그것의 그래픽스 칸텍스트에 대한 제어를 잃거나 다시 획득할 때 주로 발생합니다. 이 경우, 유니티는 GPU 에 텍스쳐와 쉐이더를 다시 업로드해야 합니다. 만약 이 애셋들을 위한 소스 애셋번들이 이용할 수 없는 상태라면, 애플리케이션은 "missing shader" 마젠타색으로 씬의 오븢게트를 렌더링하게 될 것입니다.


4.2. Distribution


프로젝트의 애셋번들을 클라이언트에 배포하기 위한 두 가지 기본 방식이 있습니다: 프로젝트와 함께 설치하는 것과 설치 후에 다운로드하는 것. 어떤 방식을 선택하느냐는 프로젝트가 실행되어야 하는 플랫폼의 기능과 제약에 의해 결정됩니다. 모바일 프로젝트들은 보통 초기 설치 크기를 줄이고 무선 다운로드 크기 제한 아래로 파일 크기를 유지하기 위해서 post-install 옵션을 선택합니다. 콘솔이나 PC 프로젝트들은 일반적으로 애셋번들을 초기 설치에 포함시킵니다.


적절한 구조를 만들면 애셋번들이 처음에 어떤 방식으로 전달되었느냐의 여부와는 관계없이 프로젝트의 post-install 로 새로운 혹은 수정된 칸텐트를 패치할 수 있습니다. 이와 관련한 더 많은 정보를 원한다면 이 기사의 Patching with AssetBundles 섹션을 참고하십시오.


4.2.1. Shipped with project


프로젝트에 애셋번들을 포함시키는 것은 애셋번들을 배포하는 가장 단순한 방법입니다. 왜냐하면 그것은 추가적인 다운로드 관리 코드를 필요로하지 않기 때문입니다. 프로젝트가 애셋번들을 설치 파일에 포함시켜야 하는 이유는 크게 두 가지가 있습니다:


    • 프로젝트 빌드 시간을 줄이고 반복적인 개발을 더 단순하게 만들기 위해서입니다. 만약 이 애셋번들이 애플리케이션 자체로부터 개별적으로 갱신될 필요가 없다면, 애셋번들은, 스트리밍 애셋에 애셋번들을 저장함으로써, 애플리케이션에 포함될 수 있습니다. 아래의 Streaming Assets 섹션을 참고하십시오.
    • 업데이트가 가능한 칸텐트의 초기 리비전을 포함시키기 위해서입니다. 이는 보통 초기 설치 이후에 엔드유저의 시간을 절약하기 위함이거나 나중의 패칭을 위한 기반의 역할을 하기 위해서입니다. Streaming Assets 는 이 경우에 이상적입니다. 그러나 커스텀 다운로딩 및 캐싱 시스템을 선택할 수 없다면, 업데이트가능한 칸텐트의 초기 리비전은 스트리밍 애셋에서 유니티 캐시로 로드될 수 있습니다.


4.2.1.1. Streaming Assets


설치시에 유니티 애플리케이션에 모든 유형의 칸텐트를 포함하는 가장 쉬운 방법은 프로젝트를 빌드하기 전에 칸텐트를 /Assets/StreamingAssets/ 폴더에 빌드하는 것입니다. 빌드시에 StreamingAssets 폴더 내에 포함된 모든 애셋은 최종 애플리케이션으로 복사됩니다. 이 폴더는 애셋번들 뿐만 아니라 최종 애플리케이션 내의 모든 유형의 칸텐트를 저장하기 위해 사용될 수 있습니다.


로컬 저장소 상에서 StreamingAssets 폴더의 전체 경로는 런타임에 Application.streamingAssetsPath 프라퍼티를 통해서 접근할 수 있습니다. 대부분의 플랫폼에서 애셋번들들은 AssetBundle.LoadFromFile 을 통해 로드될수 있습니다.


안드로이드 개발자: 안드로이드에서 Application.streamingAssetsPath 는 압축된 .jar 파일을 가리킬 것입니다. 마치 애셋번들이 압축된 것처럼 말이죠. 이 경우, WWW.LoadFromCacheOrDownload 을 호출해서 개별 애셋번들을 로드해야 합니다. 또한 .jar 파일을 압축해제하기 위한 커스텀 코드를 작성하고 애셋번들을 로컬 저장소의 읽기가능 위치로 추출하는 것도 가능합니다.


노트: 스트리밍 애셋은 특정 플랫폼에서는 쓰기가능한 위치가 아닙니다. 만약 프로젝트의 애셋번들이 설치 후에 갱신될 필요가 있다면, WWW.LoadFromCacheOrDownload 를 사용하거나 커스텀 다운로더를 작성하십시오. 세부사항을 원한다면 Custom downloaders - storage 섹션을 참고하십시오.


4.2.2. Downloaded post-install


애셋번들을 모바일 디바이스로 전송하기 위해 선호되는 기법은 번들을 앱 설치 후에 다운로드하는 것입니다. 이는 사용자가 전체 애플리케이션을 다시 다운로드하게 하지 않고도 설치 후에 새로운 혹은 변경된 칸텐트들을 사용해 칸텐트들이 업데이트될 수 있도록 해 줍니다. 모바일 플랫폼에서, 애플리케이션 바이너리들은 비싸고 복잡한 재인증 절차를 밟아야만 합니다. 그러므로 post-install 다운로드를 위한 좋은 시스템을 개발하는 것이 중요합니다.


애셋번들을 전송하기 위한 가장 단순한 방법은 웹 서버에 그것을 배치하고 WWW.LoadFromCacheOrDownload 혹은 UnityWebRequest 를 통해 전송하는 것입니다. 유니티는 자동으로 다운로드된 애셋번들을 로컬 저장소에 캐싱합니다. 만약 다운로드된 애셋번들이 LZMA 로 압축이 되어 있다면, 그 애셋번들은 추후의 빠른 로딩을 위해 압축이 안 된 캐시로 저장될 것입니다. 만약 다운로드된 번들이 LZ4 로 압축이 되어 있다면, 애셋번들은 압축된 상태로 저장될 것입니다.


만약 캐시가 꽉 차면, 유니티는 가장 최근에 사용되지 않은 애셋번들을 캐시에서 제거합니다. 세부사항을 원하면 Built-in caching 을 참고하십시오.


WWW.LoadFromCacheOrDownload 는 결점을 가지고 있음에 주의하십시오. Loading AssetBundles 섹션에서 기술했듯이, WWW 오브젝트는 다운로드를 하는 동안 애셋번들의 데이터와 같은 크기의 메모리를 소비합니다. 이는 원치않는 메모리 스파이크를 유발할 수 있습니다. 이를 피하기 위한 세 가지 방법이 있습니다:


    • 애셋번들을 작은 크기로 만드십시오. 번들이 다운로드되고 있을 때 애셋번들의 최대 크기는 프로젝트의 메모리 예산에 의해 결정될 것입니다. 다운로딩 스크린을 가진 애플리케이션은 애셋번들을 백그라운드에서 스트리밍하는 애플리케이션보다 더 많은 메모리를 할당할 수 있습니다.
    • 만약 유니티 5.3 이상 버전을 사용하고 있다면, 새로운 UnityWebRequest API 의 DownloadHandlerAssetBundle 로 전환하시기 바랍니다. 이는 다운로드 동안 메모리 스파이크를 일으키지 않습니다.
    • 커스텀 다운로더를 작성하십시오. 더 많은 정보를 원한다면 Custom downloaders 섹션을 참고하십시오.


가능하면 UnityWebRequest 를 사용해서 시작하는 것을 권합니다. 만약 5.2 이전 버전을 사용한다면 WWW.LoadFromCacheOrDownload 를 사용하십시오. 만약 built-in API 의 메모리 소비, 캐싱, 동작, 성능이 특정 프로젝트에서 원치 않는 결과를 보여 준다면, 혹은 프로젝트가 플랫폼-특정 코드를 실행해서 그것의 요구를 만족시켜야만 한다면, 커스텀 다운로드 시스템에 투자하십시오.


UnityWebRequest 나 WWW.LoadFromCacheOrDownload 의 사용을 막아야 하는 경우는 다음과 같습니다:


    • 애셋번들 캐시에 대한 fine-grained 제어가 요구될 때
    • 프로젝트가 커스텀 압축 전략을 구현할 필요가 있을 때
    • 프로젝트가 플랫폼-특정 API 를 사용해서, 비활성화되어 있는 동안 데이터를 스트림하고자 하는 요구같은, 특정 요구를 만족시키고자 할 때 
      • 예: iOS 백그라운드 태스크 API 를 사용해 백그라운드에서 데이터를 다운로드하고자 할 때
    • ( PC 처럼 ) 적절한 SSL 지원을 가지고 있지 않은 플랫폼 상에서, SSL 을 통해 전송되어야만 할때


4.2.3. Built-in caching


유니티는 빌트인 애셋번들 캐싱 시스템을 가지고 있는데, 이는 WWW.LoadFromCacheOrDownload 나 UnityWebRequest API 를 통해 다운로드된 애셋번들을 캐싱하기 위해서 사용될 수 있습니다.


두 API 는 모두 애셋번들 버전 번호를 인자로 받는 오우버로드 메서드를 가지고 있습니다. 이 번호는 애셋번들 내에 저장되는 것이 아니며, 애셋번들 시스템에 의해서 생성되지도 않습니다.


캐싱 시스템은 WWW.LoadFromCacheOrDownload 나 UnityWebRequest 에 넘겨진 마지막 버전 번호의 기록을 유지합니다. 다른 API 가 버전 번호와 함께 호출될 때, 캐싱 시스템은 캐싱된 애셋번들이 존재하는지를 확인합니다. 만약 존재한다면, 그것은 애셋번들이 처음 캐싱되었을 때 넘겨진 버전 번호와 현재 호출에 넘겨진 버전 번호를 비교합니다. 만약 이 번호가 일치하면, 시스템은 캐싱된 애셋번들을 로드하게 됩니다. 만약 번호가 일치하지 않거나 캐싱된 애셋번들이 존재하지 않는다면, 유니티는 새로운 복사본을 다운로드합니다. 이 새로운 복사본은 새로운 버전 번호와 연관됩니다.


캐싱 시스템 내의 애셋번들은 그것들이 다운로드되었던 전체 URL 에 의해서가 아니라 파일 이름에 의해서만 식별됩니다. 이는 같은 이름을 가진 애셋번들이 서로 다른 위치에 저장될 수도 있다는 것을 의미합니다. 예를 들면 애셋번들은 CDN( Content Delivery Network )의 다중 서버 상에 배치될 수 있습니다. 파일 이름이 동일한 이상, 캐싱 시스템은 그것들을 같은 애셋번들로 인지합니다.


애셋번들에 버전 번호를 할당하고 이 번호를 WWW.LoadFromCacheOrDownload 에 넘기기 위한 적절한 전략을 세우는 것은 개별 애플리케이션에 달려 있습니다. 대부분의 애플리케이션들은 유니티 5 의 AssetBundleManifest API 를 사용할 수 있습니다. 이 API 는 애셋번들 칸텐트의 MD5 해시를 계산함으로써 각 애셋번들의 버전 번호를 생성합니다. 애셋번들이 변경될 때마다 그것의 해시는 변경되며, 이는 그 애셋번들이 다운로드되어야만 한다는 것을 지시합니다.


노트: 유니티 빌트인 캐시 구현의 특이점( quirk ) 때문에, 예전 애셋번들은 캐시가 꽉 차기 전까지는 삭제되지 않을 것입니다. 유니티는 앞으로의 릴리스에서 이 특이점에 대해 고심할 의도를 가지고 있습니다.


세부사항을 원한다면 Patching with AssetBundles 섹션을 참고하십시오.


유니티의 빌트인 캐싱은 Caching 오브젝트 상의 API 를 호출함으로써 제어될 수 있습니다. 유니티 캐시의 동작은 Caching.expirationDelay 와 Caching.maximumAvailableDiskSpace 를 변경함으로써 제어될 수 있습니다.


Caching.expirationDelay 는 애셋번들이 자동으로 제거되기 전에 기다려야 할 최소한의 시간( 초 )입니다. 만약 이 시간 동안 애셋번들에 대한 접근이 없으면, 그것은 자동으로 지워집니다.


Caching.maximumAvailableDiskSpace determines the amout of space on local storage that the cache may use before it begings deleting AssetBundles that have been used less recently than the expirationDelay. 그것은 바이트 단위로 카운팅됩니다. 제한에 도달하게 되면, 유니티는 가장 옛날에 열린( 혹은 Caching.MarkedAsUsed 로 마킹된 ) 캐시에서 애셋번들을 제거합니다. 유니티는 새로운 다운로드를 완료하기 위해 충분한 공간을 확보할 때까지 캐싱된 애셋번들을 제거할 것입니다.


노트: 유니티 5.3 에서는 빌트인 캐시에 대한 제어가 매우 거칩니다. 특정 애셋번들을 캐시에서 제거하는 것은 불가능합니다. 그것들은 expiration 이나 디스크 공간 부족, 혹은 Caching.CleanCache 호출을 통해서만 제거될 수 있습니다( Caching.CleanCache 는 현재 캐시에 있는 모든 애셋번들을 제거하게 됩니다 ). 이는 개발이나 라이브 연산 동안에는 문제가 될 수 있습니다. 왜냐하면 유니티가 애플리케이션에 의해서 더 이상 사용되지 않는 애셋번들을 자동으로 지워주지 않기 때문입니다.


4.2.3.1. Cache Priming


애셋번들은 파일 이름으로 식별되기 때문에, 애플리케이션에 포함된 애셋번들을 사용하는 캐시를 "미리 지정하는( prime )" 것이 불가능합니다. 이를 위해서는, 각 애셋번들의 초기 혹은 기본 버전을 /Assets/StreamingAssets/ 에 저장하십시오. 그 절차는 Shipped with project 섹션에서 세부적으로 설명한 것과 동일합니다.


애플리케이션이 처음 실행될 때 Application.streamingAssetsPath 로부터 애셋번들을 로딩함으로써 캐시가 생성될 수 있습니다. 그 때부터, 애플리케이션은 WWW.LoadFromCacheOrDownloads 나 UnityWebRequest 를 정상적으로 호출할 수 있습니다.


4.2.4. Custom downloaders


커스텀 다운로더를 작성하는 것은 애플리케이션으로 하여금 애셋번들을 다운로드하고, 압축해제하고, 저장하는 것과 관련한 모든 제어를 할 수 있게 해 줍니다. 커스텀 다운로더를 작성하는 것은 야심찬 애플리케이션을 작성하고 있는 큰 팀들에 대해서만 권장됩니다. 커스텀 다운로더를 작성하는 동안 생각해야 하는 네 가지 정도의 문제가 있습니다:


    • 애셋번들을 다운로드하는 방법.
    • 애셋번들을 저장할 위치.
    • 애셋번들을 압축하는 방법이나 압축할지 여부.
    • 애셋번들을 패치하는 방법.


애셋번들을 패치하는 것과 관련한 더 많은 정보를 원한다면, Patching with AssetBundles 섹션을 참고하십시오.


4.2.4.1. Downloading


대부분의 애플리케이션에서, HTTP 는 애셋번들을 다운로드하는 가장 단순한 방법입니다. 그러나 HTTP 기반 다운로더를 구현하는 것은 단순한 작업이 아닙니다. 커스텀 다운로더는 너무 많은 메모리를 할당하는 행위, 너무 많은 스레드를 사용하는 행위 등을 피해야만 합니다. 유니티의 WWW 클래스는 여기에서 속속들이 설명한 이유 때문에 부적절합니다. WWW 는 높은 메모리 비용을 가지고 있으므로, WWW.LoadFromCacheOrDownload 클래스를 사용하는 경우가 아니라면 유니티의 WWW 클래스를 사용하는 것은 피하는 것이 좋습니다.


커스텀 다운로더를 작성할 때, 세 가지 옵션이 있습니다:


    • C# 의 HttpWebRequest 와 WebClient 클래스.
    • 커스텀 네이티브 플러그인.
    • 애셋 스토어 패키지.


4.2.4.1.1. C# classes


애플리케이션이 HTTPS/SSL 지원을 요구하지 않는다면, C# 의 WebClient 클래스는 애셋번들을 다운로드하기 위한 가장 단순한 가능성있는 메커니즘을 제공합니다. 그것은 관리되는 메모리 할당을 초과하는 일이 없이 로컬 저장소에 파일을 바로 다운로드하는 기능을 제공합니다.


애셋번들을 WebClient 를 통해 다운로드하기 위해서는, 클래스의 인스턴스를 할당하고 그것에 다운로드할 애셋번들의 URL 과 대상 경로를 넘깁니다. 만약 요청 파라미터에 대한 더 많은 제어를 원한다면, HttpWebRequest 클래스를 사용해서 다운로더를 작성하는 것이 가능합니다.


    1. HttpWebResponse.GetResponseStream 으로부터 바이트 스트림을 획득합니다.
    2. 고정 크기 바이트 버퍼를 스택에 할당합니다.
    3. 응답 스트림으로부터 읽어들여 버퍼에 씁니다.
    4. C# File.IO API 를 사용하거나 다른 스트리밍 IO 시스템을 사용해서 버퍼를 디스크에 씁니다.


플랫폼 노트: iOS, 안드로이드, 윈도우즈 폰은 유니티 C# 런타임이 C# HTTP 클래스들을 위한 HTTPS/SSL 지원을 포함하고 있는 유일한 플랫폼들입니다. PC 에서는, C# 클래스를 통해 HTTPS 서버에 접근하는 시도가 인증서 검증 에러( certificate validation error )를 발생시킬 것입니다.


4.2.4.1.2. Asset Store Packages


몇 개의 애셋 스토어 패키지들은 HTTP, HTTPS, 그리고 다른 프로토콜들을 통해서 파일을 다운로드하기 위한 네이티브 코드 구현을 제공하고 있습니다. 커스텀 네이티브 코드 플러그인을 작성하기 전에, 이용가능한 애셋 스토어 패키지들을 평가해 보실 것을 권합니다.


4.2.4.1.3. Custom Native Plugins


커스텀 네이티브 플러그인을 작성하는 것은 매우 시간이 많이 걸리는 작업이며 유니티에서 데이터를 다운로딩하기 위한 더욱 유연한 기법입니다. 프로그래밍 시간이 오래 걸리고 기술적 위험도가 높으므로, 이 기법은 다른 기법들이 애플리케이션의 요구사항을 만족시켜주지 못했을 때만 사용할 것을 권합니다. 예를 들어, 커스텀 네이티브 플러그인은 유니티의 C# SSL 지원이 없는 플랫폼( 윈도우즈, OSX, Linux )에서 애플리케이션이 SSL 통신을 해야만 하는 경우가 있습니다.


커스텀 네이티브 플러그인은 일반적으로 대상 플랫폼의 네이티브 다운로딩 API 에 대한 래퍼일 것입니다. iOS 의 NSURLConnection 과 안드로이드의 java.net.HttpURLConnection 이라는 예제가 있습니다. 이러한 API 를 사용하는 데 있어서의 세부사항을 원한다면 각 플랫폼의 네이티브 문서를 참고하십시오.


4.2.4.2. Storage


모든 플랫폼에서, Application.persistentDataPath 는 애플리케이션을 여러 번 실행하는 동안 지속적으로 유지되어야 하는 데이터를 저장하기 위해서 사용되어야 하는 쓰기가능한 위치를 가리킵니다. 커스텀 다운로더를 사용할 때는, Application.persistentDataPath 의 하위 디렉토리에 다운로드된 데이터를 저장할 것을 강력히 권합니다.


Application.streamingAssetPath 는 쓰기가능한 위치가 아니며, 애셋번들 캐시를 위해서는 좋지 않은 선택입니다. StreamingAssetsPath 가 포함하는 위치의 예는 다음과 같습니다:


    • OSX: .app 패키지 내; 쓰기 불가능.
    • Windows: 설치 디렉토리 내( 예를 들어 program files ); 보통 쓰기 불가능.
    • iOS: ipa 패키지 내; 쓰기 불가능.
    • Android: 압축된 .jar 파일 내; 쓰기 불가능.


4.3. Asset Assignment Strategies


프로젝트의 애셋을 애셋번들로 어떻게 나눌지를 결정하는 것은 쉽지 않은 문제입니다. 모든 오브젝트에 대해 각각의 애셋번들을 만들거나 하나의 애셋번들만 사용하는 것과 같은 단순한 전략을 취하고 싶은 충동을 느끼게 될 것입니다. 하지만 이러한 해결책은 심각한 단점들을 가지고 있습니다:


    • 너무 적은 애셋번들을 가지고 있습니다...
      • 런타임 메모리 사용량이 증가합니다.
      • 로딩 시간이 증가합니다.
      • Requires larger downloads

    • 너무 많은 애셋번들을 가지고 있습니다...
      • 빌드 시간이 증가합니다.
      • 개발이 복잡해집니다.
      • 전체 다운로드 시간이 증가합니다.


핵심 결정 사항은 오브젝트를 애셋번들에 어떻게 그룹화하느냐입니다. 주요 전략은 다음과 같습니다:


    • 논리적 요소들.
    • 오브젝트 유형들.
    • 동시성 칸텐트.


단일 프로젝트는 서로 다른 칸텐트 카테고리들을 위해 이들 전략을 섞을 수 있고 섞어야만 합니다. 예를 들어, 프로젝트는 UI 요소들을 서로 다른 플랫폼을 위한 애셋번들로 그룹화할 수 있습니다. 그러나 그것의 인터랙티브 칸텐트는 레벨이나 씬 단위로 그룹화합니다. 적용한 전략과 관계없이, 다음은 좋은 가이드라인이 됩니다:


    • 자주 갱신되는 오브젝트는 보통 변경되지 않는 오브젝트와는 다른 애셋번들로 나눕니다.
    • 동시에 로드될 것 같은 오븢게트는 함께 그룹화합니다.


예: 모델, 그것의 애니메이션, 텍스쳐.


    • 만약 오브젝트가 서로 다른 애셋번들 내에 있는 다수 개의 오브젝트들에 대한 종속성을 가지고 있다면, 그 애셋을 개별 애셋번들로 이동시키십시오.
      • 이상적으로 볼 때, 자식 오브젝트들을 그것의 부모 오브젝트들과 함께 그룹화하는 것이 좋습니다.
    • 만약 ( 텍스쳐의 HD 및 SD 버전 처럼 ) 두 개의 오브젝트들이 동시에 로드되는 것을 원하지 않는다면, 그것들을 개별 애셋번들로 나누십시오.
    • 만약 오브젝트들이 서로 다른 임포터 세팅이나 데이터를 가지고 있기 때문에 같은 오브젝트에 대한 서로 다른 버전이 된 것이라면, 애셋번들 Variants 를 대신 사용하십시오.


Once the above guideline are followed, 애셋번들 칸텐트의 50% 보다 적은 부분이 주어진 시간에 로드된다면 애셋번들을 분리하는 것을 고려하시기 바랍니다. 또한 동시에 로드되는 작은 애셋번들( 5 ~ 10 개 보다 적은 애셋 )들을 합치는 것을 고려하시기 바랍니다.


4.3.1. Logical entity grouping


논리적 엔터니 그룹화 전략에서는 오브젝트들이 그것들이 제공하는 프로젝트의 기능적 부분에 기반해서 그룹화됩니다. 이 전략에 따르면, 애플리케이션의 서로 다른 부분들은 서로 다른 애셋번들로 분리됩니다.


예:


    • UI 스크린을 위한 모든 텍스쳐와 레이아웃 데이터를 함께 번들로 묶습니다.
    • 캐릭터 셋을 위한 텍스쳐, 모델, 애니메이션을 함께 번들로 묶습니다.
    • 많은 레벨에서 공유되는 배경 조각들을 위한 텍스쳐와 모델들을 함께 번들로 묶습니다.


논리적 엔터티 그룹화는 가장 일반적인 애셋번들 전략입니다. 그리고 이는 다음과 같은 상황에 특히 적합합니다:


    • DLC( 역주 : Downloadable Content ).
    • 애플리케이션 생명주기 전반에 걸쳐 많은 곳에서 나타나는 엔터티들.


예:


    • 공통 캐릭터나 기본 UI 요소들.
    • 플랫폼이나 성능 세팅에 기반해서 다양해지는 엔터티들.


애셋을 논리적 엔터티에 의해서 그룹화하는 것의 장점은 변경되지 않은 칸텐트들을 다시 다운로드하지 않고도 개별 엔터티들을 쉽게 갱신할 수 있게 한다는 것입니다. 이것이 이 전략이 DLC 를 위해 특히 적합한 이유입니다. 이 전략은 대부분 메모리에 대해 효율적입니다. 왜냐하면 애플리케이션은 현재 사용중인 엔터티를 제출하는 애셋번들만을 로드할 필요가 있기 때문입니다.


그러나 이 전략은 구현하기 애매한 전략입니다. 왜냐하면 개발자들이 개별 오브젝트가 프로젝트에 의해서 언제 어떻게 사용되는지를 정확하게 알아야만 오브젝트들을 애셋번들에 할당할 수 있기 때문입니다.


4.3.2. Type Grouping


타입 그룹화는 가장 단순한 전략입니다. 이 전략에서, 비슷하거나 동일한 타입을 가진 오브젝트들이 같은 애셋번들에 묶입니다. 예를 들어, 여러 개의 서로 다른 오디오 트랙들이 애셋번들에 배치되거나, 여러 개의 서로 다른 언어 파일들이 애셋번들에 배치될 수 있습니다.


이 전략은 단순하지만, 빌드 시간, 로딩 시간, 업데이트 시간의 관점에서 봤을 때는 가장 비효율적입니다. 이 전략은 지역화 파일들처럼 작고 동시에 갱신되는 파일들을 위해서 자주 사용됩니다.


4.3.3. Concurrent content grouping


동시 칸텐트 그룹화는 오브젝트들이 동시에 로드되고 사용될 때 하나의 애셋번들로 묶는 전략입니다. 이 전략은 칸텐트가 매우 지역적인 프로젝트에서 보통 사용됩니다: 여기에서 칸텐트는 애플리케이션의 특정 위치나 시점에서 벗어나서 나타나지 않습니다. 예를 들어, 개별 레벨마다 유일한 아트, 캐릭터, 사운드 이펙트가 나오는 레벨 기반 게임을 들 수 있습니다.


동시-칸텐트 그룹화를 수행하기 위한 가장 일반적인 기법은 씬에 기반해 애셋번들을 생성하는 것입니다. 이 때 씬의 종속성을 거의 혹은 모두 포함하는 씬 기반 애셋번들을 사용합니다.


칸텐트가 매우 지역적이지 않거나 칸텐트가 애플리케이션 생명주기 동안에 다양한 위치에서 나타나는 프로젝트의 경우에는, 동시 칸텐트 그룹화는 논리적 엔터티 그룹화와 결합됩니다. 둘다 주어진 애셋번들의 칸텐트의 유용성을 최대화하기 위해서 필수적인 전략들입니다.


이 시나리오의 예는 오픈월드 게임입니다. 여기에서는 캐릭터들이 랜덤하게 스폰되며 월드 공간에 펴져 있습니다. 이 경우, 캐릭터가 동시에 어디에서 나타날지 예측하는 것은 쉽지 않습니다. 그래서 그것들은 일반적으로 서로 다른 전략을 사용해서 그룹화되어야 합니다.


4.4. Patching with AssetBundles


애셋번들을 패치하는 것은 새로운 애셋번들을 다운로드하고 그것을 현존하는 것과 교체하면 되기 때문에 매우 단순합니다. 만약 애플리케이션의 캐싱된 애셋번들을 관리하기 위해서 WWW.LoadCacheOrDownloadUnityWebRequest 가 사용되었다면, 이는 선택된 API 에 다른 version 매개변수를 넘기기만하므로 단순합니다( 더 많은 세부사항을 원한다면 스크립팅 레퍼런에 대한 위의 링크를 참고하세요 ). 


패칭 시스템에 있어서 해결하기 어려운 문제는 어떠한 애셋번들이 대체되어야 하는지를 찾는 것입니다. 패칭 시스템은 두 개의 리스트를 요구합니다:


    • 현재 다운로드된 애셋번들과 그것들의 버전 정보 리스트.
    • 서버 상의 애셋번들과 그것들의 버전 정보 리스트.


패쳐는 서버측의 애셋번들 리스트를 다운로드하여 애셋번들 리스트와 비교해야 합니다. Missing 애셋번들이나 버전 정보가 변한 애셋번들은 다시 다운로드되어야 합니다.


유니티 5 의 애셋번들 시스템은 빌드가 완료되었을 때 새로운 부가적인 애셋번들을 생성합니다. 이 부가적인 애셋번들은 AssetBundleManifest 오브젝트를 포함합니다. 이 매니페스트 오브젝트는 애셋번들의 리스트와 그것의 해시를 포함하고 있으며, 그것은 이용가능한 애셋번들의 리스트와 버전 정보를 클라이언트에 전송하기 위해서 사용됩니다. 애셋번들 매니페스트 번들에 대한 더 많은 정보를 원한다면 유니티 매뉴얼을 참고하세요.


애셋번들의 변화를 검색하는 커스텀 시스템을 작성하는 것도 가능합니다. 자신만의 시스템을 작성하는 대부분의 개발자들은 애셋번들 파일 리스트를 위해 JSON 같은 업계-표준 데이터 포맷을 사용하며, MD5 와 같은 체크섬을 계산하기 위해서 표준 C# 클래스를 사용합니다.


4.4.1. Differential patching


유니티 5 에서, 유니티는 결정론적인 방식으로 순서화된 데이터를 사용해 애셋번들을 빌드할 수 있습니다. 이는 커스텀 다운로더를 가진 애플리케이션이 differential patching( 역주 : 미분 패칭? ) 을 구현할 수 있도록 해 줍니다. 결정론적 레이아웃을 사용해서 애셋번들을 빌드하기 위해서는, BuildAssetBundleOptions.DeterministicAssetBundle 플래그를 BuildAssetBundles API 를 호출할 때 넘깁니다( 더 많은 세부 사항을 원한다면 스크립팅 레퍼런스 링크를 참고하세요 ).


유니티는 differential patching 을 위한 내장 메커니즘을 제공하지 않습니다. 그리고 WWW.LoadFromCachedOrDownload 나 UnityWebRequest 는 내장 캐싱 시스템을 사용할 때 differential patching 을 수행하지 않습니다. 만약 differntial pathcing 이 요구되면, 커스텀 다운로더를 작성해야 합니다.


4.4.2. iOS On-Demand Resources


온디맨드 리소스는 iOS 와 TVOS 장치에 칸텐트를 제공하기 위한 애플 API 입니다. 이는 iOS 9 장치에서 이용할 수 있습니다. 이것은 앱스토어 상에 런칭하는 데는 요구되지 않습니다만, TVOS 앱을 위해서는 요구됩니다.


애플의 온디맨드 리소스 시스템의 일반적인 개요는 애플 개발자 사이트에서 찾아볼 수 있습니다.


As of Unity 5.2.1, support for App Slicing and On-Demand Resources are both built upon another Apple system, Asset Catalogs. After registering a callback in the Unity Editor, the build pipeline for an iOS applications can report a set of files which will be automatically placed into Asset Catalogs and assigned specified On-Demand Resources tags.


A new UnityEngine.iOS.OnDemandResources API provides runtime support for retrieving and caching On-Demand Resources files. Once resources have been retrieved via ODR, they can then be loaded into Unity via the standard AssetBundle.LoadFromFile API.


For more details and an example project, see this Unity forum post.


4.5. Common Pitfalls


이 섹션은 애셋번들을 사용할 때 프로젝트에서 일반적으로 나타날 수 있는 몇 가지 문제들에 대해서 기술합니다.


4.5.1. Asset duplication


유니티 5 의 애셋번들 시스템은 오브젝트가 애셋번들에서 빌드될 때 오브젝트의 모든 종속성을 고려하지 않습니다. 이는 애셋 데이터베이스를 사용해서 수행됩니다. 이 종속성 정보는 애셋번들에 포함될 오브젝트 집합을 결정하는데 사용하는 정보입니다.


애셋번들에 명시적으로 할당된 오브젝트들은 그 애셋번들로 빌드되어야 할것입니다. 오브젝트의 AssetImporter 가 그것의 assetBundleName 속성을 비어있지 않은 문자열로 설정할 때 오브젝트는 "명시적으로" 할당됩니다. 이는 유니티 에디터에서 수행되는데, 오브젝트의 인스펙터나 에디터 스크립트로부터 애셋번들을 선택함으로써 수행될 수 있습니다.


애셋번들에 명시적으로 할당되지 않은 모든 오브젝트는 표시되지 않은 오브젝트를 참조하는 하나 이상의 오브젝트를 포함하는 모든 애셋번들들에 포함될 것입니다.


만약 두 개의 오브젝트가 서로 다른 애셋번들에 할당되었지만 둘다 공통 종속성 오브젝트를 참조하고 있다면, 그 종속성 오브젝트는 두 애셋번들에 모두 복사됩니다. 중복된 종속성이 인스턴스화될 것입니다. 이는 종속성 오브젝트에 대한 두 개의 복사본이 서로 다른 식별자를 가진 서로 다른 오브젝트로 고려된다는 것을 의미합니다. 이는 애플리케이션의 애셋번들의 전체 크기를 증가시킵니다. 또한 애플리케이션이 그것의 부모를 모두 로드한다면, 오브젝트의 서로 다른 복사본이 메모리에 로드될 것입니다.


이 문제를 해결하기 위한 두 가지 방법이 있습니다:


  1. 서로 다른 애셋번들에 빌드된 오브젝트가 같은 종속성을 가지지 않도록 합니다. 종속성을 공유하는 모든 오브젝트들은 자신의 종속성들을 복사하지 않고 같은 애셋번들에 배치될 수 있습니다.
    • 이 기법은 많은 공유 종속성을 가진 프로젝트에 대해서는 항상 실행가능한 것이 아닙니다. 이는 모놀리식 애셋번들을 생성하며, 그 애셋번들은 편의성과 효율성을 위해서 너무 자주 리빌드되거나 다시 다운로드되어야만 합니다.
  2. 애셋번들을 세그먼트화하면 종속성을 공유하는 두 개의 애셋번들이 동시에 로드되지 않을 것입니다.
    • 이 기법은 레벨 기반 게임과 같은 특정 유형의 프로젝트에 대해서 작동할 것입니다. 그러나 여전히 프로젝트의 애셋번들의 크기, 빌드 시간, 로딩 시간이 불필요하게 늘어납니다.
  3. 종속성 애셋이 자신만의 애셋번들에 빌드되도록 합니다. 이는 전체적으로 중복 애셋의 위험성을 제거합니다만, 복잡도를 증가시킵니다. 애플리케이션은 애셋번들 간의 종속성을 추적해서 AssetBundle.LoadAsset API 호출 전에 올바른 애셋번들이 로드되어 있도록 해야만 합니다.


유니티 5 에서, 오브젝트 종속성은 AssetDatabase API 를 통해 추적될 수 있습니다. 이는 UnityEditor 네임스페이스에 존재합니다. 네임스페이스가 내포하고 있듯이, 이 API 는 유니티 에디터에서만 사용할 수 있으며 런타임에는 사용할 수 없습니다. AssetDatabase.GetDependencies 는 특정 오브젝트나 애셋의 즉각적인 종속성을 모두 찾아내기 위해서 사용됩니다. 이 종속성들은 자신만의 종속성들을 가질 수도 있다는 점에 주의하십시오. 부가적으로, AssetImporter API 는 특정 오브젝트가 할당된 애셋번들을 질의하는데 사용될 수 있습니다.


AssestDatabase 와 AssetImporter API 를 혼용함으로써, 애셋번들의 직접적인 혹은 간접적인 종속성들을 모두 애셋번들에 할당하거나 애셋번들에 할당되지 않은 종속성을 애셋번들이 공유하고 있는지를 확인하는 에디터 스크립트를 작성하는 것이 가능합니다. 애셋이 중복되는 것의 메모리 비용 때문에, 모든 프로젝트에서 그런 스크립트를 제작하기를 권장합니다.


4.5.2. Sprite atlas duplication


다음 섹션은 자동으로 생성된 스프라이트 아틀라스를 결합했을 때 유니티 5 애셋 종속성 계산 코드의 특이함에 대해 기술합니다. 유니티 5.2.2p4 와 유니티 5.3 은 이 동작을 해결하기 위해서 패치되었습니다.


Unity 5.2.2p4, 5.3 and newer


자동으로 생성된 모든 스프라이트 아틀라스들은 스프라이트 아틀라스가 생성된 스프라이트 오브젝트를 포함하는 애셋번들에 할당될 것입니다. 만약 스프라이트 오브젝트가 다수개의 애셋번들에 할당되었다면, 스프라이트 아틀라스는 애셋번들에 할당되지 않고 중복되게 될 것입니다. 또한 만약 스프라이트 오브젝트가 애셋번들에 할당되지 않았다면, 스프라이트 아틀라스는 애셋번들에 할당되지 않을 것입니다.


스프라이트 아틀라스가 중복되지 않도록 하기 위해서는 같은 스프라이트 아틀라스라고 표기된 모든 스프라이트들이 같은 애셋번들에 할당되었는지 확인하십시오.


Unity 5.2.2p3 and older


Automatically-generated sprite atlases will never be assigned to an AssetBundle. Because of this, they will be included in any AssetBundles containing their constituent sprites and also any AssetBundles referencing their constituent sprites.


Because of this problem, it is strongly recommended that all Unity 5 projects using Unity's sprite packer upgrade to Unity 5.2.2p4, 5.3 or any newer version of Unity.


For projects that cannot upgrade, there are two workarounds for this problem:


    1. Easy: Avoid using Unity's built-in sprite packer. Sprite atlases generated by external tools will be normal Assets, and can be properly assigned to an AssetBundle.
    2. Hard: Assign all Objects that use automatically atlased sprites to the same AssetBundle as the sprites.


    • This will ensure that the generated sprite atlas is not seen as the indirect dependency of any other AssetBundles and will not be duplicated.
    • This solution preserves the simple workflow of using Unity's sprite packer, but it degrades developers' ability to separate Assets into different AssetBundles, and forces the re-download of an entire sprite atlas when any data changes on any component referencing the atlas, even if the atlas itself is unchanged.


4.5.3. Android textures


Due to heavy device fragmentation in the Android ecosystem, it is often necessary to compress textures into several different formats. While all Android devices support ETC1, ETC1 does not support textures with alpha channels. Should an application not require OpenGL ES 2 support, the cleanest way to solve the problem is to use ETC2, which is supported by all Android OpenGL ES 3 devices.


Most applications need to ship on older devices where ETC2 support is unavailable. One way to solve this problem is with Unity 5's AssetBundle Variants. (Please see Unity's Android optimization guide for details on other options.)


To use AssetBundle Variants, all textures that cannot be cleanly compressed using ETC1 must be isolated into texture-only AssetBundles. Next, create sufficient variants of these AssetBundles to support the non-ETC2-capable slices of the Android ecosystem, using vendor-specific texture compression formats such as DXT5, PVRTC and ATITC. For each AssetBundle Variant, change the included textures' TextureImporter settings to the compression format appropriate to the Variant.


At runtime, support for the different texture compression formats can be detected using the SystemInfo.SupportsTextureFormat API. This information should be used to select and load the AssetBundle Variant containing textures compressed in a supported format.


More information on Android texture compression formats can be found here.


4.5.4. iOS file handle overuse


이 이슈는 5.3.2p2 에서 해결되었습니다. 현재 버전의 유니티는 이 이슈의 영향을 받지 않습니다.


In versions prior to Unity 5.3.2p2, Unity would hold an open file handle to an AssetBundle the entire time that the AssetBundle is loaded. This is not a problem on most platforms. However, iOS limits the number of file handles a process may simultaneously have open to 255. If loading an AssetBundle causes this limit to be exceeded, the loading call will fail with a "Too Many Open File Handles" error.


This was a common problem for projects trying to divide their content across many hundreds or thousands of AssetBundles.


For projects unable to upgrade to a patched version of Unity, temporary solutions are:


    • Reducing the number of AssetBundles in use by merging related AssetBundles
    • Using AssetBundle.Unload(false) to close an AssetBundle's file handle, and managing the loaded Objects' lifecycles manually


4.6. AssetBundle Variant


A key feature of Unity 5's AssetBundle system is the introduction of AssetBundle Variants. The purpose of Variants is to allow an application to adjust its content to better suit its runtime environment. Variants permit different UnityEngine.Objects in different AssetBundle files to appear as being the "same" Object when loading Objects and resolving Instance ID references. Conceptually, it permits two UnityEngine.Objects to appear to share the same File GUID & Local ID, and identifies the actual UnityEngine.Object to load by a string Variant ID.


There are two primary use cases for this system:


  1. Variants simplify the loading of AssetBundles appropriate for a given platform.
    • Example: A build system might create an AssetBundle containing high-resolution textures and complex shaders suitable for a standalone DirectX11 Windows build, and a second AssetBundle with lower-fidelity content intended for Android. At runtime, the project's resource loading code can then load the appropriate AssetBundle Variant for its platform, and the Object names passed into the AssetBundle.Load API do not need to change.
  2. Variants allow an application to load different content on the same platform, but with different hardware.
    • This is key for supporting a wide range of mobile devices. An iPhone 4 is incapable of displaying the same fidelity of content as an iPhone 6 in any real-world application.
    • On Android, AssetBundle Variants can be used to tackle the immense fragmentation of screen aspect ratios and DPIs between devices.


4.6.1. Limitations


A key limitation of the AssetBundle Variant system is that it requires Variants to be built from distinct Assets. This limitation applies even if the only variations between those Assets is their import settings. If the only distinction between a texture built into Variant A and Variant B is the specific texture compression algorithm selected in the Unity texture importer, Variant A and Variant B must still be entirely different Assets. This means that Variant A and Variant B must be separate files on disk.


This limitation complicates the management of large projects as multiple copies of a specific Asset must be kept in source control. All copies of an Asset must be updated when developers wish to change the content of the Asset.


There are no built-in workarounds for this problem.


Most teams implement their own form of AssetBundle Variants. This is done by building AssetBundles with well-defined suffixes appended to their filenames, in order to identify the specific variant a given AssetBundle represents. Custom code programmatically alters the importer settings of the included Assets when building these AssetBundles. Some developers have extended their custom systems to also be able to alter parameters on components attached to prefabs.


4.7. Compressed or Uncompressed?


애셋번들을 압축할 것이냐 말 것이냐는 주의깊게 생각해 볼 주제입니다. 중요한 질문들은 다음과 같습니다:


    • 애셋번들의 로딩 타임이 중요한 요소입니까? 압축 안 된 애셋번들이 압축된 애셋번들보다 로컬 저장소나 로컬 캐시에서 로드하는데 훨씬 빠릅니다. 압축된 애셋번들을 원격 서버에서 다운로드할 대는 압축 안 된 애셋번들을 다운로드할 때보다 빠릅니다.
    • 애셋번들의 빌드 타임이 중요한 요소입니까? LZMA 와 LZ4 는 파일을 압축할 때 매우 느립니다. 그리고 유니티 에디터는 애셋번들을 직렬적으로 처리합니다. 많은 개수의 애셋번들을 포함하는 프로젝트는 그것들을 압축하는데 많은 시간을 소비하게 될 것입니다.
    • 애플리케이션 크기가 중요한 요소입니까? 만약 애셋번들이 애플리케이션에 포함된다면, 그것들을 압축하는 것이 전체 애플리케이션의 크기를 줄이는데 도움이 될 것입니다. 대안적으로, 애셋번들을 post-install 에 다운로드할 수도 있습니다.
    • 메모리 사용량이 중요한 요소입니까? 5.3 전에는 유니티의 압축해제 메커니즘이 압축해제를 하기 전에 전체 압축된 애셋번들을 메모리에 로드할 것을 요구했습니다. 만약 메모리 사용량이 중요하다면, 압축하지 말든가 LZ4 로 압축된 애셋번들을 사용하십시오.
    • 다운로드 시간이 중요한 요소입니까? 애셋번들이 크거나 사용자가 모바일 3G 나 low-speed meterred connections 와 같은 대역폭이 제한된 환경에 있다면 압축이 필요할 것입니다. 만약 몇 십 메가바이트의 데이터를 high-speed connections 를 사용하는 PC 로 전송하고 있다면, 압축을 배제해도 될 것입니다.


4.8. AssetBundles and WebGL


유니티는 WebGL 프로젝트에서는 개발자들이 압축된 애셋번들을 사용하지 말도록 강력히 권하고 있습니다.


As of Unity 5.3, all AssetBundle decompression and loading in a WebGL project must occur on the main thread. This is because Unity 5.3's WebGL export option does not currently support worker threads. (The downloading of AssetBundles is delegated to the browser via the XMLHttpRequest Javascript API, and will occur off of Unity's main thread.) This means that compressed AssetBundles are extremely expensive to load on WebGL.


With this in mind, you may want to avoid using the default LZMA Format for your AssetBundles and compress using LZ4 instead, which is decompressed very efficiently on-demand. If you need smaller compression sizes then LZ4 delivers, you can configure your web server to gzip-compress the files on the http protocol level (on top of LZ4 compression).

원문 : AssetBundle Fundamentals

주의 : 번역이 개판이므로 이상하면 원문을 참조하세요.

주의 : 허락받고 번역한 것이 아니므로 언제든 내려갈 수 있습니다.



AssetBundle Fundamentals


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


이것은 유니티 5 의 애샛, 리소스, 그리고 리소스 관리를 다루는 기사 시리즈의 네 번째 챕터입니다.


이 챕터에서는 애셋번들에 대해서 이야기합니다. 여기에서는 애셋번들이 빌드될 때까지의 기본적인 이스템과 함께 애셋번들과 상호작용하기 위해서 사용하는 핵심 API 들에 대해서 소개합니다. 특히, 애셋번들 자체를 로드하거나 언로드하는 것과 애셋번들로부터 특정 애셋과 오브젝트를 언로드하는 것에 대해서도 논의합니다.


애셋번들을 사용함에 있어서, 더 많은 패턴 및 best practices 를 원한다면 이 시리즈의 다음 챕터를 참조하십시오.


3.1. Overview


애셋번들 시스템은 하나 이상의 파일들을 유니티가 인덱싱할 수 있는 압축( archival ) 포맷으로 저장하는 기법을 제공합니다. 이 시스템의 목적은 유니티의 직렬화 시스템과 호환되는 데이터 전송 기법을 제공하는데 있습니다. 애셋번들은 설치 후에 non-code content 를 전송하고 갱신하기 위한 유니티의 주요 도구입니다. 이는 개발자들로 하여금 shipped asset size 를 줄이고, 런타임 메모리 압력을 최소화하고, 엔드 유저의 디바이스를 위해서 최적화된 칸텐트를 선택적으로 로드할 수 있도록 해 줍니다.


애셋번들이 동작하는 방식에 대해서 이해하는 것은 모바일 디바이스를 위해 성공적인 유니티 프로젝트를 빌드하기 위한 기초입니다.


3.2. What's in an AssetBundle?


애셋번들은 두 개의 부분으로 구성됩니다: 헤더와 데이터 세그먼트.


헤더는 애셋번들이 빌드될 때 유니티에 의해서 생성됩니다. 그것은 애셋 번들에 대한 정보를 포함하는데요, 그 정보로는 애셋번들의 식별자, 압축 여부, 매니페이스( manifest ) 등이 있습니다.


매니페스트는 오브젝트의 이름을 키로 사용하는 검색 테이블입니다. 각 엔트리는 주어진 오브젝트를 애셋번들의 데이터 세그먼트의 어느 부분에서 찾을 수 있는지를 가르쳐 주는 바이트 인덱스를 제공합니다. 대부분의 플랫폼에서, 이 검색 테이블은 STL std::multimap 으로 구현됩니다. 주어진 플랫폼에서 STL 구현에 의해 사용되는 특정 알고리즘은 다양하지만, 대부분은 균형잡힌 검색 트리( balanced search tree )를 사용합니다. Windows 와 OSX 에서 파생된 ( iOS 를 포함한 ) 플랫폼들은 red-black tree 를 사용합니다. 그러므로 매니페스트를 생성하기 위해 필요한 시간은 애셋번들 내부의 애셋들이 많아질 수록 비선형적으로 증가합니다.


데이터 세그먼트는 애셋번들 내의 애셋들을 직렬화함으로써 생성된 raw data 를 포함합니다. 만약 데이터 세그먼트가 압축되어 있다면, LZMA 알고리즘이 collective sequence of serialized bytes 에 적용된 것입니다 - 즉, 모든 애셋들은 직렬화되어 있으며, 전체 바이트 배열이 압축된 것입니다.


유니티 5.3 전에는 오브젝트들이 애셋번들 내부에 개별적으로 압축될 수 없었습니다. 결과적으로 5.3 전 버전에서는 압축된 애셋번들로부터 하나 이상의 오브젝트를 읽을 때, 유니티는 전체 애셋번들을 압축해제해야 했습니다. 일반적으로 유니티는 같은 애셋번들에서 발생하는 연속적인 로딩 요청을 최적화하기 위해서 애셋번들에 대한 압축해제된 복사본을 캐싱합니다.


유니티 5.3 은 LZ4 압축 옵션을 추가했습니다. LZ4 압축 옵션으로 빌드된 애셋번들은 애셋번들 내의 오브젝트를 개별적으로 압축하며, 이는 유니티가 압축된 애셋번들을 디스크에 저장할 수 있도록 허용합니다. 이는 유니티가 전체 애셋번들을 압축해제하지 않고도 개별 오브젝트를 압축해제할 수 있도록 해 줍니다.


3.3. The AssetBundle Manager


유니티는 Bitbucket 에 애셋번들 관리자의 구현에 대한 레퍼런스를 개발하고 유지합니다. 이 관리자는 이 챕터에서 세부적으로 설명하는 많은 개념들과 API 들을 사용하며, 애셋번들을 리소스 관리 워크플로우에 통합해야 하는 프로젝트들을 위한 유용한 시작점을 제공합니다.


주목할 만한 특징은 "simulation mode" 를 포함합니다. 유니티 에디터가 활성화되면, 이 모드는 애셋번들로 표시된( tagged ) 애셋들에 대한 요청을 프로젝트의 /Assets/ 폴더 내에 있는 원래 애셋으로 리디렉트( redirect )합니다. 이는 개발자로 하여금 애셋번들을 리빌드하지 않고도 프로젝트에서 작업할 수 있도록 해 줍니다.


애셋번들 관리자는 오픈소스 프로젝트이며, 여기에서 찾아볼 수 있습니다.


3.4. Loading AssetBundles


유니티 5 에서, 애셋번들은 네 개의 API 를 통해서 로드될 수 있습니다. 이 네 개의 API 들의 동작은 두 개의 조건에 의존해 달라집니다:


    1. 애셋번들이 LZMA 압축인가, LZ4 압축인가.
    2. 애셋번들이 로드되고 있는 플랫폼이 어디인가.


다음과 같은 API 들이 있습니다:




3.4.1. AssetBundle.LoadFromMemroyAsync


유니티는 이 API 를 사용하는 것을 추천하지 않습니다.


유니티 5.3.3 업데이트: 이 API 는 유니티 5.3.3 에서 이름이 변경되었습니다. 유니티 5.3.2( 및 이전 )에는, 이 API 가 AssetBundle.CreateFromMemory 로 알려져 있었습니다. 그것의 기능이 변경되지는 않았습니다.


AssetBundle.LoadFromMemoryAsync 는 관리되는 코드의 바이트 배열( byte[] in C# )에서 애셋번들을 로드합니다. 그것은 항상 소스 데이터를 관리되는 코드 바이트 배열에서 새롭게 할당된 연속된 네이티브 메모리 블록의 배열로 복사합니다. 만약 애셋번들이 LZMA 로 압축되었다면, 그것은 복사하는 동안 애셋번들을 압축해제합니다. 압축이 안 되어 있거나 LZ4 로 압축된 애셋번들은 말 그대로 복사됩니다.


이 API 에 의해 소비되는 메모리의 최대량은 적어도 애셋번들의 크기의 두 배입니다: 한 복사본은 API 에 의해 생성된 네이티브 메모리에 있고, 한 복사본은 API 에 넘겨진 관리되는 바이트 배열에 있습니다. 그러므로 이 API 를 통해 애셋번들로부터 로드된 애셋들은 메모리에 세 번 복사됩니다: 하나는 관리되는 코드 바이트 배열, 하나는 네이티브 메모리 복사본, 하나는 애셋 자체를 위해서 GPU 나 시스템 메모리에.


3.4.2. AssetBundle.LoadFromFile


유니티 5.3 업데이트: 이 API 는 유니티 5.3 에서 이름이 변경되었습니다. 유니티 5.2( 및 이전 )에서는 AssetBundle.CreateFromFile 로 알려져 있었습니다. 그것의 기능은 변경되지 않았습니다.


AssetBundle.LoadFromFile 은 매우 효율적인 API 이며, SD 카드나 하드 디스크와 같은 로컬 저장소에서 압축되지 않은 애셋번들을 로드하기 위한 의도로 만들어졌습니다. 만약 애셋번들이 압축되지 않았거나 LZ4 로 압축되었다면, 이 API 의 동작은 다음과 같습니다:


모바일 디바이스: 이 API 는 애셋번들의 헤더만을 로드하며, 데이터는 디스크에 남겨 둡니다. 애셋번들의 오브젝트는 로딩 메서드들이 호출되거나 그것들의 InstanceID 가 역참조될 때 요청에 의해( on-demand ) 로드될 것입니다. 이 시나리오에서는 과도하게 사용되는 메모리가 없습니다.


유니티 에디터: 이 API 는 마치 AssetBundle.LoadFromMemoryAsync 가 사용되거나 바이트들이 디스크에서 일어들여 지는 것처럼 전체 애셋번들을 메모리로 로드할 것입니다. 이 API 는 프로젝트가 유니티 에디터에서 프로우파일링되고 있는 동안에는 메모리 스파이크를 발생시킬 수 있습니다. 이는 디바이스 상에서의 성능에 영향을 미치지 않으며, 개선책을 취하기 전에 이 스파이크를 디바이스에서 다시 테스트해 보아야 합니다.


노트: 유니티 5.3 이전의 안드로이드 디바이스에서, 이 API 는 Streaming Assets 경로에서 애셋번들을 로드하려고 시도할 때 실패할 것입니다. 이는 그 경로의 내용이 압축된 .jar 파일 내부에 존재하기 때문입니다. 더 많은 세부사항에 대해서 알고자 한다면, AssetBundle usage patterns 챕터의 Distribution - shipped with project 섹션을 참고하십시오. 이 이슈는 유니티 5.4 에서 해결되었습니다. 유니티 5.4 이상에서 빌드된 게임에서는 이제 이 API 를 사용해 Streaming Asset 으로부터 애셋번들을 로드할 수 있습니다.


노트: AssetBundle.LoadFromFile 에 대한 호출은 LZMA 압축 애셋번들에 대해서는 항상 실패합니다.


3.4.3. WWW.LoadFromCacheOrDownload


WWW.LoadFromCacheOrDownload 는 원격 서버와 로컬 저장소에서 오브젝트를 로딩하기 위해서 유용한 API 입니다. 파일들은 file:// URL 을 사용해서 로컬 저장소로부터 로드될 수 있습니다. 만약 애셋번들이 유니티 캐시에 제출되었다면, 이 API 는 AssetBundle.LoadFromFile 과 정확히 같은 동작을 수행하게 됩니다.


만약 애셋번들이 아직 캐싱되지 않았다면, WWW.LoadFromCacheOrDownload 는 애셋번들을 소스로부터 읽어들일 것입니다. 만약 애셋번들이 압축되어 있다면, 그것은 워커 스레드( worker thread )를 사용하여 압축을 해제하고 그것을 캐시에 쓰게 됩니다. 그렇지 않다면, 그것은 워커 스레드를 통해 캐시로 바로 쓰여집니다.


일단 애셋번들이 캐싱되면, WWW.LoadFromCacheOrDownload 는 헤더 정보를 캐싱되고 압축해제된 애셋번들에서 로드합니다. 그리고 나서 이 API 는 AssetBundle.LoadFromFile 을 사용해 애셋번들을 로드하는 것과 동일한 동작을 수행합니다.


노트: 고정크기 버퍼를 통해 데이터가 압축해제되고 캐시에 쓰이는 동안, WWW 오브젝트는 애셋번들의 바이트의 전체 복사본을 네이티브 메모리에 유지합니다. 이 부가적인 복사본은 WWW.bytes 속성에 의해서 지속적으로 지원됩니다.


WWW 오브젝트 내에 애셋번들의 바이트를 캐싱하기 위한 메모리 오우버헤드 때문에, WWW.LoadFromCacheOrDownload 를 사용하는 개발자들은 자신들의 애셋번들을 작게 유지할 필요가 있습니다 - 거의 몇 메가 바이트 정도로. 또한 모바일 디바이스와 같은 제한된 메모리를 가진 플랫폼에서 작업하는 개발자들은 메모리 스파이크를 피하기 위해서 자신들의 코드가 한 번에 하나의 애셋번들만을 다운로드하도록 해야 합니다. 애셋번들 크기와 관련한 더 많은 논의를 원한다면, AssetBundle usage Patterns 챕터의 Asset assignment strategies 섹션을 참고하십시오.


노트: 이 API 에 대한 각각의 호출은 새로운 워커 스레드를 생성할 것입니다. 이 API 를 여러 번 호출할 때는 스레드가 너무 많이 생성되지 않도록 주의해야만 합니다. 만약 5 ~ 10 개 이상의 애셋번들이 다운로드되어야 한다면, 적은 개수의 애셋번들이 동시에 다운로드되도록 코드를 작성하는 것을 권장합니다.


3.4.4. AssetBundleDownloadHandler


유니티 5.3 에서 모바일 플랫폼을 위해 소개된 UnityWebRequest API 는 WWW API 를 대체할 더욱 유연한 대안을 제공합니다. UnityWebRequest 는 개발자로 하여금 유니티가 다운로드된 데이터를 어떻게 다룰지 정확하게 지정할 수 있게 합니다. 또한 개발자로 하여금 불필요한 메모리 사용량을 줄일 수 있도록 해 줍니다. UnityWebRequest 를 통해 애셋번들을 다운로드하는 가장 단순한 방법은 UnityWebRequest.GetAssetBundle API 를 호출하는 것입니다.


이 가이드의 목적을 볼 때 흥미로운 클래스는 DownloadHandlerAssetBundle 입니다. 다운로드 핸들러는 WWW.LoadFromCacheOrDownload 와 유사한 동작을 수행합니다. 그것은 워커 스레드를 사용해서 다운로드된 데이터를 고정 크기 버퍼에 스트리밍하고, 다운로드 핸들러의 구성에 따라 버퍼링된 데이터를 임시 저장소나 애셋번들 캐시에 스풀링합니다. LZMA 압축된 애셋번들은 다운로드 동안 압축해제되고 압축되지 않은 캐시로 저장됩니다.


이러한 모든 연산들은 네이티브 코드 상에서 수행되며, 관리되는 힙이 확장될 위험성을 제거해 줍니다. 더우기 이 다운로드 핸들러는 다운로드된 모드 바이트들에 대한 네이티브 코드 복사본을 유지하지 않습니다. 게다가 애셋번들을 다운로드하는 데 필요한 메모리 오우버헤드를 줄여줍니다.


다운로드가 완료되면, 다운로드 핸들러의 assetBundle 프라퍼티는 다운로드된 애셋번들에 대한 접근을 제공합니다. 마치 AssetBundle.LoadFromFile 이 다운로드된 애셋번들상에서 호출되는 것처럼 말이죠.


UnityWebRequest API 는 WWW.LoadFromCacheOrDownload 와 동일한 방식으로 캐싱을 지원하기도 합니다. 만약 캐싱 정보가 UnityWebRequest 오브젝트에 제공되고 요청된 애셋번들이 이미 유니티 캐시에 존재한다면, 애셋번들은 즉시 이용가능해지며 이 API 는 AssetBundle.LoadFromFile 과 동일하게 동작합니다.


노트: 유니티 애셋번들 캐시는 WWW.LoadFromCacheOrDownload 와 UnityWebRequest 사이에서 공유됩니다. 한 API 에 의해서 다운로드된 모든 애셋번들은 다른 API 를 통해서 사용할 수 있습니다.


노트: WWW 와는 다르게, UnityWebRequest 시스템은 내부 워커 스레드 풀과 내부 잡( job ) 시스템을 가지고 있으며, 이는 개발자가 동시에 너무 많은 번들을 다운로드할 수 없게 해 줍니다. 스레드 풀의 크기는 현재 사용자가 설정할 수 없습니다.


3.4.5. Recommendations


일반적으로, 가능하다면 AssetBundle.LoadFromFile 을 사용하십시오. 이 API 는 속도, 디스크 사용량, 런타임 메모리 사용량의 관점에서 가장 효율적입니다.


애셋번들을 다운로드하고 패치해야 하는 프로젝트를 위해서는, 유니티 5.3 이상의 버전을 사용하고 있다면 UnityWebRequest 를 사용하고 5.2 이하의 버전을 사용하고 있다면 WWW.LoadFromCacheOrDownload 를 사용하는 것을 강력히 권합니다. 다음 챕터의 Distribution 섹션에서 설명하듯이, it is possible to prime the AssetBundle Cache with Bundles include within a project's installer.


WWW.LoadFromCacheOrDownload 를 사용할 때는 프로젝트의 애셋번들이 프로젝트의 최대 메모리 예산보다 2 ~ 3% 정도 작은 상태로 유지되도록 하는 것을 추천합니다. 그래야 메모리 사용량 스파이크 때문에 애플리케이션이 종료되는 것을 막을 수 있습니다. 대부분의 프로젝트에서 애셋번들은 5 MB 를 넘어서서는 안되며, 1 ~ 2 개 이상의 애셋번들이 동시에 다운로드되어서는 안 됩니다.


WWW.LoadFromCacheOrDownload 나 UnityWebRequest 를 사용할 때는 애셋번들을 로드한 후에 다운로드 코드가 적절히 Dispose 를 호출하도록 해야 합니다. C# 의 using 문은 WWW 와 UnityWebRequest 를 안전하게 dispose 할 수 있는 가장 편리한 방법입니다.


규모가 큰 엔지니어링 팀을 위한 프로젝트와 단일 캐싱 이나 다운로딩 요구들을 위해서는 커스텀 다운로드가 필요합니다. 커스텀 다운로더를 작성하는 것은 사소한 엔지니어링 작업이 아닙니다. 그리고 모든 커스텀 다운로더는 AssetBundle.LoadFromFile 과 호환되도록 만들어져야만 합니다. 세부사항을 원한다면 다음 챕터의 Distribution 섹션을 참고하십시오.


3.5. Loading Assets From AssetBundles


UnityEngine.Object 는 AssetBundle 오브젝트에 있는 여러 API 를 사용해 애셋번들로부터 로드될 수 있습니다 : LoadAsset, LoadAllAssets, LoadAssetWithSubAssets. 이러한 모든 API 들은 비동기 버전을 가지고 있습니다 - Async 라는 접미어가 있습니다: LoadAssetAsync, LoadAllAssetsAsync, LoadAssetWithSubAssetsAsync.


동기 API 는 항상 비동기 API 보다 적어도 한 프레임 단위에서는 빠릅니다. 이는 특히 유니티 5.1 이전 버전에서는 사실입니다. 유니티 5.2 전에는 모든 비동기 API 들이 한 프레임에 거의 하나의 오브젝트만을 로드했스니다. 이는 LoadAllAssetsAsync 와 LoadAssetWithSubAssetAsync 가 관련 동기 API 들보다 심각하게 느렸음을 의미합니다. 이 동작은 유니티 5.2 에서 교정되었습니다. 비동기 로딩은 이제 자신의 시간 분할( time-slice ) 제한이 걸릴 때까지 한 프레임에 여러 개의 오브젝트를 로드합니다. 그것의 기반이 되는 기술적 요인과 시간 분할과 관련한 세부사항을 살펴보고자 한다면 아래의 Low-level loading details 를 참고하시기 바랍니다.


LoadAllAssets 는 독립적인 다수개의 UnityEngine.Object 들을 로드할 때 사용됩니다. 그것은 애셋번들 내의 대부분의( 혹은 모든 ) 오브젝트들이 로드될 필요가 있을 경우에 사용되야 합니다. 다른 두 API 와 비교해 봤을 때, LoadAllAssets 는 LoadAssets 를 개별적으로 호출했을 때 보다는 약간 빠릅니다. 그러므로 로드될 애셋의 개수가 많지만 한 번에 로드될 필요가 있는 개수가 애셋번들의 내용은 2/3 보다 적을 때는 애셋번들을 다수 개의 작은 번들로 분리하고 LoadAllAssets 를 호출할 것을 권합니다.


LoadAssetWithSubAssets 는 여러 개의 내포된 오브젝트를 포함하고 있는 복합 애셋을 로드해야 할 때 사용해야 합니다. 그러한 예로는 FBX 모델이 있는데, 거기에는 내포된 애니메이션이나 내부에 여러 개의 내포된 스프라이트를 포함하는 스프라이트 아틀라스를 포함하고 있을 수 있습니다. 만약 오브젝트들이 같은 애셋으로부터 로드될 필요가 있지만 애셋번들 내에 관련없는 다른 오브젝트들이 존재한다면, 이 API 를 사용하십시오.


다른 경우에는 LoadAsset 이나 LoadAssetAsync 를 사용하십시오.


3.5.1. Low-loevle loading details


UnityEngine.Object 로딩은 메인 스레드에서 수행됩니다: 오브젝트의 데이터는 워커 스레드에서 저장소로부터 읽혀들여집니다. 유니티 시스템의 스레드에 민감하지 않은 부분들( 스크립팅, 그래픽스 )을 건드리는 것들은 워커 스레드에서 변환됩니다. 예를 들어 VBO 는 메쉬로부터 생성되며, 텍스쳐들은 압축해제됩니다.


5.3 버전 전에는 오브젝트 로딩이 직렬적이며 오브젝트 로딩의 일부분은 메인 스레드에서만 수행되었습니다. 이는 "Integration" 이라 불렸습니다. 워커 스레드가 오브젝트 데이터를 로딩하는 것을 마친 후에, 그것은 새롭게 로드된 오브젝트를 메인 스레드에서 통합하기 위해 중지되었으며, 메인 스레드 통합이 완료될 때까지 ( 다음 오브젝트를 로딩하지 않고 ) 중지된 상태로 남아 있었습니다.


5.3 버전부터는 오브젝트 로딩은 병행처리됩니다. 여러 개의 오브젝트들이 역직렬화되며, 워커 스레드 상에서 처리되고 통합됩니다. 오브젝트가 로딩을 마쳤을 때, 그것의 Awake 콜백이 호출되며 오브젝트는 다음 프레임 동안에 유니티 엔진의 나머지 부분에 대해 이용 가능하게 됩니다.


동기화된 AssetBundle.Load 메서드는 오브젝트 로딩이 완료될 때까지 메인 스레드를 중단시킬 것입니다. 5.3 버전 전에는 비동기 AssetBundle.LoadAsync 메서드는 오브젝트를 메인 스레드에서 통합하기 전까지 메인 스레드를 중단시키지 않을 것입니다. They will also time-slice Object loading so that Object integration does not occupy more than a certain number of milliseconds of frame time. 얼마만큼의 시간이 설정되느냐는 Application.backgroundLoadingProperty 라는 프라퍼티에 의해 설정됩니다.


    • ThreadProirity.High: 프레임당 최대 50 밀리세컨드.
    • ThreadPriority.Normal: 프레임당 최대 10 밀리세컨드.
    • ThreadPriotity.BelowNormal: 프레임당 최대 4 밀리세컨드.
    • ThreadPriority.Low: 프레임당 최대 2 밀리세컨드.


유니티 5.1 전 버전에서, 비동기 API 들은 프레임당 한 오브젝트만 통합했을 것입니다. 이는 버그로 간주되었으며, 유니티 5.2 에서 해결되었습니다. 유니티 5.2 부터는 오브젝트 로딩을 위한 프레임 타임 제한에 도달할 때까지 여러 개의 오브젝트가 로드될 것입니다. AssetBundle.LoadAsync 는 ( 모든 요소가 동일하다는 가정하에서 볼 때 ) 동기 API 보다는 완료되는 시간이 길 것입니다. 왜냐하면 LoadAsync 호출을 제출하는 것과 오브젝트가 엔진에 대해 이용가능한 상태가 되는 것 사이에 최소 한 프레임의 지연이 존재하기 때문입니다.


실제 오브젝트들과 애셋들을 가지고 테스트해 보면 다른 결과가 나옵니다. 5.2 전에는 특정한 큰 텍스쳐를 로우엔드 디바이스에서 로드하면, 동기 메서드를 사용했을 때 7 ms 가 나오고 비동기 메서드를 사용했을 때 70 ms 가 나왔습니다. 5.2 이후에는 그 차이가 0 에 가까워졌습니다.


3.5.2. AssetBundle dependencies


유니티 5 의 애셋번들 시스테멩서 애셋번들 사이의 종속성은 두 개의 API 를 통해 자동적으로 트래킹되는데, 이는 런타임 환경과 관련이 있습니다. 유니티 에디터에서는 AssetBundle 종속성이 AssetDatabase API 를 통해 질의될 수 있습니다. 애셋번들 할당과 종속성은 AssetImporter API 를 통해서 접근되거나 변경될 수 있습니다. 런타임에는 유니티가 애셋번들 빌드 동안에 생성된 종속성 정보를 로드할 수 있는 선택적인 API 를 제공합니다. 이는 ScriptableObject 기반의 AssetBundleManifest API 입니다.


부모 애셋번들의 UnityEngine.Object 들이 다른 애셋번들의 UnityEngine.Object 들에 대한 하나 이상의 참조를 가질 때, 한 애셋 번들은 다른 애셋번들에 대해 "종속적"입니다. 오브젝트간 참조에 대한 더 많은 정보를 원한다면, Assets, Objects and Serialization 기사의 Inter-Object references 섹션을 참고하십시오.


그 기사의 Serialization and instances 섹션에서 기술햇듯이, 애셋번들은 애셋번들에 포함되어 있는 개별 오브젝트의 파일 GUID 와 로컬 ID 에 의해 식별되는 소스 데이터를 위한 소스로서 기능합니다


오브젝느는 인스턴스 ID 가 처음 역참조될 때 로드되기 때문에, 그리고 그것의 애셋번들이 로드될 때 오브젝트는 유효한 인스턴스 ID 를 할당받기 때문에, 애셋번들이 로드되는 순서는 중요치 않습니다. 대신에 오브젝트 자체를 로드하기 전에 오브젝트의 종속성을 포함하는 모든 애셋번들을 로드하는 것은 중요합니다. 유니티는 부모 애셋번들이 로드될 때 자식 애셋번들을 자동으로 로드해 주지 않을 것입니다.


예:


머티리얼 A 가 텍스쳐 B 를 참조하고 있다고 가정합시다. 머티리얼 A 는 AssetBundle 1 에 패키징되어 있고, 텍스쳐 B 는 AssetBundle 2 에 패키징되어 있습니다.




이 경우, Asset Bundle 2 는 Asset Bundle 1 으로부터 머티리얼 A 를 로딩하기 전에 로드되어야만 합니다.


이는 Asset Bundle 2 가 Asset Bundle 1  전에 로드되어야만 한다든가 그 텍스쳐 B 가 Asset Bundle 2 로부터 명시적으로 로드되어야만 한다든가 하는 것을 암시하지는 않습니다. Asset Bundle 1 로부터 머티리얼 A 를 로딩하는 것보다 Asset Bundle 2 를 먼저 로드하기만 하면 충분합니다.


유니티는 Asset Bundle 1 이 로드될 때 자동으로 Asset Bundle 2 를 로드하지 않을 것입니다. 이는 스크립트를 통해 명시적으로 수행되어야만 합니다. Asset Bundle 1 과 2 를 로드하기 위해서 사용되는 특정 애셋번들 API 는 중요하지 않습니다. WWW.LoadFromCacheOrDownload 를 통해 로드된 애셋번들은 AssetBundle.LoadFromFile 이나 AssetBundle.LoadFromMemoryAsync 를 통해 로드된 애셋번들과 자유롭게 혼용될 수 있습니다.


3.5.3. AssetBundle manifest


BuildPipeline.BuildAssetBundles API 를 통해 애셋번들 빌드 파이프라인을 실행할 때, 유니티는 애셋번들의 종속성 정보를 포함하는 오브젝트를 직렬화합니다. 이 데이터는 개별 애셋번들에 저장되며, 이는 AssetBundleManifest 타입의 오브젝트를 포함합니다.


이 애셋은 애셋번들이 빌드된 부모 디렉토리와 같은 이름을 가지고 애셋번들 내에 저장될 것입니다. 만약 프로젝트가 그것의 애셋번들을 (projectroot)/build/Client/ 라는 폴더에 빌드한다면, 매니페이스를 포함하는 애셋번들은 (projectroot)/build/Client/Client.manifest 로 저장될 것입니다.


매니페스트를 포함하는 애셋번들은 다른 애셋번들들처럼 로드되거나 캐싱되거나 언로드될 수 있습니다.


AssetBundleManifest 오브젝트는 그 자체로 GetAllAssetBundles 라는 API 를 제공해 매니페스트와 함께 빌드된 모든 애셋번들들을 리스팅할 수 있도록 합니다. 그리고 특정 애셋번들의 종속성을 질의하기 위한 두 개의 메서드를 제공합니다.


AssetBundleManifest.GetAllDependencies 는 애셋번들의 종속성을 모두 반환합니다. 이는 애셋번들의 계층구조상의 모든 자손들의 종속성을 포함합니다.


AssetBundleManifest.GetDirectDependencies 는 애셋번들의 바로 아래 자손들의 종속성만을 반환합니다.


이 API 들은 모두 문자열 배열을 할당한다는 점에 주의하시기 바랍니다. 자주 사용하지는 마십시오. 그리고 애플리케이션 생명주기의 성능이 중요한 시점에는 사용하지 마십시오.


3.5.4. Recommandations


애플리케이션에서 성능이 중요한 부분에 도달하기 전에 필요한 오브젝트를 최대한 많이 로드하는 것이 좋습니다. 예를 들어 메인 게임 레벨이나 월드에 들어 가기 전에 로드하는 것이 좋습니다. 이는 모바일 플랫폼에서 특히 중요합니다. 이 환경에서 로컬 저장소에 대한 접근은 느리며 플레이를 하는 동안에 오브젝트를 마구 로드하고 언로드하는 것은 가비지 콜렉팅을 발생시킬 수 있습니다.


애플리케이션이 상호작용을 하는 동안에 오브젝트들을 로드하고 언로드해야만 하는 프로젝트의 경우, 오브젝트와 애셋번들을 언로드하는 것에 대한 더 많은 정보를 원한다면 AssetBundle usgae pattern 기사의 Managing loaded assets 섹션을 참고하십시오.

원문 : Assets, Objects and Serialization.

주의 : 번역이 개판이므로 원문을 참조하세요.

주의 : 허락받고 번역한 것이 아니므로 언제든 내려갈 수 있습니다.



Assets, Objects and Serialization


확인 완료한 버전 : 5.4 - 난이도 : 고급


이 기사는 유니티 5 의 애셋, 리소스, 그리고 리소스 관리를 다루는 기사 시리즈의 두 번째 챕터입니다.


이 챕터는 유니티의 직렬화 시스템의 내부 구현과 유니티 에디터와 런타임에서 서로 다른 오브젝트 간의 빠른 참조를 유지하는 방법에 대해서 다룹니다. 오브젝트와 애셋의 기술적인 차이에 대해서도 논의합니다. 여기에서 다루는 주제들은 유니티에서 애셋들을 효율적으로 로드하고 언로드하는 방법을 이해하기 위해서 필수적입니다. 적절한 애셋 관리는 로딩 시간을 짧게 유지하고 메모리 사용을 적게 하기 위해서 중요합니다.


1.1. Inside Assets and Objects


유니티에서 데이터를 적절하게 관리하기 위한 방법을 이해하기 위해서는, 유니티가 데이터를 식별하고 직렬화하는 방법을 이해하는 것이 중요합니다. 첫 번째 중요 지점은 애셋과 UnityEngine.Object 의 차이점입니다.


애셋은 디스크 상의 파일이며, 유니티 프로젝트의 Assets 폴더에 저장됩니다. 예를 들어, 텍스쳐 파일들, 머티리얼 파일들, FBX 파일들은 모두 애셋입니다. 어떤 애셋들은 머티리얼들처럼 유니티 포맷( formats native to Unity )들로 된 데이터를 포함합니다. FBX 파일과 같은 다른 애셋들은 자체 포맷( native formats )들로 처리될 필요가 있습니다.


대문자 'O' 로 시작하는 UnityEngine.Object( 혹은 Object ) 들은 리소스의 특정 인스턴스를 집합적으로 기술하는 직렬화된( serialized ) 데이터의 집합입니다. 이는 유니티 엔진이 사용하는 어떤 리소스 타입이든 될 수 있습니다. 그 예로는 메쉬( mesh ), 스프라이트( sprite ), 오디오 클립( AudioClip ), 애니메이션 클립( AnimationClip ) 등이 있습니다. 모든 오브젝트들은 UnityEngine.Object 기저 클래스의 서브클래스입니다.


대부분의 오브젝트 타입들은 내장 타입( built-in type )인데, 두 개의 특별한 타입들이 있습니다.


    1. ScriptableObject 는 개발자가 자신만의 데이터 타입을 정의할 수 있도록 해 주는 편리한 시스템을 제공합니다. 이 타입들은 유니티에 의해 자연스럽게 직렬화되고 역직렬화( deserialized )되며, 유니티 에디터의 인스펙터 윈도우에서 다뤄집니다.
    2. MonoBehaviourMonoScript 를 링크하는 래퍼( wrapper )를 제공합니다. MonoScript 는 유니티가 특정 어셈블리( assembly )나 네임 스페이스( namespace ) 내의 특정 스크립팅 클래스에 대한 참조를 유지하기 위해서 사용하는 내부 데이터 타입입니다. MonoScript 는 어떠한 실제 실행 코드도 포함하지 않습니다.


애셋과 오브젝트 사이에는 one-to-many 관계가 성립합니다; 즉 주어진 애셋 파일은 하나 이상의 오브젝트를 포함합니다.


1.2. Inter-Object References


모든 UnityEngine.Object 는 다른 UnityEngine.Object 들에 대한 참조를 가질 수 있습니다. 이 다른 오브젝트들은 같은 애셋 파일에 있을 수도 있고 다른 애셋 파일에 있을 수도 있습니다. 예를 들어 머티리얼 오브젝트는 항상 하나 이상의 텍스쳐 오브젝트에 대한 참조를 가집니다. 이 텍스쳐 오브젝트들은 일반적으로 ( PNG 나 JPG 같은 ) 하나 이상의 텍스쳐 애셋 파일들로부터 임포트( import )됩니다.


직렬화 시에, 이 참조들은 두 개의 개별 데이터 조각으로 구성됩니다: File GUIDLocal ID.  파일 GUID 는 대상 리소스가 저장되어 있는 애셋 파일을 식별합니다. 지역적으로 유일한 로컬 ID 는 애셋 파일 내의 각 오브젝트들을 식별합니다. 왜냐하면 애셋 파일은 여러 개의 오브젝트들을 포함할 수 있기 때문입니다.


파일 GUID 는 .meta 파일에 저장됩니다. 이 .meta 파일들은 애셋이 처음 임포트될 때 생성되며 애셋과 같은 디렉토리에 저장됩니다.


위의 식별자와 참조 시스템은 텍스트 에디터에서 확인할 수 있습니다: 새 유니티 프로젝트를 생성하고 그것의 에디터 셋팅을 Visible Meta Files 를 노출하고 애셋을 텍스트로 직렬화하도록 합니다. 그 프로젝트에서 머티리얼을 생성하고 텍스쳐를 임포트합니다. 그리고 씬에 있는 큐브에 머티리얼을 할당하고 씬을 저장합니다.


텍스트 에디터를 사용해, 위의 머티리얼과 연관된 .meta 파일을 엽니다. "guid" 라 표시된 라인은 파일의 거의 최상단에 보일 것입니다. 이 라인은 머티리얼 애셋의 파일 GUID 를 정의합니다. 로컬 ID 를 찾으려면, 텍스트 에디터에서 머티리얼 파일을 엽니다. 머티리얼 오브젝트의 정의는 다음과 같이 보일 것입니다:


--- !u!21 &2100000

Material:

 serializedVersion: 3

 ... more data ...


위의 예제에서, & 뒤에 나오는 숫자가 머티리얼의 로컬 ID 입니다. 만약 머티리얼 오브젝트가 파일 GUID "abcdefg" 에 의해서 식별되는 애셋 내부에 존재하면, 그 머티리얼 오브젝트는 파일 GUID "abcedfg" 와 로컬 ID "2100000" 의 조합에 의해 유일하게 식별될 것입니다.


1.3. Why file GUIDs and local IDs?



왜 유니티에서는 파일 GUID 시스템과 로컬 ID 시스템이 필요할까요? 그 대답은 신뢰성( robustness ) 및 유연하고 플랫폼 독립적인 워크플로우를 제공하기 위함입니다.


파일 GUID 는 파일의 특정 위치에 대한 추상화를 제공합니다. 특정 파일 GUID 가 특정 파일과 연관되어 있는 한, 그 파일의 디스크 상의 위치는 중요하지 않습니다. 그 파일은 파일을 참조하는 모든 오브젝트들을 갱신하지 않고도 자유롭게 이동될 수 있습니다.


애셋 파일은 다수 개의 UnityEngine.Object 리소스들을 포함할 수 있기 때문에( 혹은 임포트를 통해 생성할 수 있기 때문에 ), 로컬 ID 는 다른 오브젝트들과 명확하게 구분될 수 있을 것을 요구받습니다.


만약 애셋 파일과 연관된 파일 GUID 가 사라진다면, 그 애셋 파일 내부의 모든 오브젝트에 대한 참조도 사라질 것입니다. 이것이 .meta 파일이 그것이 연관된 애셋 파일과 같은 파일 이름을 가지고 같은 폴더에 저장되어야만 하는 이유입니다. 유니티는 제거되거나 위치가 잘못된 .meta 파일들을 자동으로 재생성한다는 점에 주의하십시오.


유니티 에디터는 알려진 파일 GUID 와 파일 경로에 대한 맵을 가지고 있습니다. 맵 엔트리는 애셋이 로드되거나 임포트될 때마다 기록됩니다. 맵 엔트리는 애셋의 특정 경로를 애셋의 파일 GUID 에 링크합니다. 만약 유니티 에디터가 .meta 파일이 사라졌지만 애셋의 경로가 변경되지 않았을 때 열리면, 에디터는 애셋이 같은 파일 GUID 를 유지하도록 해 줍니다.


만약 .meta 파일이 유니티 에디터가 닫히고 있을 때 사라지거나 .meta 파일은 그대로 두고 애셋 파일만 옮기면, 그 애셋 안의 모든 오브젝트에 대한 참조가 깨집니다.


1.4. Composite Assets and Importers


[ Inside Assets and Objects ] 에서 언급했듯이, non-native 애셋 타입들은 유니티에 임포트되어야만 합니다. 이는 애셋 임포터를 통해서 수행됩니다. 이 임포터들은 보통 자동으로 실행되지만, 그것들은 AssetImporter API 와 그것의 서브클래스를 통해 스크립트에 노출될 수도 있습니다. 예를 들어 TextureImporter API 는 PNG 나 JPG 와 같은 개별 텍스쳐 애셋을 임포트할 때 사용할 설정들에 대한 접근을 제공합니다.


임포트 절차의 결과는 하나 이상의 UnityEngine.Object 입니다. 이것들은 유니티 에디터에서 부모 애셋 내부의 다중 서브 애셋 형태로 가시화됩니다. 예를 들어 스프라이트 아틀라스로서 임포트된 텍스쳐 애셋 내부에 포함된 다중 스프라이트들이 있습니다. 각 오브젝트들은 같은 애셋 파일 내에 저장된 소스 데이터와 같은 파일 GUID 를 공유할 것입니다. 그것들은 임포트된 텍스쳐 애셋 내에서 로컬 ID 를 통해 구분될 것입니다.


임포트 절차는 소스 애셋을 유니티 에디터에서 선택한 대상 플랫폼에 맞는 포맷들로 변환합니다. 임포트 절차는 텍스쳐 압축과 같은 무거운 연산을 포함할 수 있습니다. 유니티 에디터가 열릴 때마다 임포트 절차가 수행되는 것은 매우 비효율적입니다.


대신에, 애셋 임포팅의 결과들은 Library 폴더로 캐싱됩니다. 특히, 임포트 절차의 결과는 폴더에 저장되는데, 폴더의 이름은 애셋 파일 GUID 의 처음 두 숫자입니다. 이 폴더는 LIbrary/metadata/ 폴더 내부에 저장됩니다. 개별 오브젝트들은 하나의 바이너리 파일로 직렬화되는데, 그것은 애셋 파일 GUID 와 동일한 이름을 가지게 됩니다.


이는 실제적으로 non-native 애셋들뿐만 아니라 모든 애셋에 대해 사실입니다. 그러나 native 애셋들은 장황한 변환 절차나 재직렬화를 요구하지 않습니다.


1.5. Serialization and Instances


파일 GUID 와 로컬 ID 가 신뢰성있기는 하지만, GUID 비교는 느리며 실시간에 좀 더 성능이 좋은 시스템이 필요합니다. 유니티는 내부적으로 파일 GUID 와 로컬 ID 를 단순한 정수로 변환하는 캐시를 유지합니다. 이 캐시는 싱글 세션에서만 유일합니다. 이들은 인스턴스 ID 라 불립니다. 그리고 새로운 오브젝트가 캐쉬에 등록될 때 단순한 점진적으로 증가하는 순서로 할당됩니다.


그 캐쉬는 주어진 인스턴스 ID( 오브젝트의 소스 데이터의 위치를 정의하는 파일 GUID 와 로컬 ID ) 와 메모리 상의 오브젝트 인스턴스 사이의 매핑을 유지합니다. 이는 UnityEngine.Object 들이 서로에 대한 참조를 신뢰성있게 유지할 수 있도록 해 줍니다. 인스턴스 ID 참조에 대한 resolving 은 인스턴스 ID 에 의해 표현되는 로드된 오브젝트를 빠르게 반환할 수 있습니다. 만약 대상 오브젝트가 아직 로드되지 않았다면, 파일 GUID 와 로컬 ID 는 오브젝트의 소스 데이터에 대해 resolve 될 수 있으며, 그 후에 유니티는 오브젝트를 제때( just-in-time ) 로드할 수 있습니다.


시작시에, 프로젝트에 내장된 모든 오브젝트( 예를 들어 씬에서 참조되는 )와 Resources 폴더에 포함된 모든 오브젝트를 위한 데이터를 사용해 인스턴스 ID 캐시가 초기화됩니다. 런타임에 새로운 애셋이 임포트되거나 애셋 번들로부터 오브젝트가 로드될 때 새로운 엔트리가 캐쉬에 추가됩니다. 인스턴스 ID 엔트리는 오브젝트가 무효화될( stale ) 때만 캐쉬에서 제거될 것입니다. 이는 특정 파일 GUID 와 로컬 ID 에 대한 애셋번들이 언로드될 때 발생합니다.


애셋 번들을 언로딩이 인스턴스 ID 를 무효화할 때, 메모리 보존을 위해 인스턴스 ID 와 그것의 파일 GUID 및 로컬 ID 사이의 매핑이 제거됩니다. 만약 애셋 번들이 다시 로드되면, 새로운 인스턴스 ID 가 다시 로드된 애셋 번들로부터 로드된 오브젝트를 위해서 생성될 것입니다.


애셋 번들을 언로드하는 것의 영향에 대한 더 깊은 논의를 원한다면, AssetBundle Usage Patterns 기사의 Managing Loaded Assets 섹션을 참조하십시오.


특정 플랫폼에서의 특정 이벤트는 오브젝트를 out of memory 상태로 이끌 수 있습니다. 예를 들어 앱이 중단되면( suspended ), iOS 상의 그래픽스 메모리로부터 그래피컬 애셋들이 언로드될 수 있습니다. 만약 이 오브젝트들이 언로드된 애셋 번들로부터 만들어진 것이라면, 유니티는 그 오브젝트를 위해 소스 데이터를 다시 로드하는 것이 불가능할 것입니다. 이러한 오브젝트들에 대한 현존하는 참조들도 무효화될 것입니다. 앞의 예에서, 안 보이는( 없어진 ) 메쉬나 마젠타( 없어진 ) 텍스쳐 & 머티리얼을 가진 것처럼 오브젝트가 렌더링 될 것입니다.


구현 노트 : 런타임에 위의 컨트롤 플로우는 문자 그대로 정확한 것은 아닙니다. 파일 GUID 와 Local ID 를 런타임에 비교하는 것은 무거운 로딩 연산 동안에는 충분히 효율적이지 못할 것입니다. 유니티 프로젝트에서 빌드를 할 때, 파일 GUID 와 Local ID 는 결정론적으로( deterministically ) 더 단순한 포맷으로 매핑됩니다. 그러나 그 개념은 동일하게 남아 있으며, 파일 GUID 와 로컬 ID 항에 대한 생각은 런타임 동안에 유용한 비유( analogy )로 남아 있게 됩니다.


이것은 애셋 파일 GUID 가 런타임에 질의될( queried ) 수 없는 이유이기도 합니다.


1.6. MonoScript


MonoBehaviour 가 MonoScript 에 대한 참조를 가지고 있고, MonoScript 는 단순히 특정 스크립트 클래스를 배치하기 위해서 필요한 정보만을 유지한다는 것을 이해하는 것은 중요합니다. 어떠한 유형의 오브젝트라도 스크립트 클래스의 실행 코드를 포함하지는 않습니다.


MonoScript 는 세 가지 문자열을 포함합니다: 어셈블리 이름, 클래스 이름, 네임스페이스.


프로젝트를 빌드할 때, 유니티는 모든 loose script file 을 Assets 폴더에서 수집해서 그것들을 모노 어셈블리로 컴파일합니다. 특히, 유니티는 Assets 폴더 내에서 사용된 각각의 다른 언어들을 위한 어셈블리를 빌드합니다. 또한 Assets/Plugins 폴더에 포함된 스크립트를 위한 독립된 어셈블리를 빌드합니다. Plugins 서브 폴더 외부의 C# 스크립트들은 Assembly-CSharp.dll 에 배치됩니다. Plugins 서브 폴더 내부의 스크립트들은 Assembly-CSharp-firstPass.dll 에 배치되는 식입니다.


( 미리 빌드된 어셈블리 DLL 들과 함께 ) 이 어셈블리들은 유니티 애플리케이션의 최종 빌드에 포함됩니다. 그것들은 MonoScript 가 참조하는 어셈블리이기도 합니다. 다른 리소스들과는 다르게, 유니티 애플리케이션에 포함된 모든 어셈블리들은 애플리케이션이 처음 시작될 때 로드됩니다.


이 MonoScript 오브젝트는 애셋번들( 혹은 씬 혹은 프리팹 )이 내부에 있는 MonoBehaviour 컴포넌트들 내의 어떠한 실행 코드도 포함하고 있지 않은 이유입니다. 이는 서로 다른 MonoBehaviour 들이 특정 공유 클래스나 심지어는 다른 애셋 번들에 존재하는 MonoBehaviour 들을 참조할 수 있도록 해 줍니다.


1.7. Resource LifeCycle


UnityEngine.Object 들은 특정 시점에 메모리에 로드되거나 메모리로부터 언로드됩니다. 로딩 시간을 줄이고 애플리케이션의 메모리 사용량을 줄이기 위해서는, UnityEngine.Object 들의 리소스 생명 주기에 대해서 이해하는 것이 중요합니다.


UnityEngine.Object 를 로드하는 두 가지 방법이 있습니다: 오브젝트는 자동으로 혹은 명시적으로. 역참조되고( dereferenced ) 있으며 현재 메모리에 로드되지 않았으며 오브젝트 소스 데이터가 정확한 위치에 있는 오브젝트에 인스턴스 ID 가 매핑되었을 때 자동으로 로드됩니다. 오브젝트는 그것들을 생성하거나 리소스 로딩 API( 예를 들어 AssetBundle.LoadAsset ) 를 호출함을써 스크립트를 통해 명시적으로 로드될 수 있습니다.


오브젝트가 로드될 때, 유니티는 각 참조의 파일 GUID 와 로컬 ID 를 인스턴스 ID 로 변환함으로써 모든 참조를 resolve 하려 시도합니다.


두 가지 조건만 만족한다면, 오브젝트는 자신의 인스턴스 ID 가 처음으로 역참조될 때 요구에 의해( on-demand ) 로드될 것입니다:


    1. 인스턴스 ID 가 현재 로드되지 않은 오브젝트를 참조할 때.
    2. 인스턴스 ID 가 캐시에 등록된 올바른 파일 GUID 와 로컬 ID 를 가질 때.


이는 일반적으로 참조가 스스로 로드되고 resolve 된 후에 매우 짧은 시간에 발생합니다.


만약 파일 GUID 와 로컬 ID 가 인스턴스 ID 를 가지고 있지 않거나, 언로드된 오브젝트를 가진 인스턴스 ID 가 유효하지 않은 파일 GUID 와 로컬ID 를 참조한다면, 그 참조는 보존되고 실제 오브젝트는 로드되지 않을 것입니다. 이는 유니티에서 "(Missing)" 참조라고 나옵니다. 실행중인 애플리케이션이나 씬뷰에서는 "(Missing)" 참조가 그것들의 유형에 따라 다른 방식으로 가시화될 것입니다: 메쉬들은 비가시화 상태가 되고, 텍스쳐들은 마젠타로 나타나는 식입니다.


오브젝트들은 세 가지 특정 시나리오에서 언로드됩니다:


    1. 오브젝트들은 사용되지 않는 애셋들을 클린업할 때 자동으로 언로드됩니다. 이 절차는 씬들이 파괴될 때( Application.LoadLevel API 를 non-additive 방식으로 호출할 때 )나 스크립트에서 Resources.UnloadUnusedAssets API 를 호출할 때 자동으로 발동합니다. 이 절차는 참조가 없는( unreferenced ) 오브젝트들만을 언로드합니다: Mono 변수가 그 오브젝트에 대한 참조를 가지고 있지 않거나 그 오브젝트에 대한 참조를 가진 살아 있는 오브젝트가 하나도 없을 때만 오브젝트가 언로드될 것입니다.
    2. Resources 폴더로부터 생성된 오브젝트들은 Resources.UnloadAsset API 를 호출함으로써 명시적으로 언로드될 수 있습니다. 이러한 오브젝트들의 인스턴스 ID 는 유효한 상태로 유지되며, 여전히 유효한 파일 GUID 와 로컬 ID 엔트리를 포함할 것입니다. 어떤 Mono 변수나 다른 오브젝트가 Resources.UnloadAsset 을 사용해 언로드된 오브젝트에 대한 참조를 가지고 있다면, 그 오브젝트는 살아 있는 참조가 역참조되자 마자 다시 로드될 것입니다.
    3. 애셋번들로부터 생성된 오브젝트들은 AssetBundle.Unload(true) API 를 호출할 때 자동으로 즉시 언로드됩니다. 이는 오븢게트의 InstanceID 의 파일 GUID 와 로컬 ID 참조를 무효화하며, 언로드된 오브젝트에 대한 살아 있는 모든 참조들은 "(Missing)" 참조가 될 것입니다. C# 스크립트에서, 언로드된 오브젝트에 대한 메서드나 프라퍼티에 접근하는 것은 NullReferenceException 을 생성하게 될 것입니다.


AssetBundle.Unload(false) 가 호출되면, 언로드된 애셋번들로부터 생성된 살아 있는 오브젝트들은 파괴되지 않을 것입니다. 하지만 유니티는 그것들의 인스턴스 ID 의 파일 GUID 와 로컬 ID 참조를 무효화시킬 것입니다. 만약 나중에 오브젝트가 메모리에서 언로드되고 언로드된 오브젝트에 대한 살아 있는 참조들이 유지되고 있다면, 이 오브젝트들을 유니티가 다시 로드하는 것은 불가능할 것입니다.


1.8. Loading Large Hierarchies


유니티 GameObject 의 계층을 직렬화할 때( 예를 들어 프리팹을 직렬화할 때 ), 전체 계층이 완전히 직렬화된다는 것을 기억하는 것이 중요합니다. 즉, 계층 내부의 모든 GameObject 와 Component 들이 개별적으로 직렬화된 데이터 내에 표현된다는 것입니다. 이는 GameObject 의 계층을 로드하고 인스턴스화하는데 필요한 시간에 흥미로운 영향을 미칩니다.


GameObject 계층을 생성할 때, CPU 시간이 몇 가지 방식으로 소비됩니다:


    1. 소스 데이터를 읽는 시간( 저장소로부터, 다른 GameObject 로부터 등 ).
    2. 새로운 Transform 사이에서 부모 자식 관계를 설정하는 시간.
    3. GameObject 와 Component 를 인스턴스화하는 시간.
    4. GameObject 와 Component 를 깨우는( awaken ) 시간.


나머지 세 비용은 일반적으로 계층이 현존하는 계층으로부터 복사되느냐 저장소( 예를 들어 애셋번들 )에서 로드되느냐와 관계없이 일정합니다. 그러나 소스 데이터를 읽는 비용은 계층에 직렬화된 Component 및 GameObject 의 개수에 따라 선형적으로 증가하며, 이는 데이터 소스의 속도와 곱해집니다.


현재 모든 플랫폼에서, 저장소 디바이스에서 로드하는 것보다는 메모리 어딘가에서 데이터를 읽어 들이는 것이 훨씬 빠릅니다. 더우기, 이용가능한 저장소 매체의 성능 특성은 각 플랫폼에서 매우 다양합니다 -- 데스크탑 PC 는 모바일 디바이스보다 훨씬 빠르게 디스크에서 로드합니다.


그러므로 느린 저장소를 가진 플랫폼에서 프리팹을 로드할 때, 저장소로부터 프리팹의 직렬화된 데이터를 읽는 비용은 프리팹을 인스턴스화하는 비용을 급격하게 넘어 갈 수 있습니다. 즉, 로딩 연산의 비용은 스토리지 I/O 시간에 의해 결정됩니다.


이전에 언급했듯이, monolithic prefab 을 직렬화할 때, 각 GameObject 와 Component 의 데이터는 개별적으로 직렬화됩니다 - 심지어 데이터가 중복되어 있더라도 그렇습니다. 30 개의 동일한 요소를 가진 UI 스크린은 동일한 요소를 30 번 직렬화할 것입니다. 이는 많은 바이너리 데이터 덩어리를 생성합니다. At load time, the data for all of the GameObjects and Components on each one of those thirty duplicate elements must be read from disk before being transferred to the newly-instantiated Object. 이는 파일 읽기 시간이며, 큰 프리팹을 인스턴싱하는 비용의 대부분을 차지합니다.


유니티가 내포된 프리팹( nested prefabs )을 지원하기 전까지는, 극단적으로 큰 GameObject 계층을 인스턴스화하는 프로젝트들은유니티의 직렬화 및 프리팹 시스템에 완전히 의존하기보다는,  재사용되는 요소들을 개별 프리팹으로 쪼개고 런타임에 그것을 인스턴스화함으로써 그들의 큰 프리팹의 로딩 비용을 많이 감소시킬 수 있었습니다.


더우기, 프리팹이나 GameObject 계층이 일단 생성되면, 새로운 복사본을 저장소에서 로드하는 것보다 현존하는 계층을 복사하는 것이 더 빠릅니다.


유니티 5.4 노트: 유니티 5.4 는 메모리에서 transform 에 대한 표현을 수정했습니다. 각 root transform 의 전체 자식 계층은 작고 연속적인 메모리 영역에 저장됩니다. 다른 계층으로 reparent 되는 새로운 GameObject 를 인스턴스화할 때는, parent 인자를 허용하는 GameObject.Instantiate 오우버로드( overloads ) 메서드를 사용하는 것을 골려하십시오.


이 오우버로드 메서드를 사용하면 새로운 GameObject 를 위한 root transform 계층을 할당하는 것을 피할 수 있습니다. 테스트를 해 봤을 때, 이것은 인스턴스화 연산을 위해 요구되는 시간을 5 ~ 10 % 정도 빠르게 만들어 줬습니다.


-- 각주 생략

원문 : Character Animation: Skeletons and Inverse Kinematics

주의 : 번역이 개판이므로 이상하면 원문을 참조하십시오.

주의 : 허락받고 번역한 것이 아니므로 언제든 내려갈 수 있습니다.



Introduction



자! 당신은 고딕 성을 만들었다 - 이제 영웅이 게임 안으로 달려 들어가 성벽을 방어할 시간이다. 당신의 게임 엔진은 스켈레톤과 역운동학( IK, Inverse Kinematics )라 불리는 애니메이션 시스템, 그리고 제어할 수 있는 복잡한 계층구조 설정을 지원한다. 당신은 그것들을 모두 시도해 보고 싶은 갈망을 가지고 있다. 훌륭하다! 그러나 당신이 이전에 스켈레톤을 써 본적이 없거나 관절이 있는 모델에 IK 를 적용해 본적이 없다면, 당신은 충격에 빠질 것이다. 일부는 당신이 좋아하게 될 것이고, 일부는 그렇지 않을 것이다... 적어도 처음에는 그럴 것이다.


이 문서는, 역운동학과 애니메이션되는 캐릭터들을 움직이기 위한 top-down 회전 시스템인 순운동학( Forward Kinematics )을 위해, 스켈레톤을 사용하기 위한 초급 및 중급 원칙들을 몇 가지 소개할 것이다. 그러다 보면, 그것은 당신이 갈망하는 질문들에 대한 답을 줄 것이다. 당신이 이 글을 모두 읽었을 때, 당신의 앞을 가로 막는 장애물들을 뛰어 넘을 수 있는 충분한 에너지를 느낄 수 있기를 바란다.


Forward Kinematics vs. Inverse Kinematics



얼마 전까지만 해도, 게임 캐릭터들은 a lot like shellfish( 역주 : 조개 껍데기 같이 쌓인 구조? )였다: 그것들은 기본적으로 돌같은 세그먼트( segment )들을 쌓아 놓은 것일 뿐이었다. 애니메이터들이 바랄 수 있는 최고의 것은 기본 계층구조를 다룰 수 있는 플랫폼이었으며, 이는 그들이 모든 세그먼트들의 위치와 키프레임을 한 번에 설정할 수 있도록 해 주었다. 여기에서 현실감있게 팔꿈치를 구부리거나 근육이 움직이는 것은 바라지 말기 바란다 - 이는 일어날 수 없는 일이었다. 실시간 표면 변형( deformation )을 다룰 수 있는 현대의 프로세싱 파워가 없이는, 게임은 단지 로봇이나 갑옷만을 표현했었다.


Advanced Processor Performance Enables Computer-generated Skeletons Animated with inverse kinematics


얼마동안은 게임 개발자들은 불편함을 조용히 감내했다. 그리고 나서 PC 들은 더욱 빠르고 스마트해졌으며, 이는 게임 엔진들을 더욱 빠르고 스마트하게 만들어 줬다. 발전된 처리 성능은 단순히 세그먼트화된 캐릭터를 함께 저장하는 것 뿐만 아니라 그 캐릭터들의 스킨을 실제로 변형하기 위해서 컴퓨터가 생성한 스켈레톤을 사용할 수 있도록 해 주었다. IK 가 선택할 수 있는 제어 시스템이 되었다.


The Scoop on Hierarchies


역운동학을 이해하기 위해서는 기본적인 계층구조 및 순운동학에 대해서 이해하는 것이 중요하다. 직접적으로 target-to-target morphing 을 하는 것 외에, 애니메이터들은 대부분 자신의 캐릭터들을 움직이기 위해서 갖가지 계층구조를 사용한다. 계층은 부모-자식-이웃 관계를 말한다. 하나의 오브젝트에 부모나 자식을 할당하는 작업은 "parenting" 이나 "grouping" 이라 불린다. 인간의 다리같은 경우에, 위쪽 다리( upper leg )의 부모는 엉덩이( hip )이며, 아래쪽 다리( lower leg )은 위쪽 다리의 자식이다. 그리고 발( foot )은 아래쪽 다리의 자식이다. 오른쪽 위쪽 다리는 왼쪽과 이웃 관계를 공유하며, 둘다 엉덩이의 자식들이다( 그림 1 참조 ).



그림 1. 순운동학을 위한 기본적인 아래쪽 몸 설정 및 계층.


또 다른 계층에 대한 학설은 "inverted tree" 모델을 사용한다. 여기에서는 부모( 엉덩이나 허리( pelvis ) )가 "루트( root )"라 불린다. While no part of a hierarchy is ever really referred as the "trunk", the children, and their children, become "branches"( 그림 1 참조 ).


The Trouble with Forward Kinematics


캐릭터의 손이 기본 계층 하에서 움직이기를 원한다면, 먼저 위쪽 팔( upper arm, 상박 )을 회전시키고 나서 아래쪽 팔( forearm, 팔뚝, 하박 )을 회전시키고, 마지막으로 손 자체를 회전시키는 작업을 전체 팔이 올바른 위치에 올 때까지 해야 한다. 이는 회전의 "top-down" 시스템이며 순운동학이라 불리며, 기본 애니메이션을 위한 훌륭한 시스템이다.


애니메이션은 순운동학과 기본 계층구조를 사용하면 단순해 보인다 - 당신의 캐릭터가 발이 바닥 위로 미끌어지지 않게 걷는다든가, 몸이 돌고 있는 동안에 발은 그대로 머물러 있는다든가 하는 특정 행위를 하기 전까지는 단순하다. 그런 경우에, 당신은 미적인 만족을 시켜 주지는 않는 두 가지 선택을 할 수 있다:


    • 전체 계층을 회전시킨다( 이는 불필요하게 말이 미끄러지게 만든다 ).
    • 계층구조의 위쪽( 엉덩이 )만 회전시키고 다른 부분은 그대로 둔다( 보기에 매우 고통스럽다 ).


그 시점에서, 순운동학( 그리고 당신의 캐릭터 )은 분리된다. 걷고 있는 캐릭터의 발을 ( 바닥에 ) 심는 것은 거의 불가능하다. 왜냐하면 오브젝트에 있어서 가장 어려운 것은 계층 구조의 맨 아래쪽이, 그 위쪽이 움직이고 있음에도 불구하고, 그대로 남아 있도록 하는 것이기 때문이다. The illusion of stability actually takes constant readjustment( 그림 2 참조 ).



그림 2. 기본 계층 구조와 순운동학을 사용할 때의 어려움은 전체 계층 구조를 회전시키거나 발을 미끄러지게 할 때 나타난다. 발들을 땅에 그대로 두면 그 결과는 참담할 수 있다.


The Advent of Computer-generated Skeletons using Inverse Kinematics



그림 3. Computer-generated skeleton

다행히도 오늘날의 게임 애니메이터들은 장편 극영화( feature film )을 위해서만 사용되었던 같은 애니메이션 기법들을 사용할 수 있게 되었다. 장편 극영화의 세계에서는, 다이노사우르스의 발목, 무릎, 허벅지, 엉덩이 등의 발가락 위쪽의 관절들이 미세하게 움직이기 때문에 발가락이 화면상에서 미끄러져 보이는 것을 보상하기 위해 발가락들에 대한 지속적인 재조정이 이루어진다. 그 조정은 픽셀보다는 피트 단위로 측정된다. 캐릭터를 현실감있게 움직이기 위해서는 순운동학 이외의 뭔가가 필요하다는 것은 확실해졌다. 또 다른 시네마틱 문제 - 캐릭터가 움직일 때마다 관절이 구겨지거나( crease ) 불룩해지는( bulge ) 그럴듯한 묘사 - 는 연속성있는 메쉬( continuous mesh )로부터 만들어진 모델을 사용해야만 해결될 수 있을 것이다. 그러나 어떻게 solid band 와 walk 를 만들 수 있을까? Turning to an earlier staple of film special effects, 스톱 모션( Stop Motion ) 소프트웨어 개발자들은 아마츄어 시스템이나 스켈레톤을 자신들의 computer-generated( CG ) 모델들에 포함시켰으며, 스켈레톤을 제어하기 위해서 역운동학( Inverse Kinematics )라 불리는 시스템을 개발했다.


개념적으로 볼 때, CG 스켈레톤은 이해하기 쉽다. 그것은 우리의 물리적 뼈대를 흉내낸 것이다 - 각 관절에 있는 힘줄( tendons )을 사용하는 강제 구조가 서로를 연결한다. 이는 inverted tree 구조이며, 부모는 뼈대의 루트라 불린다. 루트는 보통 캐릭터의 무게 중심에 위치한다; 이는 보통 이족 보행 동물의 등뼈( spine )의 시작점이다. 이 시스템을 ( 뼈대 없는, non-skeletal ) 기본 계층 구조보다 더 낫게 만드는 것은 힘줄이며, 이는 존재하기는 하지만 컴퓨터 3D 프로그램에서는 보이지 않는 요소이다. 뼈대 없는 오브젝트로부터 생성된 계층 속에 있으므로, 스켈레톤은 순운동학에 의해 top-down 으로 제어될 수 있다. 그러나 스켈레톤의 가장 큰 이점은 계층구조의 위족에서 아래쪽으로 제어를 전달할 수 있는 기능이다. 그것은 문제를 아래에서 위로 ( 순운동학의 역으로 ) "풀기( solve )" 때문에, 그 과정은 "역운동학" 혹은 IK 라 불린다. 이는 top-down 회전을 다루는 과정보다 더욱 직관적이며 더 적은 시간을 소비한다.



NOTE : 어떤 애니메이션 패키지들은 cube, sphere, 그리고 null object 들과 같은 "뼈대 없는" 오브젝트들에 대한 IK 응용프로그램을 허용한다. 하지만 이런 IK 를 생성하고 운용하는 것은 매우 복잡하다.



그림 4. IK 핸들을 사용하는 단순한 본 설정. 보통 본들은 루트( root )로 갈 수록 두껍고 이펙터( effector )로 갈수록 얇아지는 형태로 묘사된다. 녹색 삼각형은 "팔꿈치"를 구부림으로써 형성되는데, 어깨 위쪽과 손목은 팔꿈치의 회전 평면을 나타낸다. 이 평면은 팔꿈치를 바깥으로 휘두르는 것을 허용하기 위해서 조정된다.


스켈레탈 체인( skeletal chain )에서 가장 아래쪽에 있는 링크( link )는 보통 골( goal )이나 엔드이펙터( end-effector )라 불린다( 그림4 참조 ) ( 이 이름들은 다른 프로그램들에서는 다른 의미로 사용될 수 있다는 점에 주의하라 ). 세그먼트화된 모델의 경우에 캐릭터의 "피부( flesh )", 팔다리( limbs ), 몸통( torso ), 머리( head ) 등은 가장 가까운 스켈레톤의 본( 혹은 관절( joint ) )의 자식으로 붙는다. 단일 메쉬로 된 폴리곤 모델이나 seamless NURBS 모델의 경우에, 당신은 밑에 있는 스켈레톤 위에 모델을 씌우게( skin or envelope ) 될 것이다.


NOTE : 캐릭터의 팔다리, 머리, 피부, 혹은 옷은 보통 "지오메트리( geometry )" 이라 불린다. 지오메트리는 렌더링될 수 있지만, 스켈레톤은 렌더링되지 않는다.


지오메트리를 움직이는 대신에 스켈레톤을 사용하면, 스켈레톤 자체가 움직이게 되며, 지오메트리는 그것에 맞춰서 따라 가게 된다. 본들은 그것들 사이에 보이지 않는 힘줄을 가지고 있기 때문에, 계층구조의 일부만 회전하고 있을 때 관절이 분리되지 않는다. 한술 더 떠서, 당신은 스켈레탈 체인에 IK 를 적용할 수도 있다.


Adventage of Inverse Kinematics


자, 지금까지 말한 것들이 애니메이터에게 무슨 의미를 가질까? 그것은 당신이 체인의 말단- 예를 들어 손 - 을 확 잡아당길 수 있으며 손 위쪽에 있는 모든 본들이 자동으로 적절한 위치로 가기 위해 회전된다는 것을 의미한다. 이는 캐릭터가 어딘가에 도달해야만 할 때 정말 플러스 요인이 된다. 예를 들어 나무에서 사과를 딴다는가 하는 것 말이다. 마음속으로 어깨, 위쪽 팔, 팔꿈치, 손목을 그 위치에 도달하기 위해서 얼마나 회전시켜야 하는지를 계산할 필요가 없다. 애니메이터는 단지 손을 사과 위에 올리기만 하면 된다. 그러면 팔의 나머지 부분들은 따라 오게 된다.


기저에 깔린 스켈레톤을 사용하는 것의 부가 효과는 본과 관절이 표면을 변형( deformation )하기 위한 자연스런 제어 구조를 제공한다는 것이다. 변형을 사용하면, 기하 도형상의 각 제어점들은 본과 관절에 대한 상대 위치로 이동한다. 이는 지오메트리의 전체 조각을 한 번에 움직이는 것과 비교했을 때 뚜렷한 개선점이다.


모델이 스켈레톤 위에 입혀졌을 때( skinned or enveloped ), 운동학과 순운동학은 그것을 움직이기 위해서 사용될 수 있다. 스켈레톤의 일부분에 대해 운동학을 사용하는 것에 대한 이점들이 여전히 존재한다. 어떤 패키지들은 순운동학과 역운동학을 같은 스켈레탈 체인에 동시에 사용할 수 있도록 허용하며, 심지어는 실시간에 그것들 사이를 전환할 수 있도록 허용한다. 그리고 어떤 패키지들은 엄청난 노력을 해야지 그것들을 전환할 수 있도록 한다. 이를 위해서 당신은 제약( constraints )( 제약은 키프레임에 들어 가거나 빠질 수 있는 자성같은 것이라 생각할 수 있다 )이나 표현식( 수학적 공식 ), 혹은 그것들의 조합을 도입해야만 한다.


Bone Basics



먼저 소프트웨어 패키지를 살펴 보자. 그리고 나서 우리 본과 관절들을 살펴 보고, 마지막으로 그것들이 제어되는 방식에 대해서 살펴 보자.


Software Packages


모든 응용프로그램에서 스켈레톤이 같은 방식으로 제어되거나 표현되지는 않는다. IZWare Mirai, Alias Wavefront Maya, PowerAnimator 와 같은 패키지에서는, 당신이 완벽하고 완전히 붙어 있는 팔다리를 가진 스켈레톤들을 생성할 수 있었다. 이 문서를 작성한 시점에는 Softimage 3D 와 XSI 는 그런 기능을 지원하지는 않았지만, 그것들은 팔 체인, 다리 체인, 목 체인 등을 결합할 수 있는 도구를 제공하고 있었다. 이는 "제약"이라 불리는 독립된 제어 시스템들과 parenting 을 통해서 수행되었다.



그림 5. 지오메트리가 입혀지면, 서피스 제어점들은 그것들과 가장 가까운 본들에 의해 제어된다. 본들이 서피스에 대한 제어를 공유하면, 부드러운 주름과 구부림이 가능해진다. 그러나 서피스가 변형된 결과가 당신의 의도와 맞지 않는다 하더라도, 스켈레톤은 세그먼트화된 모델을 묶는 데 있어서 훌륭하며, 그것들의 관절들은 모든 조각들을 위한 자연스런 피봇( pivot ) 포인트를 제공한다.


어떤 패키지들은 역운동학 시스템을 제공하지만 본을 전혀 지원하지 않는다. 대신에 당신은 자신만의 스켈레톤을 주요 오브젝트로부터 만들어서 스켈레탈 속성들을 각 캐릭터의 개별 파트들에 부여할 수 있다. Softimage 3D, Hash Animation: Master, Discreet 3d Studio Max 와 같은 다른 패키지들은 두 가지 옵션을 모두 제공하는데, ( 보통 렌더링되지 않는 지오메트리를 사용하는 중심이나 피봇인 ) nulls 나 더미 오브젝트같은 다른 오브젝트들을 일반적인 스켈레탈 계층 구조 내로 포함시킬 수 있도록 허용해 준다. 여기에서 우리는 간략함을 위해 이러한 모든 오브젝트들을 "nulls" 라 부르기로 한다. 이 nulls 는 스케일, 회전, 이동될 수 있으며, 이는 당신의 캐릭터 메쉬의 제어점들을 그것들을 따라서 움직이도록 한다. 이 기법은 보통 근육을 볼록하게 만들거나 흉부를 확대하거나 하기 위해서 Softimage 3D 에서 사용된다( 그림 6 참조 ).



그림 6. Softimage 3D 에서 스켈레탈 구조( 보라색 오브젝트와 박스 )에 직접적으로 parenting 된 "null" 오브젝트를 사용하여 간단하게 근육 부풀리기( bulge ) 설정을 하는 모습. null 의 이동, 회전, 스케일링은 근육의 위치와 부풀림에 영향을 주며, 표현식( expressions )을 통해 팔꿈치 회전에 쉽게 엮일 수 있다. 왼쪽에 보이는 검은색 박스는 이 패밀리의 부모 역할을 하는 팔 지오메트리를 보여 준다. 파란색 박스는 루트, 팔꿈치, 손목의 관절이며 이는 그것들 사이의 "본들"을 회전시킨다. Softimage 3D 에서 관절들은 선택 가능한 오브젝트이며, 본들은 그렇지 않다는 것에 주의하라.  Softimage XSI 에서는 둘 다 선택할 수 있다.


개별 본들은 자신만의 로컬 축들을 가진 상태에서 생성되며, ( 항상은 아니고 ) 보통은 X, Y, Z 이다. 지오메트리를 사용할 때, 이 축들의 위치와 오리엔테이션( 역주 : orientation 은 기저 벡터로 이루어진 하나의 좌표계 공간을 의미함. 예를 들어 y-up 왼손 자표계, z-up 오른손 좌표계 )은 본의 피봇 포인트를 결정할 뿐아니라 그것의 회전 방향도 결정한다. 일반적으로 본들은 용접된 두 개의 조각으로 생각될 수 있다 - 본 자체와 본을 회전시킬 수 있도록 하는 관절. 그러나 모든 패키지들이 이러한 개념을 사용하는 것은 아니라는 것에 주의할 필요가 있다. 예를 들어 Softimage XSI 와 3D 는 전체 본 세그먼트들을 관절이라 부른다. Maya 와 IZWare Mirai 에서는 관절은 ( 본에 ) 붙어있는 것이지만, 개별적으로 선택될 수 있는 오브젝트이다. 이는 "굴근( flexors )"( 역주 : 구부리는데 사용하는 근육 ) 와 같은 변형되는 오브젝트들이 관절 자체나 본의 장축을 따라서 배치될 수 있도록 해 준다. 굴근들은 팔꿈치 안쪽의 주름( 관절 배치를 위한 좋은 후보 )과 같은 현실감있는 주름과 ( 본을 따라 배치된 굴근들의 ) 근육 부풀림을 가능하게 해 준다.


어떤 경우에, 축들은 고정된다 - 사용자는 본의 중심의 오리엔테이션을 변경할 수 없다. Softimage 3D 에서, X 축은 항상 본의 장축을 바라 본다. Maya 와 같은 다른 패키지들은 중심의 오리엔테이션을 선택할 수 있도록 한다. 이러한 패키지들은 본의 방향을 고려하지 않고 중심을 자유롭게 회전할 수 있도록 해 준다. 비록 그렇게 하는 것이 원하지 않는 결과를 나을 수 있기는 하지만 말이다.


피봇과 오리엔테이션이 중요한 이유는 무엇일까? 전문적인 애니메이션은 이것들을 올바르게 하는 것만을 고려하는 것은 아니다 - 그것을 빠르게 하는 것도 고려해야 한다. 만약 당신의 본들이 같은 방식으로 구성되었다면( 우리는 양의 X 축이 각 본의 장축을 바라보도록 설정할 것이다 ), 그것은 당신의 손가락들, 무릎들, 팔꿈치들, 척추가 같은 축을 중심으로 앞뒤로 구부려진다는 것을 의미한다. 대부분의 설정에서 그 축은 Z 축이다. 이는 딱부러진 표현을 창출하도록 한다( This makes creating expressions a snap ). 당신은 캐릭터가 어떤 방향으로 움직일지에 대해서 추측하거나 시도하거나 에러를 검사할 필요가 없다.


An Example of Surface Deformation using Bones


손바닥을 위로 바라보게 한 상태에서 손을 맞잡아 보라. 그리고 아래쪽 팔( forearm )을 보라. 이제 어깨를 움직이지 말고, 엄지 손가락이 천장을 가리키도록 회전해 보라. 만약 아래쪽 팔이 하나의 꽉찬 조각으로서 회전하고 있다면, 손목과 팔꿈치 사이에서 그리 미세하지 않은 회전을 보는 것은 불가능할 것이다( 혹은 적어도 고통스러울 것이다 ). 손과 더 가까운 피부는 손목 관절을 따라서 회전하지만 이 효과는 팔꿈치 쪽으로 갈 수록 낮아진다는 것에 유의하라. 서피스 변형을 사용하면, 덮혀 씌여진 지오메트리의 각 제어점들은 가장 가까운 관절이나 본에 의해서 제어된다.


This means that characters no longer need be loose piles of rock-hard segments. 팔꿈치는 자연스럽게 구부려진다; 심지어 이두박근( biceps )이 부풀려지거나 평평해진다( 그림 5 참조 ).


Bone Control


자, 이제 우리는 시작점으로 되돌아 왔다: 당신은 완벽한 스켈레탈 시스템과 IK 시스템을 지원하는 응용프로그램을 구입했다 치자. 당신의 문제는 끝났다. 맞나? 글쎄, 정확히 그렇진 않다. 나쁜 소식은 IK 시스템이 항상 순운동학 시스템보다 직관적이지는 않다는 것이다. 사과를 집거나 걷고 있는 동안에 바닥에 발을 붙이거나 하는 경우를 위해서는, IK 가 직관적이고 사용하기 쉬우며, 당신이 적절하게 그것을 설정할 수 있도록 해 준다. 그 "설정"은 본과 함께 동작하며 IK 가 시도되는 곳이다. 그 설정을 이해하는 데는 시간이 좀 걸린다.


Where to Begin


당신의 관절을 살펴 보라. 너무 깊이 들어 가기 전에, 당신의 몸이 작동하는 방식을 고려하고 컴퓨터가 생성해 준 스켈레톤은 인간의 스켈레톤과 완벽하게 같지 않음을 기억하라 - 그것은 하나의 표현일 뿐이다. 애니메이션 툴이 사실성을 반영하기 위해 점점 발전해 가고 있다고는 하지만, 애니메이션을 그럴싸하게 만드는 것은 여전히 애니메이터인 당신에게 달려 있다. 


관절이 동작하는 다양한 방식을 생각해 보라. 팔꿈치와 무릎은 어깨나 엉덩이와는 다르게 움직이는데, 그것들도 서로 조금씩 다르게 움직이며, 이 모든 것들은 등이나 목이 구부려지는 것과는 또 다르다. 일반적으로, 애니메이션 패키지들은 당신에게 하나나 혹은 두 가지 유형의 본들을 제공한다. 그것들은 본을 제어하기 위한 몇 가지 옵션들을 제공하기도 한다. 비록 우리 인간들은 발, 다리, 손, 장기들을 위한 수 백개의 본들을 가지고 있지만, CG 스켈레톤을 만들 때는 우리의 내부 본들은 거의 매칭될 필요가 없다. 모든 것을 매칭하려는 기법은 보통 애니메이션의 관점에서 역효과를 낸다: 서피스 제어를 위해서 너무 많은 본들을 가지는 것은 식당에서 너무 많은 메뉴를 가지고 있느 것과 같다. 타협하라. 가능한한 적은 개수의 본들만 사용하라. 다시 말하지만, 이는 그럴싸한 것을 만드는 것이지 실제를 만드는 것이 아니다.


Joint Types and Control


편의를 위해, 당신은 두 종류의 관절만을 가지고 있으면 된다: 하나는 소켓에서 모든 방향으로 휘두를 수 있는 것이고( which is really more than any of yours do without excruciating pain ), 다른 하나는 팔꿈치처럼 한 방향으로 구부릴 수 있는 것이다. Softimage 3D 는 모든 방향으로 회전할 수 있는 기능을 가진 모든 스켈레탈 체인에 대한 첫 번째 관절( root )과 절구공이 관절( ball-and-socket joint )을 제공함으로써 이를 다룬다. 그러면 당신은 "3D" 스켈레톤을 선택할지 "2D" 스켈레톤을 선택할지 결정하게 된다. 3D 스켈레톤은 루트처럼 모든 관절을 다루고 2D 스켈레톤은 볼소켓 관절처럼 특정 축을 따라서만 구부릴 수 있게 한다. 볼소켓 관절에서 시작해서 팔꿈치같은 관절에서 끝나는 "2D" 스켈레톤은 팔이나 다리를 위해서 최고이다. 또한 동시에 두 개 이상의 링크를 사용하지 않는 것이 최선이다.


Dealing with Challenges



동시에 두 개 이상의 링크를 사용하면 어떤 일이 벌어질까? 발과 같은 것을 위한 세 번째 링크를 추가한다거나 캐릭터가 사과를 집는 움직임을 만들기 위해서 IK 를 사용한다거나 하는 일반적인 도전들에 대해서 이야기해 보자.


The Third Link Dilemma: What About Adding Feet?


IK 에 의해서 제어되는 체인에서 두 개의 링크는 충분히 직관적이다. 하지만 발은 세 번째 링크를 표현한다. 발을 추가하는 것을 어떻게 다룰 것인가? Softimage 3D 에서, 발목은 실제로는 두 개이다: 다리 체인의 끝과 발 체인의 시작이다. 이 두개를 같이 넣으려면 당신은 발 체인을 다리 체인의 엔드 이펙터의 아래로 parenting 하거나 "제약"을 사용해야 한다. 제약에 대해서는 나중에 다루도록 하겠다. 두 개의 링크 다음에 IK 를 사용해 제어하는 것이 왜 어려운지에 대해서 이야기해 보자.


엄격히 말하자면, IK 에 의해 제어되는 체인은 체인의 가장 아래쪽에 있는 링크나 관절에 의해서 제어된다. 그 바닥 관절이나 엔드 이펙터의 모든 움직임은 계층구조상 최상위까지에 있는 모든 본들을 조금씩 회전시키게 된다.


두 개의 다리 본( 허벅지와 종아리 )으로 구성된 체인을 고려해 보자. 여기에서 발목은 바닥 관절이고 엔드 이펙터이다. 발목을 밀면 그 결과로 무릎이 구부려지고 허리에서 허벅지가 회전한다. 매우 직관적인 모션이다. 여기에다가 다른 링크를 추가하자: 발을 위한 본. 이번에는 발의 볼에 있는 엔드 이펙터를 밀어 보자. 그러면 발목이 구부려지고 무릎이 구부려지고 허리에서 허벅지가 회전한다. 그러나 각 관절이 구부려지는 순서와 각각이 회전하는 양이 약간의 조절만으로도 크게 달라진다. 이는 설정을 제어하기 어렵게 만든다( 그림 7 참조 ).



그림 7. 본이 많아질 수록 변형이 더 부드러워지기는 하지만, 그 본들에 대한 실제 IK 제어는 2 개의 링크를 넘어 가지 않는 체인으로 분리하는 것이 최선이다. 가장 왼쪽의 설정( 보라색 화살표 )은 Softimage 3D 에서 two-link 다리 체인에 대해 제출된 one-link 발 체인을 가지고 있다. 이 설정은 발목에 대해 하나의 엔드 이펙터를 제공하고, 발가락에 대해 다른 엔드 이펙터를 제공한다. 이는 three-link 체인에 대해 하나의 엔드 이펙터만을 사용하는 것보다 좋다.  일반적으로 IK 에서, 더 많은 본을 사용하는 것은 더 적은 제어를 한다는 것을 의미한다.


얼마나 직관적인가. 두 개의 본을 사용해서 쉽게 제어되는 모션은 세 개 이상의 본을 사용하게 되면 완전히 망가지게 된다. 이것이 Softimage 3D 스켈레탈 설정에서 많은 체인들이 서로 parenting 되거나 제약을 가지게 되는 현상을 보게 되는 하나의 이유이다. 당신의 소프트웨어에서 IK 솔루션들을 고려해야 하는 부분이 여기이다. 그것이 요구하는 제약과 parenting 을 창조적으로 사용함에도 불구하고, Softimage 3D 는 3D figure 애니메이션을 위한 확고한( solid ) IK 솔루션을 제공한다.


다른 패키지들은 다른 솔루션들을 제공한다. Maya 와 Mirai 는 허리에서 발가락까지 완전한 뼈대를 생성하는 기능을 제공한다( 그림 8 참조 ). Maya 는 체인들 자체에 배치된 분리된 "솔버( solver )" 들을 사용함으로써 긴 체인들의 예측불가성을 제어한다. 애니메이터는 필요한 곳에 솔버를 배치함으로써 솔버의 영향이 미치는 범위( 시작과 끝 )를 선언한다. 팔을 제어하기 쉽게 만들기 위해, 어깨에서 손목까지 솔버를 늘릴 수 있다. 손목에서 중지의 시작부분까지 솔버를 배치할 수도 있다. 손과 팔의 애니메이션은 각 솔버를 개별적으로 조작하는 것을 포함한다.


Maya 는 "스플라인( spline )" 솔버라는 특별한 솔버를 제공해 긴 목을 가진 생명체를 애니메이션할 수 있도록 하기도 한다. 이 솔버를 사용하면, 커브( 스플라인 )이 목의 척추뼈를 관통해 그려진다. 커브가 수정될 때마다, 척추뼈는 커브의 모양을 고려해 회전한다 - 해양 생물체를 위한 굉장한 솔루션이다.


IZWare( 공식적으로는 Nichimen ) 애니메이션 소프트웨어는 Walt Disney 의 Tron 을 만들 때부터 막후에서 사용되어 왔다. 그리고 이는 그것의 polygonal modeling package 로 유명하다. IZWare Mirai, a newcomer on the "off-the-shelf" animation package scene, helps beginning character animators get up and animating in no time( 역주 : IZWare Mirai 는 초보들이 시작하기 졶은 도구라는 의미인듯 ). The is because IZWare Technologies has done so much work up front( 역주 : 선불이 아니라는 의미인듯 ). Mirai 는 Maya 에서 처럼 완전한 branching skeletons 를 제공할 뿐만 아니라, 많은 캐릭터 솔루션들에 완벽히 걸맞는 이미 만들어진 뼈대들을 제공하기도 한다( 인간, 개, 심지어는 진드기도 ).


IZWare 는 매우 많은 공식( expressions )들과 팔다리 움직임을 자동으로 미러링( 혹은 뒤집기, mirroring or opposing )하기 위한 캐릭터 제어들을 추가함으로써 테크니컬 디렉터들의 두통을 해소해 주기도 한다. 이러한 움직임들의 예를 들면 걷거나 뛰는 사이클에서 팔과 다리를 흔드는 것을 뒤집는( 한 팔은 앞으로 한 팔은 뒤로 ) 것과 팔을 드는 컨덕터( conductor ) 등이 있다. 당신은 한 팔과 다리만 애니메이션시키고, 그 다음에 반대 팔다리를 자동으로 애니메이션시킬지 말지만 결정하면 된다. 이는 다른 프로그램들에서 스켈레톤들을 절반만 생성한 후에 거울면으로 복사( mirror-copied )하면 발생하는 음의 방향 회전( negative-rotation ) 문제도 교정해 준다.



그림 8. Mirai 에서 이미 만들어진 모델과 뼈대.소년, 개, 그리고 엄청 큰 진드기! 
자동 미러링과 음의 방향 회전 문제를 해결.


Dealing with IK Constraints


자, 이제 뼈대를 만들고 발을 제어하기 위해서 IK 를 사용하고 바닥에 발이 닿도록 했다. 손에도 IK 를 적용했다. 캐릭터가 앞으로 걷게되면 팔에 어떤 일이 벌어지는지 확인해 보자( 그림 9 참조 ).



그림 9. IK 에서 엔드 이펙터를 위한 위치들은 ( 단순한 계층 구조에서 처럼 ) 부모 공간의 위치에 대한 참조가 아니라 월드 공간에서 keyframed 되었다. 이는 실제로 IK 를 사용한 발이 쉽게 땅에 붙게 만드는 요인이다 - but it doesn't work well for wrist positions, which need to relate back to the skeleton( 역주 : 손목은 상대 위치여야 한다는 의미인듯 ). 이를 쉽게 해결하는 방법은 손목 엔드 이펙터를 null 오브젝트나 로케이터( locator )를 사용해 제약하는 것이다( 오른쪽 그림에서 십자 표시 ). 그리고 그 로케이터들을 계층 구조 내부로 다시 parenting 하는 것이다( 역주 : 월드공간에서 위치잡고 다시 그것을 부모 공간으로 돌리라는 의미인듯 ).


여기가 제약이 발생하는 곳이다. 엔드 이펙터를 keyframe 하는 것은 별로 좋은 생각이 아니라는 것이 밝혀졌다. 그렇게 하는 것은 실제로는 IK 를 사용할 때 발견할 수 있는 대부분의 문제를 발생시키며, 당신이 고민해서 만든 훌륭한 움직임들을 수행하는 것을 방해할 수 있다.


제약은 의지에 의해서 껐다 켰다 할 수 있는 강력한 자성이라고 설명하는 것이 최선일 것이다. 그것들은 하나의 오브젝트( 심지어는 null 오브젝트라도 )가 다른 오브젝트들에 영향을 미치도록 만든다. 서로 다른 제약들은 서로 다른 일을 수행할 수 있다. 제약은 거의 대부분 오브젝트의 중심이나 피봇에 대해서 작동하는데, 이는 오브젝트의 중심이나 피봇의 배치를 매우 중요하게 만든다. 어떤 패키지들은 다른 것들보다 더 많은 제약들을 포함하고 있지만, 세 개의 기본 제약들이 핵심이다:


    • Aim or directional.
    • Orientation.
    • Point or positional.


Aim or Directional


Aim 혹은 Directional 제약은 "영향을 받는" 오브젝트가 "대상" 오브젝트의 중심이나 피봇에서 지속적으로 어떤 축( 어떤 패키지들은 그것을 당신이 선택하도록 함 )을 바라보도록 만든다. 영향을 받는 오브젝트의 오리엔테이션은 대상 오브젝트의 오리엔테이션과 일치한다.


Orientation


Orientation 제약은 싱크로나이징을 하는 선수와 비슷하다. 한 선수가 돌면, 다른 선수도 돈다. 영향을 받는 오브젝트의 중심 오리엔테이션은 대상 오브젝트의 오리엔테이션과 일치한다.


Point or Positional


Point 혹은 positional 제약은 IK 를 위해 가장 자주 사용된다. 이 제약은 한 오브젝트를 직접적으로 다른 오브젝트에 가져다 붙이는데, 각각의 중심 위치에 맞춘다. 한 오브젝트가 움직이면, 다른 것도 강제로 움직여진다.


제약 대상으로 사용되는 오브젝트들은 다른 오브젝트들의 부모일 수도 있는데, 이는 그것들이 기본 계층 구조의 룰을 따른다는 것을 의미한다. 계층 구조에서 그것들의 위치와 움직임은 부모에 대해 상대적이다.


The Apple-picking Problem


제약은 그림 9 에서 내 뼈대의 손이 뒤로 회전하는 이유를 제공한다. 이는 스켈레탈 계층 구조와 기본 오브젝트 혹은 지오메트리 계층구조 사이의 중요한 차이들 중 하나 때문이다. 이는 성공적인 IK 애니메이션이 보통 두 종류의 계층 구조를 포함하고 있는 이유이기도 하다. 계층 구조에서 몇 개의 오브젝트들의 예로 비행 편대를 들어 보자. 이 비행 편대에는 부모로 선도기( lead plane )가 있다. 만약 한 비행기가 그룹보다 높거나 낮게 날도록 하자고 결정했다면, 우리는 움직임을 keyframe 할 수 있으며, 그것은 교묘하게 움직이면서 계속해서 그룹과 함께 날것이다. 이는 그것의 움직임이 부모 오브젝트인 선도기의 움직임에 대해 상대적이기 때문이다.


기본 계층 구조에서, 자식의 위치는 자식의 부모의 위치에 대해 상대적이다. That's why the feet slide when a character held together solely by hierarchies ( without bones ) rotates his or her hips( 역주 : 순운동학에서는 발이 땅에 닿지 않고 끌리는 것을 의미하는듯 ).


역운동학에서는 그렇지 않다. 엔드 이펙터( IK 계층 구조에서 가장 아래의 자식 )의 위치는 월드 공간에 대해 상대적이다. 그것이 IK 를 사용해서 애니메이션된 발이 그대로 남아 있는 이유이다. 불행히도 이는 IK 를 사용해서 애니메이션된 손들이 그것이 keyframe 된 공간의 위치에 도달하지 못하는 이유이기도 하다.


IK 는 발 배치를 위해서는 자연스럽다. 하지만 캐릭터가 사과를 집을 때는 어떨까? 그 액션은 IK 를 사용해서 하는 것보다 쉽지 않은가? 그렇다. 그것은 기본 계층 구조와 제약들의 도움을 받으면 최상이다.


우리는 어깨를 회전시키고 나서 위쪽 팔을 회전시키고 나서 아래쪽 팔을 회전시키는 등의 행동을 하는 것보다 사과에 손을 배치하는 것이 더 쉽기 때문에 IK 를 사용하기를 원한다. 하지만 우리는 캐릭터의 손이 등 뒤로 넘어 가지 않고 사과 나무로 올라 가는 것을 원한다. 어떻게 해야 할까?


The Apple-picking Solution


우리는 IK point 제약을 기본 계층구조와 함께 사용한다:


    • 정사각형과 원인 두 오브젝트를 선택하는 것이 좋다. 왜냐하면 그것들은 스플라인일 뿐이고 렌더링되지 않을 것이기 때문에, 나중에 그것을 감추기 위해서 기억할 필요가 없다. 우리는 원을 사용할 것이다.
    • 원 하나를 ( 팔 체인의 엔드 이펙터인 ) 손목에 배치한다. 그리고 다른 원 하나를 다른 손목에 배치한다. If you're really into it, point 제약을 사용해서 원들을 손목들에 직접 연결하고 그 제약들을 꺼 둔다. 
    • 그 원들을 캐릭터 몸통의 자식으로 만들어라( 몸통에 grouping 하거나 parenting 한다 ). 이는 그것들이 몸통이 가는 곳을 따라 가고 원들의 모든 움직임들은 몸통에 대해 상대적임을 의미한다. 이제 손목 엔드 이펙터들을 각각의 원들에 대해 제약한다. 이 아이디어는 엔드 이펙터가 아니라 제약 오브젝트들을 keframe 하는 것이다.

최종 결과는 두 세계에 있어 최상이다: 손들은 캐릭터가 움직일 때 몸통을 따라서 움직이게 되고, 당신이 제약을 가진 원을 사과에 배치할 때 손은 그것을 따라 간다. 이는 당신에게 IK 의 이점을 제공한다.


IK-driven 뼈대를 개선하기 위해서 제약 오브젝트의 계층 구조를 사용하는 것은 캐릭터 애니메이션 문제를 95% 정도 해결해줄 것이다. Everything from two characters playing catch to a rider falling from or jumping up onto a horse can be done with some form of animated constraint hierarchies and IK( 역주 : IK 와 애니메이션되는 제약 계층구조를 사용하면 말에서 떨어지거나 뛰는 행위들에 대한 문제들도 해결할 수 있다는 의미인듯 ). With the addition or a little math in the form of expressions to control complex behaviors like foot rotation, you'll have the tools you need to handle just about anything.


Conclusion



자 로봇의 전원을 끄고 방어구만으로 구성된 캐릭터는 벽에 걸어 두자. 그리고 이제는 서피스 변형을 해 보자. 우리는 계층 구조, 역운동학 대 순운동학, 그리고 그것들을 제공하는 주요 애니메이션 패키지들에 대해서 다뤘다. 또한 IK 와 제약을 사용하여 일반적인 애니메이션 문제들도 해결했다.


이제 당신만의 것을 경험하는 것은 당신에게 달렸다. 먼저 엔진이 IK 와 제약 계층 구조를 지원하는지 확인하고, 그것들을 해 보라. 이 문서에서 언급되지 않은 3D 소프트웨어 패키지라고 할지라도, 가격과 상관없이 IK 시스템, 계층 구조, 어떤 종류의 제약 혹은 링크들은 가지고 있음을 기억하라. 어떤 것을 얻을 수 있는지 확인해 보고 나가서 움직여라!


For More Information



아래의 리스트에서, 당신은 앞에서 언급한 소프트웨어 패키지와 도구들에 대한 URL 들을 찾을 수 있다. 또한  Intel® Software Directory and Software Download Store 를 확인해서 도구들과 솔루션들의 리스트들을 찾아보기를 원할 것이다.


About the Author



A professional animator and technical marketing engineer for Intel Corporation, Steve Pitzel has been a computer graphics instructor and animator for six years. He began his graphic arts career in college as an editorial cartoonist and courtroom sketch artist. After converting from pencil to mouse, he went on to convert others, teaching 3D applications such as Softimage, PowerAnimator, and Maya to traditional cell animators and computer graphic artists for Disney Feature Animation, Sony Pictures Imageworks, VIFX/Rhythm & Hues and UCLA. He was a lead animator for the CBS feature, The Nuttiest Nutcracker*, and a senior artist for Mattel. 


When he isn't animating, he's usually writing. His first novel, Wizrd, was published by St. Martin's Press in 1994 under his pen name, Steve Zell. He is currently working on his second novel.


'물리_수학_기하학' 카테고리의 다른 글

중력과 수직항력  (10) 2019.07.07
장력( Tension )  (13) 2019.06.26
Matrix major & multiplication  (2) 2018.08.12
[ 번역 ] The Perils of Floating Point  (0) 2018.08.10
[ 번역 ] Depth Precision Visualized  (11) 2017.06.04
[ 번역 ] Moment of inertia 일부 번역  (0) 2016.11.07
모멘트( moment )  (22) 2016.01.06
Curve  (0) 2015.10.04
[ 일부 번역 ] CLIPPING USING HOMOGENEOUS COORDINATES  (0) 2013.04.29
Arc length of curve  (0) 2012.09.21

개요



이 문서에서는 1인칭 캐릭터에서의 이동 및 애니메이션에 대해서 다룹니다.


1인칭 애니메이션 애셋은 "Content/RestrictedAssets/Animations/Universal/1stPerson/UT4_Base_1stP_AnimBP.uasset" 입니다. 이 블루프린트 안에는 여러 가지 애니메이션 블렌딩 루틴들이 있는데요, 이 중에서 이동과 관련한 부분만 살펴 볼 것입니다.


1인칭 이동 애니메이션은 FSM( Finite State Machines )로 표현됩니다. 다음과 같은 순서로 이동 애니메이션을 분석해 볼 것입니다.


    • 먼저 FSM 이 어떤 식으로 구성되어 있는지를 알아 볼 것입니다.
    • 다음으로 FSM 에 값을 공급하기 위해서 이벤트 그래프가 어떻게 구성되는지 살펴 볼 것입니다.
    • 다음으로 각 State 에서 어떠한 애니메이션들이 블렌딩되는지를 살펴 볼 것입니다.
    • 마지막으로 각각의 애니메이션 애셋들이 어떻게 구성되어 있는지를 살펴 볼 것입니다.


Main_Motion FSM



1인칭 이동 애니메이션에서 핵심은 "Main_Motion" FSM 입니다. AnimGraph 를 보면, "Main_Motion_Cache" 라는 것을 만들기 위해서 "Main_Motion" FSM 을 사용합니다. "Main_Motion_Cache" 가 뭐냐라는 질문에 대한 답은 다른 문서에서 하도록 하겠습니다. 여기에서는 "Main_Motion" 에 대해서만 집중합시다.


그림1. Main_Motion_Cache.


이 "Main_Motion" 노드를 더블클릭하면, 아래와 같은 FSM 을 볼 수 있습니다.



너무 그림도 작은데다가 Hierarchical FSM 이기 때문에 State 안쪽의 내용을 볼 수 없습니다. 게다가 Transition 조건도 마우스를 올리거나 클릭해야 나오기 때문에 한 눈에 볼 수 없습니다. 그래서 따로 UML State Diagram 을 준비했습니다.



Transition 까지 전부 표현하다 보니 그림이 좀 지저분한 감이 있긴 하지만, 보시는데 큰 문제는 없을 것입니다.


Movement 를 중심으로 Jump, Fall, Slide 라는 동작을 수행하게 됩니다. 물론 각각은 여러 개의 state 로 나뉘어 있거나 sub-state 를 가지게 됩니다.


 State

Animation & Desc

 Transition Desc

 Target State

 Movement

  • 이동 관련 하위 상태를 포함함.
    • Idle.
    • Start_Run.
    • Run.
    • Stop_Run.
    • Change_Direction.
  • 11 번 transition.

 Falling

  • 18 번 transition.
 Slide

 Idle

  • 1stP_Idle_Ready_Rif( 대기 동작 ).
  • 대기 상태.
  • 1 번 transition.

 Start_Run

  • 5 번 transition.

 Run

 Start_Run

  • 1stP_Run_Fwd_Rif( 전방 달리기 동작 ).
  • BS_1stP_Run_Transition_Direction_Change_Rif( 방향에 따른 팔 블렌딩 ).
    • 1stP_Run_Transition_Fwd_to_Bwd_Rif.
    • 1stP_Run_Transition_Right_to_Left_Rif.
    • 1stP_Run_Transition_Bwd_to_Fwd_Rif.
    • 1stP_Run_Transition_Left_to_Right_Rif.
  • 달리기 시작함.
  • 원하는 이동방향에 따라서 팔을 흔드는 모양이 달라짐.
  • 2 번 transition.

 Run

  • 8 번 transition.

 Stop_Run

 Run

  • 1stP_Run_Fwd_Rif( 전방 달리기 동작 ).
  • 앞으로 달려감.
  • 3 번 transition.

 Stop_Run

  • 5 번 transition.

 Idle

  • 9 번 transition.

 Change_Direction

 Stop_Run

  • 1stP_Idle_Ready_Rif( 대기 동작 ).
  • BS_1stP_Run_Transition_Direction_Change_Rif( 방향에 따른 팔 블렌딩 ).
    • 1stP_Run_Transition_Fwd_to_Bwd_Rif.
    • 1stP_Run_Transition_Right_to_Left_Rif.
    • 1stP_Run_Transition_Bwd_to_Fwd_Rif.
    • 1stP_Run_Transition_Left_to_Right_Rif.
  • 멈추기 시작하거나 달리기 시작함.
  • 원하는 이동방향에 따라서 팔을 흔드는 모양이 달라짐.
  • 4 번 transition.

 Idle

  • 7 번 transition.
 Start_Run

 Change_Direction

  • BS_1stP_Run_Transition_Direction_Change_Rif( 방향에 따른 팔 블렌딩 ).
    • 1stP_Run_Transition_Fwd_to_Bwd_Rif.
    • 1stP_Run_Transition_Right_to_Left_Rif.
    • 1stP_Run_Transition_Bwd_to_Fwd_Rif.
    • 1stP_Run_Transition_Left_to_Right_Rif.
  • 원하는 이동방향에 따라서 팔을 흔드는 모양이 달라짐.
  • 10 번 transition.

 Run

 Falling
  • 점프 관련 하위 상태를 포함함.
  • Jump_Start.
    • 1stP_Jump_Start_Rif( 점프 시작 동작 ).
  • Jump_Loop.
    • 1stP_Jump_Loop_Rif( 점프 활강 동작 ).
  • Jump_Start 애니 끝나면 바로 Jump_Loop 로 전이됨.
  • 12 번 transition.

 Jump_Land

  • 14 번 transition.

 Slide

 Jump_Land
  • 1stP_Jump_Land_Rif( 착지 동작 ).
  • 바닥에 착지함. 
  • 13 번 transition.
 Movement
  • 15 번 transition.
 Slide

 Slide

  • 1stP_KneeSlide_Fwd_Rif( 미끌어지는 동작 ).
  • 경사면에서 미끌어짐.
  • 왼손의 총에 대한 IK 가 해제됨.
  • 16 번 transition.

 Slide_End

  • 19 번 transition.
 Movement
 Slide_End
  • 1stP_KneeSlide_Fwd_End_Rif( 미끌어지는 동작 종료 ).
  • 왼손의 총에 대한 IK 가 복구됨.
  • 17 번 transition.

 Movement

 

개요



[ 5.3. 플레이어 입력 ] 에서 어떤 플레이어 입력이 있는지 살펴 보았습니다. 이 섹션에서는 이동과 관련한 로직 및 애니메이션에 대해서 살펴 보도록 하겠습니다.


이동( locomotion, 보행, 운동 )과 관련된 로직에 대해서 다루도록 하겠습니다. 간단하게 요약하자면 UT 의 이동 로직은 UUTCharacterMovment 컴포넌트에 의존합니다. Character component 의 처리 결과에 따라서 어떠한 애니메이션들을 블렌딩할지를 결정하게 됩니다.


1인칭 캐릭터에서는 "Content/RestrictedAssets/Universal/1stPerson/UT4_Base_1stP_AnimBP.uasset" "Main_Motion" FSM( finite state machines ) 을 사용하며, 3인칭 캐릭터에서는 "Content/RestrictedAssets/Animations/Universal/UT4_Base_AnimBP.uasset""Locomotion" FSM 과 "Landing" FSM 을 사용합니다.


일단 Character Movement 컴포넌트의 주요 역할은 물리와 애니메이션에서 사용할 자료( 변수 )를 준비하는 것입니다. 만약 Character Movement 컴포넌트가 없고 Player Controller 만 존재한다면, Player Controller 나 Character 에서 물리 및 애니메이션을 처리해야만 할 것입니다.


Character Movement 컴포넌트



UT 에서 기본 Character Movement 컴포넌트의 클래스는 UUTCharacterMovement 입니다. "DefaultCharacter" 블루 프린트를 열어서 "Components" 뷰를 보면 아래쪽에 "UTCharacterMovment(Inherit)" 라는 항목을 볼 수 있습니다. 오른쪽의 "Details" 뷰를 보면 매우 많은 속성 카테고리들이 존재함을 알 수 있습니다.



보시면 알겠지만 게임에서 사용할 만한 상황들은 거의 다 들어 가 있습니다. 물론 상황에 맞춰 FSM 을 구성하는 수고는 해야 합니다.


이동 모드 



Character Movement 컴포넌트에서 이동 모드의 전환은 FSM 으로 표현될 수 있습니다만 여기에서 다루지는 않겠습니다. 애니메이션 블루프린트마다 애니메이션 FSM 을 따로 구성하기 때문에 코드 상에서의 상태 전환에 대해서 언급하는 것은 크게 의미가 없을 것 같습니다. 애니메이션 FSM 에 대해서는 다른 문서에서 다루도록 하겠습니다. 단지 다음과 같은 이동 모드들이 있다는 것만 알아 두시면 될 것 같습니다.


    • Walking : 땅바닥에 붙어서 걸어다니는 이동 모드.
    • NavWalking : AI 등이 네비게이션 메쉬와 길찾기를 통해서 걸어다니는 모드.
    • Swimming : 물에 들어 갔을 때의 이동 모드.
    • Falling : 점프를 하거나 바닥에 닿지 않아 떨어지고 있을 때의 이동 모드.
    • Custom : 사용자의 커스텀한 이동 모드.
    • Flying : 날아다니는 이동 모드.


이제 각 이동 모드와 관련한 중요한 속성들을 살펴 보도록 하겠습니다. 대부분 어렵지 않은 속성들을 가지고 있기 때문에 이해하는데 큰 어려움은 없을 것입니다. 일단 어떤 기능들을 가지고 있는지 이해하고 있어야지 이미 존재하는 기능을 또 구현하는 불상사를 막을 수 있기 때문에, 지루하더라도 한 번씩은 읽어 보시기 바랍니다. 


제가 밥상은 차려줄 수 있지만, 떠 먹는건 알아서 하시기 바랍니다.


Character Movement




각 이동 모드의 가속도 및 감속도를 설정하는 곳입니다.


 이름

 설명

 MaxFallingAcceleration

  • Falling 시의 최대 가속도( 이는 AirControl 속성에 의해 스케일링 됨 ).

 MaxSwimmingAcceleration

  • Swimming 시의 최대 상수 가속도.

 MaxRelativeSwimmingAccelNumerator

  • Swimming 시의 부가적 가속도인데, 속도 크기에 의해 나눠짐. Swimming 가속도는 MaxSwimmingAcceleration + MaxRelativeSwimmingAccelNumerator / ( Speed + MaxRelativeSwimmingAccelDenominator ) 임.

 MaxRelativeSwimmingAccelDenomitor

  • Swimming 가속도 공식의 일부.  Swimming 가속도는 MaxSwimmingAcceleration + MaxRelativeSwimmingAccelNumerator / ( Speed + MaxRelativeSwimmingAccelDenominator ) 임.

 BrakingDecelerationSliding

  • Sliding 시의 정지 감속도.

 DefaultBrakingDecelerationWalking

  • Walking 시의 정지 감속도 - BrakingDecelerationWalking 과 같은 값으로 설정하라.

 IgnoreClientMovementErrorChecksAndCorrection

  • true 이면, 이 이동 컴포넌트 상에서 클라이언트 에러를 위한 서버 위치 차이 검사를 무시한다.
  • 이는 캐릭터가 잠시 동안 극단적인 속력으로 움직이는데 클라이언트에서 부드럽게 보이도록 만들고 싶을 때 유용하다. 사용하고 나면 비활성했는지 확인해야 한다. 왜냐하면 이것은 캐릭터의 서버-클라이언트 이동 보정을 오동작하게 만들기 때문이다.


Character Movement(General Settings)




일반적인 설정을 하는 곳입니다.


 이름

 설명

 GravityScale

  • 커스텀 중력 스케일. 캐릭터를 위한 중력에 이 값이 곱해진다.

 MaxAccelleration

  • 최대 가속도( 속도가 변하는 비율 ).

 BrakingFrictionFactor

  • 정지할 때 사용되는 실제 마찰력 값에 곱해지기 위한 요소이다.
  • 이는 현재 사용되는 모든 마찰력 값에 적용된다. UseSeperateBrakingFriction 에 의존한다.
  • @note : 이는 경험적 이유로 2 값이 기본값이다. 1 값은 실제 drag equation 이다.

 BrakingFriction

  • ( Acceleration = 0 이거나 캐릭터가 최대 속력을 초과하고 있을 때마다 ) 정지시에 적용될 마찰력 ( drag ) 상수; 실제 사용되는 값은 BrakingFrictionFactor 와 곱해진다.
  • 정지중일 때, 이 속성은 바닥을 통해 움직이고 있을 때 얼마나 많은 마찰력이 적용될지를 제어할 수 있도록 해 준다. 이는 현재 속도를 스케일링하는 반대쪽 힘을 적용하게 된다.
  • 정지는 마찰력( 속도 의존적인 drag )와 상수 감속( deceleration )으로 구성된다.
  • 이는 모든 이동 모드에서 사용되는 현재값이다; 만약 이것을 원하지 않는다면, 이동 모드가 바뀔 때 이 값이나 bUseSeperatedBrakingFriction 을 재정의하라.
  • bUseSerperatedBrakingFriction 이 true 일 때만 사용된다. 그렇지 않으면 GroundFriction 같은 현재 마찰력이 사용된다.

 UseSeperateBrakingFriction

  • 만약 true 이면, ( 가속이 없을 때 ) 캐릭터를 천천히 멈추게 하기 위해서 BrakingFriction 이 사용될 것이다.
  • 만약 false 이면, CalcVelocity() 에 넘겨지는 것과 같은 마찰력을 사용할 것이다( 예를 들어 걸어다닐 때의 GroundFriction ). 이는 BrakingFrictionFactor 와 곱해진다.
  • 이 설정은 모든 이동 모드에 적용된다; 만약 특정 모드에서 이를 원하지 않는다면, 이동 모드가 변경될 때 토글링하는 것을 고려해 보라.

 CrouchedHalfHeight

  • Crouching( 앉기 )시에 사용할 충돌 절반 높이( 컴포넌트 스케일이 각각 적용됨 ).

 RotationRate

  • 초당 회전률. UseControllerDesiredRotation 이나 OrientationToMovement 가 true 일 때 사용된다. Infinite rotation rate 와 instant trun 을 위해서는 음수값을 설정한다.

 OrientRotationToMovement

  • true 이면, 가속 방향을 향해 캐릭터를 회전시킨다. 이 때 회전률은 RotationRate 를 통해 지정된다. UsecontrollerDesiredRotation 을 덮어 쓴다.
  • 보통 캐릭터의 UseControllerRotationYaw 같은 다른 설정들이 클리어되어 있기를 기대할 것이다.

 Mass

  • 폰( pawn )의 질량( 운동량( momentum )이 주어졌을 때를 위해 ).
 DefaultLandMovementMode
  • 물 속에 있지 않을 때의 기본 이동 모드. 플레이어 스타트업이나 텔레포트시에 사용됨.
  • Walking
  • NavWalking
  • Falling,
  • Swimming
  • Flying
  • Custom
 DefaultWaterMovementMode
  • 물 속에 있을 때의 기본 이동 모드. 플레이어 스타트업이나 텔레포트시에 사용됨.

 JustTeleported

  • 위치 변화가 일반 이동에 의한 것인지 텔레포트에 의한 것인지 결정하기 위해서 이동 코드에서 사용됨. 만약 텔레포트가 아니면, 위치 변화 기반해 속도가 재계산될 수 있음.

 WantstoCrouch

  • true 이면, 다음 업데이트시에 crouch( 혹은 crouch 유지 )를 시도함. false 이면 다음 업데이트시에 crouching 종료를 시도함.
 UseControllerDesiredRotation
  • true 이면, 컨트롤러의 회전을 향해서 캐릭터를 부드럽게 회전시킨다. 이 때 회전률은 RotationRate 를 통해 지정된다. OrientRotationToMovement 에 의해 덮어 써 진다.
 EnableScopedMovementUpdates
  • If true, high-level movement updates will be wrapped in a movement scope that accumulates updates and defers a bulk of the work until the end.
  • When enbled, touch and hit events will not be triggered until the end of multiple moves within n update, which can improve performance.
  • 역주 : 이동을 누적시키는 것과 관련한 업데이트들을 한 번에 묶어서 처리하고, 나머지 업데이트들은 지연시켜서 나중에 처리하는 기능을 의미하는 듯하다.

 RunPhysicsWithNoController

  • true 이면, 캐릭터 소유자를 위한 컨트롤러가 존재하지 않더라도 이동을 실행할 것이다.
  • 일반적으로 컨트롤러가 없으면, 이동은 무시되며, 캐릭터가 걷고 있다면 속도와 가속도가 0 이 될 것이다.
  • 컨트롤러 없이 생성된 캐릭터에서 이 플래그가 활성화되면, 이동 모드를 DefultLandMovementMode 나 DefultWaterMovementMode 로 적절히 초기화할 것이다.

 MaxSimulationTimeStep

  • 각각의 분절된( discrete ) 시뮬레이션 스텝의 최대 타임 델타이다.
  • 주로 큰 타임 스텝을 쪼개는 진보된 이동 모드에서 사용된다( usually those applying gravity such as falling and walking ).
  • 이 값을 작게 하면, 빠르게 움직이는 오브젝트 시나리오나 복잡한 충돌 시나리오를 해결할 수 있는데, 성능 비용을 지불해야 한다.
  • @경고 : 만약 ( MaxSimulationTimeStep * MaxSimulationIterations ) 가 최소 프레임율보다 너무 작다면, 마지막 시뮬레이션 스텝은 시뮬레이션을 완료하기 위해서 MaxSimulationTimeStep 을 초과할 수도 있다.

 MaxSimulationIterations

  • 각각의 분절된 시뮬레이션 스텝들을 위해 사용되는 반복( iteration ) 횟수.
  • 주로 큰 타임 스텝을 쪼개는 진보된 이동 모드에서 사용된다( usually those applying gravity such as falling and walking ).
  • 이 값을 증가시키면, 빠르게 움직이는 오브젝트 시나리오나 복잡한 충돌 시나리오를 해결할 수 있는데, 성능 비용을 지불해야 한다.
 CrouchMaintainsBaseLocation
  • true 이면, crouching 은 쪼그라든 캡슐의 중심을 낮춤으로써 캡슐의 바닥을 그대로 유지한다. false 이면, 캡슐의 바닥이 위로 올라가고 중심은 그대로 남는다.
  • 같은 행위가 uncrouch 시에도 적용된다: true 이면 바닥은 같은 위치를 유지하고, 중심이 올라 간다. false 이면, 캡슐이 커지고 바닥이 무엇인가와 충돌할 때만 올라간다. 
  • 기본적으로 이 변수는 이동 모드가 변경될 때만 설정된다: walking 일 때 true 로 설정하고 그렇지 않으면 false 로 설정한다. 이동 모드가 변경될 때 이 행위를 재정의하는데 부담가질 필요가 없다.
 RequestedMoveUseAcceleration
  • path following 을 위해 가속도를 사용할지 여부를 결정한다.
  • true 이면, path following 시에 목표 속도에 도달하기 위해서 가속도를 적용한다.
  • false 이면, path following 속도가 직접 설정되며, 가속도를 고려하지 않는다.


CharacterMovement : Walking




걷기와 관련한 설정을 하는 곳입니다. 


 이름

 설명

 MaxStepHeight

  • 캐릭터가 걸어 올라 갈 수 있는 ( 계단의 ) 최대 높이. 

 WalkableFloorAngle

  • 걸어다닐 수 있는 표면의 최대 각도. 이보다 큰 각도이면 걷기에는 너무 뾰족한 것임. 

 WalkableFloorZ

  • 바닥의 법선( normal )에 대한 최소 z 값. 이것보다 크면 걸을 수 없음. WalkableFloorAngle 로부터 계산됨.

 GroundFriction

  • 이동 제어에 영향을 주는 설정. 값이 높을수록 방향이 빠르게 변함.
  • 만약 bUseSeperateBrakingFriction 이 false 라면,  ( Acceleration 이 0 일 때마다 ) 멈출 때 더 빠르게 정지하는 능력에 영향을 주기도 함. 이는 BrakingFrictionFactor 와 곱해짐.
  • 이 속성은 땅바닥 위를 이동하다가 정지할 때 마찰력이 얼마나 적용되어야 하는지를 사용자가 제어할 수 있도록 하는 속성임. 이는 현재 속도를 스케일링하는 반대방향의 힘임.
  • 이 값을 변경함으로써 이는 눈이나 기름과 같은 미끄러운 표면을 시뮬레이션하기 위해서 사용될 수도 있음( 아마도 폰이 서 있는 재질에 기반해서 설정해야 할 것임 ).

 MaxWalkSpeed

  •  걸어다닐 때의 최대 속력. 떨어지고 있을 때의 최대 측면( lateral ) 속도를 결정하기도 함.

 MaxWalkSpeedCrouched

  •  앉아서 걸어다닐 때의 최대 속력.

 BrakingDecelerationWalking

  • 가속도 없이 걸어 다닐 대의 감속도. 이는 상수값에 의해서 속도를 직접적으로 감소시키는 지속적인 반대방향의 힘이다.

 CanWalkOffLedges

  • true 이면 캐릭터가 절벽 가장자리( ledge )에서 걸어서 떨어질 수 있음.

 CanWalkOffLedgesWhenCrouching

  • true 이면 캐릭터가 앉아서 걸어다닐 때 절벽에서 걸어서 떨어질 수 있음.

 CurrentFloor

  • 캐릭터가 서 있는 바닥에 대한 정보( 걷기 이동시에만 갱신됨 ).

 MaintainHorizontalGroundVelocity

  • true 이면, 걷기 이동시에 경사로를 올라 가더라도 항상 수평 속도를 유지하는데, 이는 경사로가 아닌 평면에서 이동했을 때보다 더 빠르게 이동하게 만든다. 
  • false 이면, 경사로가 아닌 평면에서 이동했을 때와 같은 속도로 이동하게 된다.

 IgnoreBaseRotation

  • 캐릭터가 그것이 서 있는 바닥의 회전을 무시할지 여부.
  • true 이면, 캐릭터가 현재 world 회전값을 유지한다.
  • false 이면, 캐릭터가 움직이는 바닥의 회전값만큼 회전한다.

 PerchRadiusThreshold

  • 캐릭터의 캡슐의 가장자리와 표면의 가장자리가 가까울 때 캐릭터가 표면의 가장자리에 걸쳐 있지 못하게 하는 문턱값.
  • 걸어다닐 수 있는 표면보다 낮은 값의 MaxStepHeight 를 가지는 캐릭터는 떨어지지 않는다는 것에 주의할 것.

 PerchAdditionalHeight

  • 절벽 가장자리에 걸쳐 있을 때, MaxStepHeight 에 이 값을 더해서 걸어다닐 수 있는 바닥에서 얼마나 떨어져 있는지를 검사한다.
  • 걸어 올라가도록 하기 위해서 MaxStepHeight 강제로 바꿈; 이는 캐릭터를 가장자리에서 떨어지게 하거나 바닥에서 약간 높게 떠서 올라가도록 함.

 ForceNextFloorCheck

  • 캐릭터가 걷기 이동중 상태일 때 그것이 실제로 이동하지 못했더라도 강제로 유효한 바닥을 검사하도록 함. 다음 바닥 검사 이후에 클리어됨.
  • 보통 AlwaysCheckFloor 가 false 일 때는 특정 상황이 발생하지 않는다면 바닥 검사를 피하려고 시도할 필요가 없다. 하지만 이는 다음 검사를 항상 실행하도록 강제하기 위해서 사용됨.

 LedgeCheckThreshold

  • 폰이 절벽 가장자리로 가서 떨어지는지 여부를 검사하기 위해서 사용됨. 만약 이 값보다 가장자리의 길이가 짧다면 폰은 절벽에서 떨어질 수 있다.

 AlwaysCheckFloor

  • 캐릭터가 걷고 있는 동안에 stationary character 를 위한 바닥 검사를 항상 강제할 것인지 여부.
  • 보통 움직이고 있지 않을 때는 바닥 검사를 피하는 것이 좋다. 하지만 ( 오브젝트들이 캐릭터 위로 타고 올라 가는 상황과 같이 ) 깡총깡총 뛰다가 잘못되는 상황이 존재한다면 바닥 검사를 강제하기 위해서 사용될 수 있다.

 UseFlatBaseforFloorChecks

  • 캐릭터가 평평한 바닥을 가진 도형을 사용하고 있는 것인양 바닥 검사를 수행함.
  • 이는 캐릭터가 절벽 가장자리에서 ( 캡슐이 가장자리에서 균형을 이루는 것처럼 ) 천천히 떨어지는 상황을 방지한다.


CharacterMovement : Jumping / Falling



캐릭터가 점프하거나 떨어지고 있는 상황을 제어하는 곳입니다.



 이름

 설명

 JumpZVelocity

  • 점프할 때 초기 속도( 즉각적인 수직 가속도 ).

 BrakingDecelerationFalling

  • 떨어질 때 측면 감속도. 가속도에 영향을 주지 않음. 

 AirControl

  • 떨어질 때, 캐릭터에 대해 가능한 측면 이동 제어의 양.
  • 0 = 제어 없음. 1 = MaxWalkSpeed 의 최대 값에서 완전한 제어.

 AirControlBoostMultiplier

  • 떨어질 때, AircontrolBootVelocityThreshold 보다 작은 측면 속도일 때 Aircontrol 에 곱해질 값. 
  • 이 값을 0 으로 설정하면 air control boosting 이 비활성화됨. 최종 결과는 1 로 잘림.

 AirControlBoostVelocityThreshold

  • 떨어질 때, 측면 속도의 크기가 이 값보다 작으면, AirControl 에 AirControlBoostMultiplier 가 곱해짐.
  • 이 값을 0 으로 설정하면 air control boosting 이 비활성화됨.

 FallingLateralFriction

  • 떨어질 때, 측면 공중 이동에 적용될 마찰력.
  • bUseSeperateBrakingFriction 이 false 이면, ( 가속도가 0 일 때마다 ) 멈출 때 더욱 빠르게 멈추는 능력에 영향을 줌.

 ImpartBaseVelocityX

  • true 이면, ( 점프를 포함해 ) 떨어지는 것이 끝났을 때 기저 액터의 X 축 속도에 전달됨. 

 ImpartBaseVelocityY

  • true 이면, ( 점프를 포함해 ) 떨어지는 것이 끝났을 때 기저 액터의 Y 축 속도에 전달됨.

 ImpartBaseVelocityZ

  • true 이면, ( 점프를 포함해 ) 떨어지는 것이 끝났을 때 기저 액터의 Z 축 속도에 전달됨.

 ImpartBaseAngularVelocity

  • true 이면, 점프나 떨어지는 것이 끝났을 때 기저 컴포넌트의 각속도의 접선( tangential ) 성분에 전달됨.

 NotifyApex

  • true 이면, 꼭대기( apex )에서 점프할 때 CharacterOwner 의 컨트롤러에 NotifyJumpApex() 이벤트를 전달함. 이는 이벤트가 트리거되면 클리어됨.

 JumpOffJumpZFactor

  • 캐릭터 밑에 있도록 허용되지 않은 액터로 점프해서 올라갔을 때 사용될 JumpZVelocity 의 분수값( 예를 들어, 여러분이 다른 플레이어의 위에 서 있도록 허용되지 않았다면 ).


Character Movement : Swimming



캐릭터가 물에 빠졌을 때의 이동을 제어하는 곳입니다.



 이름

 설명

 MaxSwimSpeed

  • 최대 수영 속력.

 BrakingDecelerationSwimming

  • 수영시의 감속도이며 가속도에는 영향을 주지 않음.

 Buoyancy

  • 물의 부력. 비율( 1.0 = 자연스런 부력, 0.0 = 부력 없음 ).

 MaxOutOfWaterStepHeight

  • 물에서 나가기 위한 최대 높이.

 OutofWaterZ

  • 폰이 물에서 나가려 할 때 적용되는 Z 축 속도.
 JumpOutofWaterPitch
  • 물 속에 있을 때, 이 값 이상의 pitch 각을 올리면 jump 함.


Character Movement : Flying



날아 다닐 때의 이동을 제어하는 곳입니다.



 이름

 설명

 MaxFlySpeed

  • 최대 비행 속력.

 BrakingDecelerationFlying

  • 비행시의 감속도이며 가속도에는 영향을 주지 않음.


Character Movement : Custom Movement



사용자가 커스텀하게 설정하는 이동을 제어하는 곳입니다.


 이름

 설명

 MaxCustomMovementSpeed

 최대 속력.


Character Movement : Physics Interaction


캐릭터 이동시 물리의 영향을 어떻게 받을 것인지 설정하는 곳입니다.



 이름

 설명

 EnablePhysicsInteraction

  • 만약 활성화되면, 걸어다닐 때 플레이어는 물리 개체들과 상호작용함.

 TouchForceScaledtoMass

  • 만약 활성화되면, TouchForceFactor 가 영향받는 오브젝트의 kg 질량마다 적용됨.

 PushForceScaledtoMass

  • 만약 활성화되면, PushForceFactor 가 영향받는 오브젝트의 kg 질량마다 적용됨.

 PushForceUsingZOffset

  • 만약 활성화되면, PushForce 위치가 PushForcePointZOffsetFactor 를 사용해 이동됨. 그렇지 않으면 단순하게 충돌 지점을 사용함.

 ScalePushForcetoVelocity

  • 만약 활성화되면, 적용된 push force 는 물리개체의 속도를 플레이어의 속도와 같게 만들려고 시도함. 이는 힘을 감소시킬 것이며, PushForceFactor 에 의해 정의된 것보다 더 많은 힘을 적용하지는 않을 것이다.

 StandingDownwardForceScale

  • 플레이어가 서 있는 개체에 적용되는 힘이 ( 질량과 중력 때문에 ) 이 만큼 스케일링 됨.

 InitialPushForceFactor

  • 플레이어가 blocking 하는 물리 개체로 튕겨졌을 때 적용하는 초기 충격력( impulse force ).

 PushForceFactor

  • 플레이어가 blocking 하는 물리 개체와 충돌했을 때 적용할 힘.

 PushForcePointZOffsetFactor

  • 힘이 적용되는 위치에 대한 Z축 오프셋. 0.0 은 물리 개체의 중심이며, 1.0 은 천장. -1.0 은 바닥.

 TouchForceFctor

  • 플레이어가 터치했을 때 물리 개체에 적용되는 힘.

 MinTouchForce

  • 플레이어가 터치한 물리 개체에 적용되는 최소 힘. 만약 0.0 보다 작으면, 최소값 없음.

 MaxTouchForce

  • 플레이어가 터치한 물리 개체에 적용되는 최대 힘. 만약 0.0 보다 작으면 최대값 없음.

 RepulsionForce

  • 모든 겹쳐있는 요소들에게 지속적으로 적용되는 kg 당 힘.


개요



UT 에서 캐릭터 관련 애셋들이 실제로 어떻게 사용되는지 구체적으로 알아 보기 전에 캐릭터의 로직에 대해서 살펴 볼 필요가 있습니다.


플레이어가 게임 도중에 취할 수 있는 행동은 Input 매핑과 관련이 있습니다. "Edit >> Project Settings >> Input" 항목에는 두 종류의 Input Mapping 이 존재합니다; Action Mapping 과 Axis Mapping.




이 문서에서는 어떠한 입력 매핑이 존재하고, 그런 것들이 어떻게 캐릭터와 연관되는지에 대해서 살펴 보도록 하겠습니다.


입력 매핑



다들 알고 계실거라 생각하지만 노파심에 설명하자면 Action Mapping 은 단일 이벤트이며, Axis Mapping 은 지속 이벤트입니다. 이러한 Input Mapping 과 관련한 자세한 내용이 궁금하시다면, 언리얼 공식 문서의 [ 입력 (Input) ] 항목을 참조하십시오. 참고로 매핑을 할 때는 특정 키가 연관되어 있다는 것만 지정하지, down, up, double click 등의 정보를 명시적으로 지정하지는 않습니다.


어쨌든 UT 의 Action Mapping 은 다음 표와 같습니다( 여기에서는 PC 관련 매핑만 다루도록 하겠습니다 ).


 매핑 키

  매핑 입력 키

 설명 

 AUTPlayerController 메서드

 Jump

 Space Bar

 점프.

 IE_Pressed : Jump()

 Crouch

 C

 Left Ctrl

 앉기.

 IE_Pressed : Crouch()
 IE_Released : UnCrouch()

 Slide

 Left Shift

 슬라이딩.

 IE_Pressed : Slide()
 IE_Released : StopSlide()

 PrevWeapon

 Mouse Wheel Up

 이전 무기를 선택.

 IE_Pressed : PrevWeapon()

 NextWeapon

 Mouse Wheel Down

 다음 무기를 선택.

 IE_Released : NextWeapon()

 ThrowWeapon

 M

 무기를 버림.

 IE_Released : ThrowWeapon()

 StartFire

 Left Mouse Button

 Right Ctrl

 총질을 시작.

 IE_Pressed : OnFire()

 StopFire

 Left Mouse Button

 Right Ctrl

 총질을 멈춤.

 IE_Released : StopFire()

 StartAltFire

 Right Mouse Button

 아마도 alternative fire( secondary fire ).

 Alternative fire 를 시작.

 IE_Pressed : OnAltFire()

 StopFire

 Right Mouse Button

 Alternative fire 를 멈춤.

 IE_Released : OnStopAltFire()

 StartActivatePowerup

 Q

 Powerup( U Damage, Invisibility, Berserk, Jump Boots ) 을 활성화함.

 IE_Pressed : OnActivatePowerupPress()

 SlowerEmote

 Mouse Wheel Down

 감정 표현 애니메이션을 느리게 만듦.

 IE_Pressed : FasterEmote()

 FasterEmote

 Mouse Whee Up

 감정 표현 애니메이션을 빠르게 만듦.

 IE_Pressed : SlowerEmote()

 Play Taunt

 J

 첫 번째 도발 애니메이션 재생.

 IE_Pressed : PlayTaunt()

 Play Taunt2

 K

 두 번째 도발 애니메이션 재생.

 IE_Pressed : PlayTaunt2()

 TapRight

 D

 오른쪽으로 회피.

 IE_Pressed : OnTabRight()

 IE_Released : OnTapRightRelease()

 TapLeft

 A

 왼쪽으로 회피.

 IE_Pressed : OnTabLeft()
 IE_Released : OnTapLeftRelease()

 TapForward

 W

 앞쪽으로 회피.

 IE_Pressed : OnTabForward()
 IE_Released : OnTabForwardRelease()

 TapBack

 S

 뒤쪽으로 회피.

 IE_Pressed : OnTabBack()
 IE_Released : OnTabBackRelease()

 SingleTapDodge

 V

 앞의 TabXXX 시리즈가 더블 클릭을 요구하는데 단일 클릭만으로 회피.

 IE_Pressed : OnSingleTabDodge()

 ShowScores

 Tab

 점수 현황판을 보여 줌.

 IE_Pressed : OnShowScores()
 IE_Released : OnHideScore()

 ShowMenu

 Escape

 메뉴를 보여 줌.

 ShowMenu()

 Talk

 T

 전체 채팅창을 보여 줌.

 IE_Pressed : Talk()

 TeamTalk

 Y

 팀 채팅창을 보여 줌.

 IE_Pressed : TeamTalk()


Axis Mapping 은 다음 표와 같습니다.


 매핑 키

 매핑 입력 키

 스케일

 설명 

 AUTPlayerController 메서드

 MoveForward

 W

 Up

 1.0

 1.0 

 앞쪽으로 이동. 

 MoveForward()

 MoveBackward

 S

 Down

 1.0

 1.0 

 뒤쪽으로 이동.

 MoveBackward()

 MoveLeft

 A

 1.0

 왼쪽으로 이동.

 MoveLeft()

 MoveRight

 D 

 1.0 

 뒤쪽으로 이동.

 MoveRight()

 TurnRate

 Left

 Right

 -1.0

 1.0

 비율로 Yaw 회전.

 TurnAtRate()

 Turn

 Mouse X

 1.0

 Yaw 회전.

 AddYawInput()

 LookUp

 Mouse Y

 -1.0

 Pitch 회전.

 AddPitchInput()

 MoveUp

 C

 Space Bar

 1.0

 -1.0

 수직으로 이동. 

 MoveUp()


이러한 입력 매핑들은 AUTPlayerController::SetupInputComponent() 에서 수행됩니다.



이동 입력



이동을 위한 이벤트 처리 로직은 아래의 sequence diagram 에 나와 있습니다. 간단한 실행 흐름만을 보여 주려고 했기 때문에, 내부적으로 설정되는 필드같은 것은 생략했습니다. 여기에서 전부 표현해 주기에는 너무 많습니다. 


반복되는 호출에 대해서는 하위 호출을 생략했으니 보시는데 주의하시기 바랍니다.




위의 다이어그램은 매우 복잡해 보이지만 사실 매우 단순합니다. 입력은 Player Controller( AUTPlayerController ) 에서 처리합니다. 그리고 Character( AUTCharacter ) 로 전달하죠. 그러면 Character 는 최종 TM 을 결정하기 위한 플래그나 정보를 설정합니다. 그런데 애니메이션 피드백이나 물리 피드백을 위해서 Movement Component( UUTCharacterMovement ) 에 상태 정보를 전달합니다. 


이벤트 처리 단계에서는 대부분 현재 상태나 플래그를 설정하는 것으로 끝납니다. 애니메이션 피드백이나 물리 피드백을 위한 실제 처리는 UUTCharacterMovement::PerformMovement() 에서 처리됩니다.


PerformMovement() 의 내부가 어떻게 구성되는지 좀 더 자세히 알고자 하신다면 [ UE4 캐릭터 이동 시스템 가이드 ]를 참조하시기 바랍니다.


전투 입력



FPS 게임이다보니 전투와 관련한 입력은 그리 많지 않습니다; fire, alt-fire, select weapon, drop weapon.


전투 입력이나 이동 입력이나 전반적으로 그 처리의 흐름이 크게 다르지 않습니다. 단지 Movement Component 와의 연관성이 더 적습니다. 특이한 것은 FDeferredFireInput 의 인스턴스는 UUTCharacterMovement::TickComponent() 호출 시점에서 소비된다는 것입니다.


나가며



여기에서는 플레이어 입력과 관련한 로직들을 간단하게 살펴 보았습니다.


그런데 근본적으로 우리가 관심을 가지고 있는 것은 이런 로직들이 최종적으로 다른 애셋들( 메쉬, 애니메이션 등 )과 어떤 식으로 연관되는지 알아 내는 것이므로 아직 성에 차지 않을 수 있습니다. 하지만 내용이 너무 복잡해져서 여기에서 모두 담기 어려운 면이 있어서 나눠서 분석할 계획입니다.

개요



1인칭 캐릭터는 말 그대로 1인칭 카메라 모드에서 동작합니다.


UT 에서는 하나의 캐릭터 내에 1인칭 캐릭터 메쉬와 3인칭 캐릭터 메쉬를 모두 포함하고 있습니다. 일단 플레이를 시작하면 플레이어를 위해서 DefaultCharacter 블루프린트의 인스턴스를 생성하게 됩니다.


그림1. DefaultCharacter 블루프린트.


노란 엣지를 가진 메쉬를 확인할 수 있습니다. 이 블루프린트의 상속구조는 다음과 같습니다.


그림2. DefaultCharacter 상속 구조.



[ 그림1 ]의 블루프린트에서 "(Inherited)" 라고 표시되어 있는 컴포넌트들은 모두 AUTCharacter 클래스에서 정의한 컴포넌트들입니다. 그래서 위치를 바꾸거나 이름을 변경하는 것이 불가능합니다. 만약 변경하고 싶다면 소스 코드를 수정해야 합니다.


어쨌든 이 문서에서는 1인칭 캐릭터와 관련한 컴포넌트에 집중하도록 하겠습니다. [ 그림1 ]의 "Components" 뷰에서 선택한 두 개의 컴포넌트( CharacterCameraComonent 와 FirstPersonMesh )들이 1인칭 캐릭터 전용 컴포넌트입니다. UTChracterMovement 는 1인칭 캐릭터와 3인칭 캐릭터에서 공용으로 사용합니다. 이 CharacterMovement 컴포넌트에 대한 간략한 설명은 [ UE4 캐릭터 이동 시스템 가이드 ] 에서 찾아볼 수 있습니다.


FirstPersonMesh



[ 그림1 ]의 FirstPersonMesh 컴포넌트는 USkeletalMeshComponent 의 인스턴스입니다. 이것은 UStaticMeshComponent 와 대응되는 것으로서 본애니메이션이 가능한 메쉬 컴포넌트를 의미합니다.


[ 그림3 ] 은 이 컴포넌트의 가장 중요한 속성들을 보여 줍니다.


그림3. FirstPersonMesh 컴포넌트의 주요 속성들.


속성들은 다음과 같은 의미를 가집니다. 여기에서는 간략하게 설명하도록 하겠습니다.

    • Animation 카테고리에서 "Content/RestrictedAssets/Animations/Universal/1stPerson/UT4_Base_1stP_AnimBP_C.uasset" 이라는 애니메이션 블루프린트를 사용할 것임을 지정합니다. 
    • Mesh 카테고리에서 "Content/RestrictedAssets/Character/Human/Male/malcolm_ut4_1stp_SKELMESH.uasset" 이라는 스켈레탈 메쉬를 사용할 것임을 지정합니다.
    • Materials 카테고리에서 "Content/RestrictedAssets/Character/Malcom_New/Materials/M_Malcom_Body_Panini.uasset" 이라는 머티리얼을 사용할 것임을 지정합니다.
    • Collision 카테고리에서 "NoCollision" 프리셋을 지정합니다. 즉, 부모 컴포넌트인 CapsuleComponent 의 콜리전 설정에 의존하겠다는 것입니다. 참고로 CapsuleComponent 의 콜리전 프리셋은 "Pawn" 으로 지정되어 있으며, [ 그림 4 ] 에서 확인할 수 있습니다.


그림4. CapsuleComponent 컴포넌트의 Collision Preset.


CharacterCameraComponent



CharacterCameraComponent 는 1인칭 카메라를 의미합니다. CharacterCameraComponent 가 FirstPersonMesh 를 자식으로 가지고 있기 때문에 카메라를 회전시키거나 이동시키면 자동으로 FirstPersonMesh 도 카메라의 영향을 받게 됩니다.


반대로 캐릭터 컨트롤러를 회전시키게 되면 자동으로 카메라도 회전합니다. 이는 CameraSettings 카테고리의 "UsePawnControlRotation" 속성을 true 로 만듦으로써 가능합니다.




"UsePawnControlRotation" 는 카메라가 플레이어 컨트롤러의 forward 방향을 바라보도록 강제하겠다는 것입니다. 다시 말하면 카메라가 항상 캐릭터의 등짝을 바라보게 된다는 의미입니다. 1인칭에 딱 맞는 카메라라 할 수 있겠죠. 세부적인 구현은 다음과 같습니다. 



정리



여러 가지 컴포넌트들이 존재하지만, 1인칭 캐릭터와 관련된 핵심 컴포넌트는 FirstPersonMesh 스켈레탈 메쉬 컴포넌트와 CharacterCameraComonent 카메라 컴포넌트입니다.


중요한 것은 FirstPersonMesh 가 CharacerCameraComponent 의 자식이어서 캐릭터의 TM 이 카메라에 종속되며, 카메라가 항상 등쪽을 바라보도록 하기 위해서 "UsePawnControlRotation" 을 사용한다는 것입니다.


이 문서에서는 간략하게 구조에 대해서만 언급하고 다른 문서들에서 1인칭 캐릭터의 세부 사항에 대해서 다루도록 하겠습니다.

개요



UT 에는 여러 종류의 캐릭터들이 있습니다. 그런데 N 개의 캐릭터에 대해 M 개의 애니메이션을 가지고 있다면, N X M 개의 애니메이션이 필요할 것입니다. 게다가 1인칭과 3 인칭을 모두 표현해야 한다는 것을 감안한다면 몇 개의 애니메이션을 만들어야 할지 감도 잡기 어렵습니다. 제가 대충 살펴 보니 3rdPerson 폴더에만 327 개의 애니메이션 애셋이 존재하더군요. 그리고 애니메이션의 개수도 문제지만 용량도 무시할 수 없습니다.


그런데 다행히도 UT 의 캐릭터들은 모두 인간형( Humanoid )이라는 공통점을 가집니다. 그래서 UE4 의 애니메이션 리타게팅( Animation Retargeting ) 기능을 사용하면 큰 힘을 들이지 않고도 하나의 스켈레톤( Skeleton )과 애니메이션을 공유할 수 있게 됩니다. 하지만 UT 에서는 리타게팅 기법을 사용하지 않고, 그냥 모든 스켈레탈 메쉬( Skeletal Mesh )의 스켈레톤을 공유하고 있습니다. 아마도 신체 비율이나 메쉬의 모양이 큰 차이가 없다고 판단한 것 같습니다.


공유하고 있는 스켈레톤 애셋의 경로는 "/Content/RestrictedAssets/Character/Human/Male/ut4_base_Skeleton" 입니다.


이 스켈레톤을 중심으로 크게 2 부류의 애니메이션으로 나뉩니다; 1인칭3인칭. 대부분의 애니메이션 애셋들은 "Content/RestrictedAssets/Animations/Universal" 에 저장되어 있습니다. "Content/RestrictedAssets/Animations""Human", "Necris", "Skaarj" 같은 하위 폴더들이 존재하지만, 거기에는 특정 캐릭터에 국한된 애니메이션들만 저장되어 있습니다.


1인칭의 경우에는 "Content/RestrictedAssets/Animations/Universal/IstPerson/UT4_Base_1stP_AnimBP" 라는 애니메이션 블루프린트를 사용하고, 3인칭의 경우에는 "Content/RestrictedAssets/Animations/Universal/UT4_Base_AnimBP" 라는 애니메이션 블루프린트를 사용합니다.


Animation Blueprint



애니메이션 블루프린트는 UAnimInstance 를 부모로 하는 블루프린트입니다. 가끔 애니메이션 블루프린트를 캐릭터 블루프린트같은 곳에서 어떻게 찾느냐는 질문을 하시는 분들이 있는데, 다음과 같이 찾으시면 됩니다. 아래 그림은 BaseUTCharacter 블루프린트에서의 예제입니다.



GetAnimInstance 를 통해 얻은 인스턴스를 UT4_Base_AnimBP 로 변환하는 것을 보실 수 있습니다. Target 으로 Mesh 가 설정되어 있는데, 그것은 3인칭 캐릭터에 대한 USkeletalMeshComponent 인스턴스입니다.


어쨌든 중요한 것은 애니메이션 블루프린트는 애니메이션 인스턴스라는 것입니다.


애니메이션 블루프린트를 열게 되면 크게 3 종류의 그래프가 존재한다는 것을 알 수 있습니다.


    • EventGraph
    • AnimGraph
    • StateMachine


UE4 에서는 이러한 그래프들을 적절하게 다룸으로써 최종 애니메이션 포즈를 결정하게 됩니다.


EventGraph



EventGraph 는 AnimGraph 와 StateMachine 에서 사용할 변수들을 공급하거나 AnimMontage 같은 애니메이션을 실행하기 위한 그래프입니다. 여기에서는 보통 Player Controller 나 Character 에 접근해서 필요한 정보를 뽑아 옵니다.



EventGraph 는, 그 이름이 의미하는 것처럼, 특정 이벤트가 발생했을 때 특별한 처리를 하게 됩니다. 이것은 일반적인 블루프린트의 EventGraph 와 같은 방식으로 동작합니다. 여기에서는 Animation 이나 State Machine 에서 발생하는 이벤트( notify )도 받을 수 있기 때문에 매우 활용도가 높습니다.




AnimGraph



AnimGraph 는 애니메이션 블렌딩을 위한 그래프입니다. 여러 종류의 애니메이션을 블렌딩할 수 있습니다. 



여기에서 특이한 점은 최종 포즈에서 사용되지 않는 블렌딩 노드들은 평가되지 않는다는 것입니다. 위의 그림을 보면 "Blend Poses by bool" 노드의 "True Pose" 슬롯에 바인딩되어 있는 라인은 평가되고 있지 않은 것을 볼 수 있습니다.


블렌딩 대상은 개별적으로 플레이될 수 있는 대부분의 애니메이션 요소이며, State Machine, 개별 애니메이션, Animation Montage 등을 블렌딩할 수 있습니다.


StateMachine



다들 잘 아시겠지만 StateMachine 은 특정 조건을 통해 노드를 전환할 수 있는 그래프입니다. 이것은 AnimGraph 의 하위요소입니다. AnimGraph 가 블렌딩을 통해 최종 포즈를 결정하는 것이기 때문에, 이러한 구조는 당연한 것이라 할 수 있습니다. UE4 의 StateMachine 은 HFSM( Hierarchical Finite State Machine ) 입니다.



UE4 의 StateMachine 에서 가장 좋은 점을 꼽으라고 한다면, transition 의 유연성이라고 할 수 있을 것 같습니다.


Unity3D 의 Mechanim StateMachine 같은 경우에는 파라미터를 넘겨서 transition 조건을 판단하는데, 이것은 복잡한 조건을 판단해야 하는 경우에는 매우 불편합니다. 그러므로 조건이 복잡해지면 하드코딩을 해야 합니다.


하지만 UE4 StateMachine 은 EventGraph 를 통해 복잡한 조건을 검사해서 StateMachine 에 변수를 공급할 수도 있고, transition 자체에서 조건을 만들 수도 있습니다.



게다가 transition 에 다양한 옵션들이 존재하고 있으며, blueprint 로 Notify 를 보낼 수 있다는 점이 매우 좋습니다.



나가며



정리하다가 보니 UE4 광고가 되 버린 것 같습니다. 어쨌든 UT 는 UE4 의 기본 애니메이션 메커니즘을 사용하고 있습니다.


애니메이션 애셋들은 1인칭 용과 3인칭 용으로 나뉘어 있으며, 모든 캐릭터가 스켈레톤을 공유하고 있습니다.


사실은 이 문서에서 애니메이션 애셋을 용도별( Animation Offset, Animation Montage, Animation Blend )로 구분해 놓으려고 했으나 좀 복잡해서 나중으로 미루도록 하겠습니다.


1인칭과 3인칭에 대한 애니메이션 애셋들의 종류나 그것이 사용되는 방식들에 대해서는 다른 문서를 통해 다루기로 하겠습니다.

개요



UE4 에서는 어떤 인스턴스의 근본 구조와 로직은 C++ 클래스를 통해 정의하고, 인스턴스당 특성들은 블루프린트 및 그것의 상속을 통해서 정의합니다.


UT 에서의 캐릭터도 마찬가지의 방식으로 정의되어 있으며, 그 구조는 다음과 같습니다.



GhostCharacter 라는 것은 튜토리얼에서 사용하는 특별한 캐릭터입니다. 그런데 이 구조를 보면서 뭔가 미진함을 느끼시는 분들이 있을 겁니다. DefaultCharacter BaseUTCharacter 에는 메시를 바꿀만한 이벤트같은 것이 존재하지 않습니다. 그러면 어떠한 경로를 통해서 다양한 메시가 나올 수 있는 것일까요? 


결론적으로 이야기하자면 UT 에서 모든 캐릭터는 DefaultCharacter 만 사용해서 생성됩니다. 다음 섹션에서는 이러한 일들이 어떻게 가능한지에 대해 구체적으로 설명하도록 하겠습니다.


Character Content



UT 에서 DefaultCharacter 의 Mesh 컴포넌트는 AUTCharacterContent 라는 액터를 참조하여 대체될 수 있습니다. Mesh 컴포넌트는 이전에도 이야기했듯이 3인칭 관점에서의 캐릭터를 표현하기 위한 컴포넌트입니다.


이 Mesh 컴포넌트를 어떻게 채워야 하는지에 대한 정보를 담고 있는 것이 바로 character content 입니다. UT 에서 AUTCharacterContent 를 상속하여 만든 블루프린트들은 "Content/RestrictedAssets/Character" 폴더에 있습니다.



그중에 NecrisFemaleBase 라는 블루프린트를 열어 보도록 하겠습니다.



열어 보시면 매우 실망스러울 것입니다. Mesh 라는 컴포넌트가 달랑 하나 있는데, 내용이 전혀 채워져 있지 않습니다. 그것은 Base 클래스이기 때문에 그렇습니다. 그렇다면 실제로 뭔가가 할당된 것이 있을까요?


네 있습니다. 단지 하나밖에 없어서 문제지요. "Content/RestrictedAssets/Character/Malcom_New" 폴더에 가면 Malcolm_New 라는 블루프린트 애셋이 있습니다( 폴더 이름과 애셋 이름이 다른 것은 오타가 아닙니다. 실제로 그렇게 되어 있습니다 ). 이것은 HumanMaleBase 를 상속하고 있으며, SkeletalMesh'/Game/RestrictedAssets/Character/Human/Male/malcolm_ut4_SKELMESH.malcolm_ut4_SKELMESH' 를 사용합니다.



여기까지 보시고 나서 "그래서 뭐 어쩌라고?" 라는 질문을 던지시는 분이 계실 겁니다. 당연한 질문입니다.


AUTCharacter 에는 ApplyCharacterData() 라는 메서드가 있습니다. 여기에서 AUTCharacterContent 를 인자로 받아 AUTCharacter 가 가지고 있는 Mesh 컴포넌트를 변경하게 됩니다.



코드를 조금만 읽어 봐도 금방 이해하시겠지만, 요약하자면 팀 재질과 메쉬를 설정합니다.


용례 : Bot



실제로 DefaultCharacterAUTCharacterContent 가 어떤 식으로 연결되는지에 대한 예를 들어 보도록 하겠습니다.


UE4 에서 플레이어의 상태를 저장하기 위해서는 PlayerState 라는 것을 사용합니다. Character 나 Pawn 에 정보를 직접 저장할 수도 있지만, 서버와의 연동을 생각하면 PlayerState 를 사용하는 것이 좋습니다. 언리얼 공식 문서의 [ 게임플레이 프로그래밍 ] 에서는 PlayerState 에 대해 다음과 같이 정의합니다.


인간 플레이어 또는 플레이어인 척 하는 봇과 같은 게임 참여자의 상태를 말합니다. 게임의 일부로서 존재하는 플레이어가 아닌 AI 에는 PlayerState 가 없습니다.

PlayerState 에 적합한 예제 데이터라면, 플레이어 이름, 점수, MOBA 게임류에서의 대전상대 레벨, CTF 게임에서 플레이어가 현재 깃발을 운반중인지 여부 등입니다. 모든 플레이어에 대한 PlayerState는 ( PlayerController 와는 달리 ) 모든 머신에 존재하며, 동기화 상태 유지를 위해 자유로이 리플리케이트 가능합니다.


어쨌든 정리하자면 이 PlayerState 는 플레이어의 정보를 유지하는데 사용됩니다. UT 의 경우에는 AUTCharacterContent  AUTPlayerState::SelectedCharacter 라는 속성을 통해 현재 플레이 대상의 CharacterContent 를 공급합니다.


자 원래 주제로 돌아 와서, UT 에서 Bot 은 UUTBotCharacter 라는 데이터 애셋으로 정의됩니다. "Content/RestrictedAssets/Character/Bots" 폴더에 보면 봇 캐릭터를 정의하는 애셋들이 있습니다. 이것은 실제 캐릭터가 아니라 UDataAsset 을 상속하고 있는 데이터입니다. "Content/RestrictedAssets/Character/Bots/ThunderCrash/Taye" 라는 봇의 데이터를 한 번 살펴 보도록 하겠습니다.



봇의 성격이라든가 목소리라든가 하는 여러 가지 특징들을 정의할 수 있군요. 하지만 우리가 집중할 것은 노란 박스로 강조해 둔 Character 속성입니다. 이것은 다음과 같이 정의되어 있죠.



앞에서 언급한 AUTCharacterComponent 를 사용하도록 메타 클래스를 지정하고 있음을 알 수 있습니다. 그런데 지금은 "None" 으로 비어 있죠? 이 경우에는 위에서 언급한 Malcolm_New 라는 기본 CharacterContent 를 사용하게 됩니다. 이것을 바꾸는 방법에 대해서는 "실습" 섹션에서 논의하도록 하겠습니다.


자 이제 이것이 전체적으로 어떤 관계를 가지는지 클래스 다이어그램을 통해 살펴 보도록 하겠습니다.



우리가 Character 속성에 CharacterContent 애셋을 지정하면, 그것은 AUTPlayerState.SelectedCharacter 에 설정되며, 그것은 다시 ( DefaultCharacter 의 부모인 ) AUTCharacter ApplyCharacterData() 의 인자로 넘겨집니다. 이를 통해서 DefaultCharacter 의 ( 3인칭 메쉬의 ) 외형이 결정되는 것입니다.


여기에서는 봇의 경우만 예로 들었지만, 다른 플레이어 캐릭터의 경우에도 PlayerState 를 가지기 때문에 다를 것이 없습니다.


실습 : Taye



이제 실제로 우리가 원하는 CharacterContent 의 봇에 지정해 보도록 하겠습니다. Taye 는 왠지 여자 이름인 것 같으므로 여자 캐릭터를 지정해 보겠습니다. 일단 "Content/RestrictedAssets/Character/Necris_Female" 폴더로 이동합니다.


1. 먼저 CharacterContent 부터 생성해야겠죠. 다음과 같이 블루프린트 부모로 NecrisFemaleBase 를 지정한 후에, 블루프린트가 생성되면 이름을 "NecrisFemale" 로 변경합니다.



그리고 나서 Mesh 의 "Skeletal Mesh" 항목에 "necris_female_ut4_SKELMESH" 를 할당해 줍니다. 이것으로서 CharacterContent 애셋 생성은 끝입니다. 굳이 애니메이션 돌아 가는 것을 확인하고 싶으시다면 "Anim Class" 항목에 애니메이션을 할당해 봐도 좋겠죠.



다음으로는 봇에다가 이 CharacterData 를 할당할 차례입니다. Taye 봇 데이터 애셋을 열어 "Character" 항목에 "NecrisFemale" 을 할당합니다.



"ExmapleMap" 의 시작부에는 다음 스샷과 같이 봇을 생성하는 곳이 있습니다. 게임에 들어 가서 그 위치에서 "Enter" 키를 누르면 봇이 생성되었다가, 다시 "Enter" 키를 누르면 봇이 죽습니다. 이렇게 몇 번 하다가 보면 Taye 가 생성됩니다. 기본으로는 Malcolm_New 가 생성되므로 구분하기는 어렵지 않을 것입니다. 랜덤으로 생성되기 때문에 인내심이 필요할 것입니다( Blue Team Spawn 에 서서 생성하면 초반에 잘 나오더군요 ). 




아래 그림은 possession 을 해제하고 찍은 스샷입니다. 이상하게도 빙의를 해제하면, 1인칭 메시도 같이 나오더군요. 이 부분은 왜 그런지 나중에 확인해 봐야겠습니다.




원하는 봇만 생성되기를 원한다면 AUTGameMode::AddBot() 메서드를 수정하십시오.


개요



이 문서는 Beahvior Tree( 이하 BT ) 의 세부적인 구현이나 노드들에서 다루기 위해서 작성된 것이 아니라 전반적인 개념 및 흐름을 정리하기 위해서 작성되었습니다. 그러므로 BT 의 세부적인 동작 방식들에 대해 알고 싶으시다면 가마수트라의 [ Behavior trees for AI: How they work ][ 4 ] 를 읽어 보시기 바랍니다( 하지만 안타깝게도 영문입니다 ).


개념



BT 를 이야기하기 위해서는 유한 상태 기계( Finite State Machines, 이하 FSM )에 대해서 언급하지 않고 넘어 갈 수 없습니다. 


FSM 은 특정 유형의 로직을 제공합니다. 이는 상태( state )와 전이( transition )으로 구성됩니다. 상태는 동시에 실행되는 행동( action )의 집합입니다. 행동의 예를 들면 애니메이션, 사운드, 특정 시간동안 대기 등을 들 수 있습니다. 전이는 조건( condition )을 포함합니다. 전이의 조건이 충족되면, 상태는 다른 상태로 이동하게 됩니다.


게임에서 이러한 FSM 은 애니메이션 상태를 전환하는 데 많이 사용됩니다. 이러한 FSM 의 한 예는 Unity3D 의 메카님 스테이트 머신( Mechanim State Machine )입니다. 이것을 사용하면 한 애니메이션에서 다른 애니메이션으로 전환되는 로직을 쉽게 작성할 수 있습니다[ 5 ].


출처 : [ 4 ]


게다가 비주얼 디버깅( visual debugging )도 매우 쉽습니다. 현재 상태를 보여주기 때문입니다.


출처 : [ 5 ]


하지만 이러한 상태들이 매우 많아지게 되면 노드가 매우 복잡해집니다.  




그렇기 때문에 상태를 계층화( 혹은 그룹화)하는 계층적 유한 상태 기계( Hierarchical Finite State Machines, 이하 HFSM )라는 개념이 등장했습니다[ 3 ].


출처 : [ 3 ]


FSM 은 서로 다른 문맥을 가진 로직을 재사용할 수 있는 방법을 제공하지 않지만, HFSM 은 FSM 들을 그룹화하고 계층화함으로써 특정 문맥을 가진 상태를 재사용할 수 있게 해 줍니다. 그리고 FSM 이 그렇듯이 현재의 문맥( 상위 상태 )을 파악하기도 쉽습니다. 그래서 최근까지 게임 AI 에서 많이 사용되던 방식입니다.


그런데 이 HFSM 도 문제가 있습니다. HFSM 이 어느 정도의 확장성을 가지기는 하지만, ( 하위 ) 상태를 모듈화하는 기능을 제공하지는 않습니다. 예를 들어 같은 상태를 다른 문맥에서 사용할 수는 없습니다. 왜냐하면 특정 상태에서 전이되어야 한다는 조건이 붙어 있기 때문입니다.


좀 더 실용적인 예를 들어 보도록 하겠습니다. 여러분이 "걷기" 상태를 가지고 있다고 합시다. "걷기" 상태는 "전투" 상태의 하위 상태도 될 수 있지만, "추적" 상태의 하위 상태도 될 수 있습니다. 만약 HFSM 을 사용한다면 "전투" 상태에 "걷기" 상태를 추가하고, "추적" 상태에도 "걷기" 상태를 추가해야 합니다. 물론 각 문맥에서의 ( "걷기" 상태로의 ) 전이 조건은 서로 다르겠죠.


그래서 같은 상태를 재작성하지 않고도 다른 목적이나 상황에 따라 상태를 재사용할 수 있도록 하기 위한 목적을 가지고 행동트리( Behavior Tree )라는 것이 생겨났습니다[ 1 ].


BT 는 로직을 캡슐화함으로써 상태의 모듈성을 증가시킵니다. 예를 들면 내포된 상태( 하위 상태 )를 만드는 것이죠. 이는 HFSM 에서도 제공하고 있습니다만, 전이라는 것이 존재하지 않는다는 차이점을 가집니다. 그래서 상태는 그 자체로서 존재할 수 있습니다.


출처 : [ 1 ]


Behaviour Tree 작동 원리



이 부분은 자료구조에 대한 이해가 필요합니다. 일반적으로 BT 를 구현하기 위해서는 스택( Stack )이라는 자료구조를 사용하게 됩니다. 이것은 전형적인 후입선출( Last In First Out ) 방식의 자료구조입니다. 이를 간단하게 도식화하면 다음과 같습니다.


출처 : [ 6 ]


스택에 대해서 언급한 이유는 나중에 언급할 BT 노드들이 동작하는 방식을 이해하는 기반이 되기 때문입니다.


BT 는 태스크( Task ) 집합으로 구성됩니다. FSM 류에서는 행동 집합을 상태라고 하고 상태가 다른 상태로 넘어 갈 수 있는 방향 및 조건을 지정하는 것을 전이라 표현했습니다. 하지만 BT 에서는 모든 것을 노드로 표현합니다.


BT 구현에 따라서 조금씩 다르지만 태스크의 종류는 크게 Composite, Decorator, Condition, Action 으로 나뉩니다. Action 은 단말 태스크로서 FSM 의 행동 집합으로써의 상태에 가깝다고 보시면 됩니다. 보통 태스크와 노드( node )라는 용어를 같은 의미로 사용하는 경우가 많으므로 헷갈리지 않기를 바랍니다.


Action task


Action task 는 실제 행동을 표현하는 단말 노드입니다. 이것은 항상 true false 를 반환하게 되어 있습니다. 일반적으로는 Action.OnStart(), Action.OnUpdate(), Action.OnEnd() 같은 메서드를 가지고 있는데, Action.OnUpdate() 에서 true false 를 반환하면 그 Action 의 작업이 끝납니다. 메서드의 이름은 구현마다 다를 수 있습니다.


스택에 처음 올라갈 때 OnStart() 가 불리고, truefalse 를 반환하지 않으면 계속해서 OnUpdate() 가 불립니다. 그러다가 truefalse 가 반환되면 스택에서 빠지면서 OnEnd() 가 불립니다. 어떤 구현들( UE4, ParadoxNotations 의 NodeCanvas 등 )에서는 EndAction() 과 같은 메서드를 명시적으로 호출해서 Action 을 끝내기도 하고, 어떤 구현들( BehaviorDesigner 등 )에서는 true, falserunning 과 같은 반환값을 기반으로 Action 이 끝났는지 판단하기도 합니다.




Composite task


Composite task 는 우리말로 하면 복합 태스크입니다. 이것은 말 그대로 ( 하나 이상의 ) 여러 개의 자식으로 구성된 태스크입니다. 자주 사용되는 Composite 으로는 Select, Sequence 등이 있습니다. 이러한 Composite 의 핵심 용도는 node 의 flow 를 제어하는 것입니다.


기본적으로 node 의 실행 순서는 위에서 아래로, 왼쪽에서 오른쪽으로입니다.


Select composite자식 노드가 true 를 반환할 때까지 자식 노드들을 실행합니다. 말 그대로 하나를 선택하는 것이죠. 참고로 스샷은 ParadoxNotations 의 NodeCanvas 의 스샷입니다.



위의 Select 를 스택 구조로 도식화하면 다음과 같습니다. 그림이 복잡해지는 것을 방지하기 위해서, OnStart() 에서 바로 EndAction() 을 호출했다고 가정합니다.



다른 것들도 마찬가지로 동작하므로 스택 구조로 도식화하는 것은 여기까지만 하도록 하겠습니다. 


Sequence composite 는 자식 노드가 false 를 반환할 때까지 자식 노드들을 실행합니다. 말 그대로 순차적 실행입니다.



이것들을 잘 조합하면 다양한 로직을 구성할 수 있습니다.



Conditional Aborts


BT 의 단말 노드에 존재하는 Action 이 true 나 false 를 반환하지 않으면 계속해서 그 작업에 머물러 있게 됩니다. 그 Action 의 OnUpdate() 메서드 내부에서 종료 조건을 판단할 수 있으면 좋겠지만 외부에서 강제적으로 그 Action 의 실행을 중단시키고 싶을 수 있습니다. 


예를 들어 "추적" 이라는 Action 은 일반적으로 내부에서 추적이 완료되었는지 여부를 판단하고 있을 것입니다. 예외적인 조건 판단까지 그 Action 에 넣어 버리면 너무 복잡해지고, 다른 Action 에 대한 종속성을 가지게 될 것입니다. 이럴 경우에 "추적" Action 을 취소시킬 수 있는 방법이 있다면 좋을 것입니다. 그런 방법을 조건부 취소( Conditional Aborts )라 부릅니다. 어떤 구현에서는 평가를 재활성화한다( Reactive Evaluation )고 합니다.


조건부 취소는 실행 흐름에 영향을 주게 되므로 Composite 에 기능이 내장되어 있습니다. 어떤 변수를 계속 감시하고 있다가 변수의 값이 바뀌게 되면 지금의 실행 흐름을 취소시키고 자신의 노드로부터 재평가를 하는 것입니다. 


Conditional Aborts 는 보통 Self, Lower Priority, Both 로 이루어집니다. Self 는 자신의 하위에 있는 태스크를 취소시키는 것이고, Lower Priority 는 자신의 오른쪽에 있는 이웃 노드의 흐름을 취소시키는 것입니다. 그리고 Both 는 Self + Lower Priority 입니다. 여기에서 Lower Priority 라는 의미를 이해하기 힘든 분이 있을 수 있습니다. Lower 라는 이름이 붙은 이유는 BT 의 실행 흐름이 왼쪽에서 오른쪽으로 이어지기 때문입니다.


간단한 예를 들어 보도록 하겠습니다. 일단 NodeCanvas 의 경우에는 Composite 에 Dynamic 이라는 속성이 있습니다. 이것은 Conditional aborts on Self 를 의미합니다. UE4 나 BehaviorDesigner 는 Self, Lower Priority, Both 를 모두 가지고 있습니다. 어쨌든 계속해서 실행되는 어떤 Action 이 있다고 합시다. 아래 BT 에서는 "B" Action 을 실행한 후에 "Run Forever" 라는 Action 으로 제어가 넘어 갔기 때문에, "B" Action 은 앞으로 절대로 평가되지 않습니다.



그런데 특정 조건이 만족되면 다시 Sequece Composite 를 평가하고 싶다면 어떻게 해야 할까요? 이럴 때 Sequencer 노드를 dynamic 으로 변경하고, 하위에 Condition 노드를 추가해 Conditional Aborts 상황을 만들 수 있습니다. 형태는 다음과 같습니다.



이제 Cancel 이라는 변수에 false 를 할당하면, Sequencer 노드가 이를 감시하고 있다가 "Run Forever" Action 을 취소하고 다시 자신의 노드를 평가합니다. 참고로 취소될 때는 "Run Forever" 의 OnEnd() 가 호출됩니다.



여기에서 "Sequencer 가 첫 번째 노드에서 false 를 반환해서 멈춰버리네?" 라는 의문을 가지는 분이 계실 겁니다. 이런 사태에 대비해서 모든 Action.OnEnd() 안에서 Cancel = true 로 만들어 주는 방법이 있고, Condition 앞에서 true 로 만들어 줄 수도 있습니다. 어떤 방법을 선택하느냐는 취향의 문제입니다. 심지어는 Sequencer.OnUpdate() 에서 true 로 만들어 줘도 되겠죠.



그냥 순차적으로 실행되는 것이라고 생각하면 의미가 모호하지만, 이것의 실행 문맥( 스택이 rewind 된 것임 )을 잘 생각하면 문제가 없습니다.


참고로 NodeCanvas 같은 경우에는 Dynamic Composite 을 계층적으로 사용하면 Both 와 같은 Conditional Aborts 를 처리하는 것도 가능합니다. 그냥 Composite 에서 세 종류를 모두 설정할 수 있었으면 좋았겠지만 그 부분이 아쉽습니다.


Decoration task


Decoration task 는 조건을 의미합니다. Decoration 은 하나의 자식만을 가질 수 있는데, 조건을 만족하면 자식을 실행하고, 조건을 만족하지 못하면 false 를 반환합니다. Decoration 이 지정하는 조건을 만족했을 경우의 반환 결과는 자식의 반환 결과에 의존합니다. 자주 사용하는 Decoration 에는 Probability, TimeOut, CheckEvent 등이 있습니다. 


예를 들어 "B" Action 과 "C" Action 의 실행 확률을 결정하고 싶다고 합시다. 그러면 Probability task 를 사용해 다음과 같이 할 수 있습니다. 



참고



[ 1 ] Understanding Behavior Trees.

[ 2 ] On Finite State Machines and Reusablility.

[ 3 ] The Gist of Hierarchical FSM.

[ 5 ] 스테이트 머신 기초.

[ 6 ] Stack Data Structures.

개요



Example_Map 을 플레이하게 되면 게임모드와 캐릭터가 생성되는 것을 볼 수 있습니다. 여기에서, 경험자라면 프로젝트 세팅을 떠 올리게 될 테지만, 초보자나 저같이 간만에 UE 를 다시 본 사람들은 혼란에 빠지게 됩니다.


"Edit -> Project Settings..." 메뉴를 클릭하게 되면 "Project Settings" 라는 다이얼로그가 뜹니다. 여기에서 "Maps & Modes" 카테고리를 선택하게 되면 다음과 같은 화면을 볼 수 있습니다.



프로젝트 세팅과 관련한 전반적인 내용은 다음 링크에서 확인하시기 바랍니다.


  • Default Maps
    • Editor Startup Map 은 에디터를 처음 실행할 때 열어 줄 맵을 지정합니다.
    • Game Default Map 은 게임을 실행할 때 열어 줄 맵을 지정합니다. 그러나 PIE( Play In Editor ) 에서 게임을 실행하면 현재 맵에서 게임을 실행합니다.
    • Local Map OptionUEngine::LoadMap() 호출시 넘어 갈 부가인자를 설정합니다. 현재는 "?listen" 을 붙여 listen server 기능을 강제하는 기능이 있다는 것만 알고 있습니다. 자세한 내용은 더 연구를 해 봐야 알 수 있을 것 같습니다.
    • Transition MapSeamless Travel 이 활성화된 상태에서 맵을 전환할 때 중간에 사용되는 맵입니다.
    • Server Default Map 은 서버를 실행할 때 열어 줄 맵을 지정합니다.
  • Default Modes
    • Default GameMode 는 맵의 "World Settings" 에서 "GameMode Override" 를 지정하지 않았을 때, 기본적으로 실행해 줄 게임모드를 지정합니다.
    • Selected GameMode 는 "Default GameMode" 에 선택된 게임모드의 내용을 간략하게 보여 줍니다.
    • Global Default Server Game Mode 는 서버의 게임모드를 지정합니다.
  • Local Multiplayer
    • Use Splitscreen 은 로컬에서 멀티플레이를 실행할 때 화면을 분할할 것인지 여부를 결정합니다.
    • Two Player Splitscreen Layout 은 로컬에서 2 마리에 대한 멀티플레이를 실행할 때 화면을 분할할 레이아웃을 결정합니다.
    • Three Player Splitscree Layout 은 로컬에서 3 마리에 대한 멀티플레이를 실행할 때 화면을 분할할 레이아웃을 결정합니다.
  • Game Instance
    • Game Instance Class 는 게임 인스턴스의 유형을 결정합니다.

UUTGameInstance



UE 4.4 버전부터 GameInstance 라는 개체가 생겼습니다. UE 문서에 따르면 게임인스턴스는 다음과 같은 역할을 합니다.


GameInstance: 실행중인 게임의 인스턴스를 위한 고수준 관리자 개체. 게임 생성시 생성되지만 게임 인스턴스가 닫힐때까지 파괴되지 않습니다. Standalone 게임으로서 실행중일 때, GameInstance 는 하나만 생성될 것입니다. PIE( Play-in-editor ) 에서 실행하면 PIE 인스턴스당 하나씩 생성될 것입니다.


뭔가 설명을 어렵게 해 놨는데, 결국은 게임 그 자체를 의미하게 됩니다. 레벨이 전환되더라도 공유할 수 있는 데이터를 저장할 수 있는 전역 개체입니다.


UE 위키에서 열심히 활동하는 Rama 는 [ Game Instance, Custom Game Instance For Inter-Level Persistent Data Storage ] 라는 아티클에서 다음과 같이 활용예를 들었습니다.


현실적인 예로써, Solus 에는 다른 레벨로 들어 갔을 때도 같은 상태를 유지할 필요가 있는 통신탑( Comms Tower )이 존재합니다. 마치 그것이 엄청나게 먼 거리에서 보이는 것처럼 말이죠.


플레이어는 통신탑의 상태를 발전시키는 행동을 취할 수 있습니다. 그리고 그런 변화는 플레이어가 입장하는 다른 레벨에서도 반영되어야만 합니다.


GameInstance 클래스를 사용하면, 나는 플레이어가 통신탑의 상태에 변화를 줄 때마다 그것을 기록해서, 그 정보를 플레이어가 새로운 레벨에 진입할 때 넘겨줄 수 있습니다. 


UT 의 경우에는 UUTGameInstance 라는 클래스를 기본 게임 인스턴스 클래스로 지정합니다( asset-field 에 클래스가 들어 갈 때는 접두어를 배제한 이름이 들어갑니다. 그래서 실제 클래스는 UTGameInstance 가 아니라 UUTGameInstance 입니다 ).


이 게임 인스턴스 클래스는 다음과 같은 정보를 담고 있습니다:

    • 마지막 플레이한 데모 정보.
    • 매칭 정보.
    • 파티 정보.
    • 세션 정보.


AUTDMGameMode



게임 인스턴스가 게임 자체를 의미한다면, 게임 플레이를 의미하는 것은 게임 모드입니다. 일단 "A" 는 "Actor" 의 머리글자이며, "UT" 는 "Unreal Tournament" 의 머리글자이고, "DM" 은 "Death Match" 의 머리글자입니다. 데스 매치를 위한 게임 모드라 할 수 있습니다. 왜 게임 모드가 액터냐는 질문을 던지신다면야, 실제로 씬에 배치되기 때문이라고 대답하겠습니다. 왜 씬에 배치되야 하느냐고 질문하신다면, 그건 언리얼을 만든 사람의 마음이라 잘 모르겠습니다. 아마도, Unity 3D 처럼, 게임 인스턴스를 제외한 모든 개체는 월드( 씬 ) 단위로 유지되기를 원한 것 같습니다.


어쨌든 게임 모드는 게임에서 사용하게 될 핵심 액터들을 정의하게 됩니다. 각각은 다음과 같은 역할을 수행합니다.


    • DefaultPawnClass AGameMode.DefaultPawnClass 프라퍼티입니다. 아래에서 리스팅된 이름들도 다 마찬가지입니다. 다들 잘 아시겠지만 노파심에 설명하자면, 프라퍼티는 C# 프라퍼티가 아니라 UPROPERTY() 특성 매크로를 지정한 필드를 의미합니다. 이것은 일종의 메타 데이터( metadata )로, UnrealHeaderTool 은 이것을 파싱해서 C++ 클래스로 만듭니다. 어쨌든 DefaultPawnClass 는 게임 모드를 생성했을 때 자동으로 생성할 플레이어를 위한 을 의미하는 클래스입니다.
    • HUDClass 는 게임에서 사용할 HUD 를 지정하는 프라퍼티입니다.
    • PlayerControllerClass 는 플레이어를 위한 컨트롤러를 지정하는 프라퍼티입니다. 그것은 폰과 그것을 제어하는 사람간의 인터페이스를 제공합니다. 플레이어 컨트롤러는 플레이어의 의지( 조작 )를 반영합니다.
    • GameStateClass 는 게임 상태를 모니터링 할 게임 스테이트를 지정하는 프라퍼티입니다.
    • PlayerStateClass 는 플레이어 컨트롤러가 사용하는 플레이어에 대한 리플리케이트 정보를 포함하는 플레이어 스테이트를 지정하는 프라퍼티입니다.
    • SpectatorClass 는 관전모드에 들어 갔을 때 사용할 관찰자를 지정하는 프라퍼티입니다.


이러한 정보들에 대한 더 자세히 알고자 한다면, 공식 문서의 [ 게임플레이 프로그래밍 ] 항목을 참조하시기 바랍니다.


게임 모드들



여기까지 읽으시면 게임 모드가 하나밖에 없다고 착각하실 수 있으실텐데요, UT 에는 수 많은 게임 모드들이 있습니다.



개요


 

UT 는 1인칭 슈팅 게임입니다. 그런데 내 입장에서는 1인칭이지만 적이나 아군 입장에서는 3인칭입니다. 또한 ( 관전모드와 같이 ) 자신을 관찰해야 하는 모드에서는 3인칭으로 보여야 합니다. 그래서 UT 에서 캐릭터는 2 개의 skeletal mesh 와 각각의 mesh 에 할당된 animation blueprint 를 소유하게 됩니다.

 

UT 를 컴파일하고 에디터를 열면 Exmaple_Map 이라는 레벨을 볼 수 있습니다다. 이 레벨에서 Play 를 실행하면, PIE( Play In Editor ) 모드로 게임이 실행되는데, DefaultCharacter 라는 것이 생성되어 있는 것을 볼 수 있습니다.

 

 

플레이중에 화면 바깥으로 나가려면 "ALT + ENTER" 를 눌러야 합니다. "ESC" 를 누르면 플레이가 중지됩니다.

 

어쨌든 월드 아웃라이너( World Outliner )에서 흰색 액터( actor )는 원래 씬에 배치되어 있던 것이고, 노란색( ? ) 액터는 플레이 이후에 생성된 것입니다. 오른쪽에 있는 "Edit DefaultCharacter" 라는 하늘색 링크를 누르면 블루프린트가 뜹니다.

 

 

처음에는 그냥 property-grid( Class Default 탭 )만 나오는데, "Open Full Blueprint Editor" 라고 써진 하늘색 링크를 누르면 전체 블루프린트를 볼 수 있습니다. 그리고 "Parent class" 항목은 이 블루프린트의 부모 블루프린트나 부모 클래스가 무엇인지 알려 줍니다. 이름이 하늘색으로 써져 있으면 블루프린트 애셋이며 흰색으로 써져 있으면 C++ 클래스입니다. DefaultCharacter 의 경우에는 "BaseUTCharacter" 라는 블루프린트를 부모로 하고 있습니다.

 

이제 Viewport 항목으로 이동하면 두 개의 mesh 가 존재한다는 것을 알 수 있습니다; Mesh, FirstPersonMesh. 컴포넌트 뷰( Components )에서 (Inherited)라 되어 있는 것은 C++ 클래스에서 정의하고 있는 컴포넌트들이며 계층구조나 이름을 변경할 수 없습니다.

 

 

BaseUTCharacter 는 AUTCharacter 클래스를 상속합니다. 아래 그림에서는 "Parent class" 항목에 "UTCharacter" 라고만 써져 있는데, 이 클래스는 액터 클래스이므로 "A" 라는 접두어가 붙습니다. 만약 헷갈린다고 생각하시면, 그냥 헤더 파일 이름이라 생각하셔도 좋을 것 같습니다. 클릭하면 실제로 Visual Studio 에서 헤더 파일이 열립니다.

 

 

앞에서 언급하지는 않았지만 DefaultCharacter 블루프린트의 EventGraph 는 텅 비어 있습니다. 하지만 BaseUTCharacter 의 EventGraph 에서는 뭔가 열심히 하고 있습니다. 즉, 현재 DefaultCharacter 는 mesh 와 animation 을 재정의하기 위한 용도로 BaseUTCharacter 를 상속하고 있는 것입니다.

 

일반적으로 언리얼 엔진을 사용할 때는 액터의 구조 및 핵심 기능은 C++ 클래스에서 구현하고, 기본 동작은 블루프린트에서 구현합니다. 그리고 variation 은 블루프린트 상속을 통해 구현합니다.

 

다른 요소들 : Reference Viewer


 

지금까지는 mesh 와 animation 에 대해서만 언급했지만, 이것과 연관된 모든 요소들을 확인하고 싶을 경우가 있습니다. 이 때 사용하는 것이 reference viewer 입니다.

 

애셋 브라우저에서 애셋을 선택한 다음에 마우스 오른쪽 버튼을 클릭하면 context menu 가 나옵니다. 이 중에서 "Reference Viewer..." 라는 항목을 선택하면 참조 그래프가 나옵니다. 열어 놓은 블루 프린트에서 "Asset > Reference Viewer..." 를 선택해도 동작은 같습니다.

 

 

이제 DefaultCharacter 의 참조 그래프를 살펴 보도록 하겠습니다.

 

 

중심에 있는 노드가 "DefaultCharacter" 입니다. 그리고 왼쪽의 노드들이 DefaultCharacter 를 참조하고 있는 애셋들이며, 오른쪽에 있는 노드들이 DefaultCharacter 에 의해 참조되고 있는 애셋들입니다.

 

"Search Depth Limit" 와 "Search Breadth Limit" 를 조절하면 그래프를 모두 볼 수 있습니다. 노드의 가장 아래쪽을 보면 "Collapsed nodes" 라는 노드가 있습니다. 이는 "Search Breadth Limit" 를 늘리면 펼쳐집니다.

 

 

 

다른 노드를 클릭해서 다른 애셋의 참조 그래프를 볼 수 있습니다. 익스플로러에서처럼 좌상단의 좌우 버튼을 눌러 뒤로 돌아 가는 것도 가능합니다.


각 요소들의 세부사항에 대해서는 다른 섹션에서 다루도록 하겠습니다.

[ 게임 개발자를 위한 물리, 2판 ] 책의 45 페이지에서 질량중심에 대해서 다음과 같이 설명하고 있습니다.

 

1차 모멘트를 계산하는 방법은 각 좌표축마다 원점으로부터 질량중심까지의 거리를 구한 뒤, 그 결괏값을 질량에 곱하면 됩니다.

 

이것 때문에 한참 헤맸네요. 일단 질량중심 구하는 식에서 "질량중심까지의 거리"를 구하라고 하는 것부터가 넌센스네요. 적절한 설명이 되려면 다음과 같아야 합니다.

 

1차 모멘트를 계산하는 방법은 각 좌표축마다 원점으로부터 각 원소 질량중심까지의 거리를 구한 뒤, 그 결과를 각 원소의 질량에 곱하면 됩니다.

 

 

개요



언리얼 엔진에서 모듈이라는 개념을 이해하는 것은 매우 중요합니다. 그래서 이 문서에서는 다음과 같은 주제에 대해서 다루고자 합니다.


  • 모듈의 개념.
  • 모듈의 빌드 방식.
  • 모듈 룰 파일.


모듈의 정의


 

언리얼에서의 "모듈"이라는 것은 특정 함수성( functionality )를 제공하는 기능 집합을 의미합니다. 예를 들어 UI 모듈이면 UI 관련 기능 집합을 담고 있는 dll 이라 할 수 있습니다. 아래 그림은 언리얼 엔진이 제공하는 모듈의 예를 보여 줍니다.

 

 

이런 모듈을 만들기 위해서 기존에는 프로젝트를 따로 생성했었습니다. 그런데 언리얼의 경우에는 하나의 프로젝트 내에서 여러 개의 모듈을 생성할 수 있도록 하고 있습니다. 아마도 dll 을 만들기 위해서 프로젝트를 여러 개 생성해야 하고 설정도 해야 하는 불편함을 없애려는 목적으로 그렇게 한 것 같습니다.

 

언리얼에서 한 프로젝트에서 모듈을 여러 개 생성할 수 있도록 해 주는 메커니즘은 NMAKE 입니다. UnrealBuildTool.exe 을 이용해서 모듈 단위로 묶어서 컴파일하고 링크하는 것이 가능하기 때문에, 한 프로젝트에서 여러 개의 모듈 파일( dll )이 나올 수 있는 것입니다.


그런데 도대체 모듈은 왜 구분하는 것일까요? 대부분의 모듈들은 정적으로 임포트되지 않습니다. 왜냐하면 특정 기능집합을 특정 응용프로그램에서는 사용하지 않을 수도 있기 때문입니다. 예를 들어 네트워킹과 관련한 기능이 전혀 없는 응용프로그램에서 그것과 관련한 모듈을 반드시 임포트해야 할 필요는 없을 것입니다.


이러한 모듈 개념은 동적인 로드/언로드/리로드를 가능하게 해 주며, 이런 특성은 플러그인 시스템을 구축하기 위해서 사용되기도 합니다.

 

모듈의 빌드 방식


 

언리얼 엔진에서 모듈은 두 가지 방식으로 빌드됩니다. Modular( 조립식 ) 모드와 Monolithic( 통합식 ) 모드가 있습니다.

 

Modular 모드는 모든 모듈이 개별 dll 로 쪼개진다는 것을 의미하고, Monolithic 모드는 모든 모듈이 정적 라이브러리처럼 하나의 실행파일에 임포트되는 것을 의미합니다. 어떤 모드로 빌드되느냐는 UnrealBuildTool 세팅, 플랫폼, 빌드 환경 설정에 따라 다릅니다.

 

언리얼에서는 빌드를 하기 위해서 타겟 룰이라는 것을 사용합니다. 그러한 타겟 룰의 유형에는 Game, Editor, Client, Server, Program 이 있는데, Game, Client, Server 의 경우에는 Monolithic 을 권장하고, Editor 에는 Modular 를 권장합니다. 그리고 Program 의 경우에는 프로그램의 종류에 따라 다릅니다.

 

그렇다고 Game 타겟 룰은 무조건 Monolithic 이어야 한다는 것은 아닙니다. 이것은 Target.cs 파일을 작성하는 사람의 마음대로 정할 수 있는 것입니다. 예를 들어 TargetRules 클래스는 다음과 같은 가상 메서드를 포함합니다. 이를 재정의하게 되면 Monolithic 모드 실행 여부를 결정할 수 있습니다.

 


기본적인 구현은 이렇습니다. Editor 가 아닌 경우에는 "-modular" 라는 인자를 강제로 지정하지 않으면 Monolithic 모드로 빌드하게 됩니다. Editor 인 경우에는 "-monolithic" 을 지정해야만 Monolithic 모드로 빌드하게 됩니다. 앞의 조건에 해당하지 않으면 무조건 Modular 모드로 빌드합니다.


그런데 어떤 경우에 Modular 모드를 사용하고 어떤 경우에 Monolithic 모드를 사용할까요? Modular 모드를 사용하면 빌드( 컴파일 + 링크 ) 단위를 구분할 수 있다는 장점이 있습니다. 이는 빌드 시간에 영향을 줍니다. 일부 모듈만 수정된 상황이라면 Modular 모드는 그 모듈만을 빌드합니다.

 

모듈 룰 파일


 

Modular 모드로 모듈을 빌드하면 dll 이 생성됩니다. 이 모듈을 컴파일하기 위해 dllexport 지정자가 사용되면, 이 모듈에 접근하기 위해서는 dllimport 지정자가 필요합니다. 만약 한 번이라도 dll 을 만들어 보신 분이라면, 쉽게 이해하실 수 있을 것입니다. 이러한 지정자를 모듈 API 지정자라 부릅니다.


언리얼 엔진 솔루션을 열어 솔루션 익스플로러를 확인하면, 여러 개의 폴더가 있는데, 그 중에 아무 거나 펼쳐 봅시다. 여기에서는 EditorStyle 폴더를 열어 보았습니다.


 

그러면 그 폴더에 EditorStyle.Build.cs 라는 파일이 있는 것을 확인할 수 있습니다. 이것이 모듈 룰 파일입니다. 이 모듈 룰 파일이 있는 디렉토리는 하나의 모듈이라 할 수 있습니다. 모듈 룰 파일에서는 모듈 이름을 지정하고, import 할 다른 모듈을 지정하고, 자신의 프로젝트 내에서 include 할 header 의 경로를 지정합니다. EditorStyle.Build.cs 파일을 살펴 봅시다.



5 라인에서 모듈의 이름을 "EditorStyle" 로 지정해 줍니다. 그리고 PublicDependencyModuleNames, PrivateDependencyModuleNames, PrivateIncludePathModuleNames 등을 지정합니다. 위에서 언급했듯이 외부 모듈 등을 설정해 줍니다. 여러 종류의 다른 리스트들이 존재하지만, 아직까지 모든 리스트의 의미에 대해서 파악하지는 못했습니다. 이게 제대로 정리되어 있는 문서가 없네요. 단지 경험적으로 역할에 대해 대충 추정할 뿐입니다. 이 부분에 대해서는 기회가 되면 따로 정리하거나 문서를 갱신하도록 하겠습니다.


어쨌든 이렇게 모듈 이름이 지정되면 UnrealHeaderTool 이라는 녀석이 자동으로 EDITORSTYLE_API 라는 정의를 생성해 줍니다.


그래서 "#define EDITORSTYLE_API" 라는 것은 아무리 검색해도 찾을 수 없지만, 빌드할 때 자동으로 생성되는 *.generated.h 파일에는 포함됩니다.






개요



UT 를 설치하고 나면 게임을 어떻게 실행해야 하는지 몰라서 답답함을 느끼게 될 것입니다. 이 때 도움을 줄 수 있는 것이 "ServerLaunch.exe" 라는 프로그램입니다.


이 파일의 경로는 "$(SolutionDir)/UnrealTournament/Binaries/ServerLaunch.exe" 이며, 이것을 디버깅하거나 분석할 수 있는 소스 파일 패키지( ServerLaunchSource.zip )도 같은 디렉토리에 들어 있습니다.




이 파일을 실행하게 되면 다음과 같은 윈도우가 뜹니다.



로고 버튼 혹은 LAUNCHER 버튼 : Settings



가장 위쪽에 있는 로고나 LAUNCHER 라는 글자를 클릭하면 Settings 다이얼로그가 나옵니다.



  • "Location of the UE4Editor.exe" 항목은 "UE4Editor.exe" 의 경로입니다. 즉 게임을 실행할 때 "UE4Editor.exe" 를 통해서 실행한다는 의미입니다. 물론 "UE4Editor.exe" 도 "UnrealTournament" 모듈을 포함하기 때문에 게임을 실행하는 데는 문제가 없습니다.
  • "Client IP" 는 클라이언트 프로그램의 IP 인데요, 로컬에서 띄울 것이기 때문에 "127.0.0.1" 로 설정되어 있습니다.
  • "Add Custom Server Command Line" 항목은 서버 실행시에 넘길 매개변수입니다. 어떠한 매개변수가 추가될 수 있는지는 아직까지는 잘 모르겠습니다. 거기까지는 분석을 안 했거든요...
  • "Game Types" 의 의미는 다음과 같습니다.
    • DM : Death Match.
    • TDM : Team Death Match.
    • CTF : Capture The Flags.
  • "Client Resolutions" 는 클라이언트 해상도입니다. 원하는 해상도를 추가하시면 됩니다. 게임 내에서 해상도를 바꿔도 다시 실행했을 때 런처의 설정으로 덮어 써 집니다. 해상도 말고 다른 설정들은 유지됩니다.


참고로 왜인지 모르겠지만 다이얼로그의 크기가 맞지 않아서 "Save" 버튼이 안 나오고 있는데, 현재 그 버튼에 포커스가 가 있으므로 엔터를 치면 "Save" 가 눌립니다. 맘에 들지 않으면 소스를 수정하시면 됩니다. 소스의 윈폼 디자이너에서 다이얼로그 크기를 늘렸다가 다시 줄이면 제대로 나옵니다.


"Single Player" 버튼



"Single Player" 버튼을 누르면 하나의 싱글 모드 클라이언트가 실행됩니다. 다음과 같은 식으로 인자가 넘어 갑니다.


UE4Editor.exe UnrealTournament ?Game=DM?GoalScore=5?TimeLimit=6 -game -log -winx=20 -winy=40 -resx=1600 -resy=900 -consolex=20 -consoley=960


의미를 이해하는 데는 큰 어려움이 없을 거라 생각합니다.


이 모드에서는 "Map To Play" 드롭다운박스에서 선택한 맵을 플레이를 시작하게 됩니다.


클라이언트를 띄우면서 콘솔이 같이 뜨는데, 그건 서버가 아닙니다. 서버는 따로 "Launch Server" 버튼을 통해 띄우게 되어 있습니다.



이 모드에서는 튜토리얼같은 싱글플레이만 즐길 수 있습니다. 멀티 플레이에 입장이 안 되는 건 아니지만, 입장해 봐야 다른 클라이언트가 들어 올 수 없으므로 의미가 없습니다.


현재 초기 맵이 "ShockAttaches" 라는 DM 맵이므로, 초기 화면으로 가려면 ESC 버튼을 누르고 Back 버튼을 누르면 됩니다.



클라이언트가 하나 뜨면 "DESKTOP-XXX" 와 같은 플레이어 아이디가 생성됩니다. 확인해 본 결과 싱글 플레이를 띄우면 항상 같은 아이디를 할당하는 것을 알 수 있었습니다.


이제 "BASIC TRAINING" 과 같은 싱글 모드 contents 를 즐길 수 있습니다. 아까도 말했듯이 멀티 플레이는 들어 가 봐야 의미가 없습니다. 트레이닝 맵에 처음 입장할 때는 텍스쳐 압축같은 것을 하느라 시간이 걸릴 수 있으므로 로그 창을 잘 보고 인내심을 기르시기 바랍니다.


"Launch Server" 버튼



"Launch Server" 버튼을 누르면 서버를 띄우게 됩니다. "Listen Server" 가 선택되지 않았을 때 다음과 같은 인자가 넘어 갑니다.


UE4Editor.exe UnrealTournament ?Game=DM?GoalScore=5?TimeLimit=6 -SERVER -log


그리고 나서 다음과 같이 서버 콘솔이 하나 뜹니다.



하지만 "Listen Server" 에 체크를 하게 되면, 게임을 띄웁니다. 제가 listen server 의 의미는 잘 몰라서 더 이상은 설명드리기 어려울 것 같습니다.


UE4Editor.exe UnrealTournament ?Game=DM?GoalScore=5?TimeLimit=6?Listen=1 -GAME -winx=20 -winy=40 -resx=1280 -resy=720 -consolex=20 -consoley=780 -log


"Connect Local Client" 버튼



"Connect Local Client" 는 "127.0.0.1" 에 접근하는 클라이언트를 "Number of Clients" 에 설정된 개수만큼 띄워 줍니다. 그 서버는 "Launch Server" 버튼을 통해 미리 띄워 둔 서버입니다. 물론 "Listen Server" 에 체크를 해서는 안 됩니다.



Single Player 의 인자와 다른 점이 있다면, "127.0.0.1" 이라는 주소가 들어 가 있다는 것과 클라이언트마다 창 위치를 다르게 한다는 것입니다. 만약 본인이 서버를 따로 구축했다면, 소스 코드에서 이 주소 부분을 수정하면 됩니다. 그렇게 되면 더 이상 "Local" 은 아니겠지만 말이죠.


이 클라이언트들도 싱글모드에서와 마찬가지로 각자 ID 를 할당받게 됩니다.


개요


 

UE4 는 모듈이라는 개념을 사용해서 프로젝트를 관리합니다. 각 프로젝트에는 "*.Target.cs" 라는 파일이 존재합니다. 이는 빌드타겟을 지정하고 있으며, 내부의 SetupBinaries() 메서드에서는 사용하고자 하는 모듈을 지정하게 됩니다.

 

UT 의 UnrealTournament 는 세 개의 빌드 타겟을 가집니다.

 

    • UnrealTournament
    • UnrealTournamentEditor
    • UnrealTournamentServer

 

그 중에서 UnrealTournamentEditor 빌드 타겟은 다음과 같은 모듈들을 포함합니다.

 

 

아래의 섹션들중에서 클라이언트 및 에디터와 관련한 두 모듈에 대해서 설명하도록 하겠습니다.

 

UnrelTournament 모듈


 

이 모듈의 정의파일은 UnrealTournament.Build.cs 입니다.

 

다음과 같은 기능들을 포함합니다. 모든 기능에 대해서 언급하기는 어렵고 관심이 있으신 분들은 관련 모듈 파일들을 살펴 보시기 바랍니다.

 

 

대부분 게임을 구동하는 데 사용하는 모듈들입니다. NetworkReplayStreaming, Json, JsonUtilities 등은 json replay data streaming 을 위해 사용됩니다.

 

 

UnrealTournamentEditor 모듈


 

이 모듈의 정의파일은 UnreaTournamentEditor.Build.cs 입니다.

 

당연한 이야기지만 UnrealTornament 의 기능을 포함하며, 편집을 위한 기능들을 추가적으로 가집니다.

 


+ Recent posts