2016-9-13

언리얼 엔진 4의 노이즈를 활용해봅시다

By Ryan Brucks

언리얼 엔진 4에는 머티리얼을 기반으로 한 프로시저럴 노이즈(procedural noise) 기능이 탑재되어 있지만, 대부분의 사용자들은 퍼포먼스 향상을 위해 이 기능을 제한해놓고 있었습니다. 그 결과 수많은 유저들이 다른 프로그램을 통해 노이즈 텍스처를 타일링한 다음, 이것을 다시 언리얼 엔진 4로 로드해 사용하는 방식을 선호했습니다. 많은 사람들이 이 과정을 언리얼 엔진 4로 처리하고 싶어했지만, 그러기엔 딱히 쉬운 방법이 없었던 것입니다. 

언리얼 엔진 4.13 버전에서 이런 문제가 해결되었습니다. 이번에 이루어진 향상점은 크게 다음과 같이 나눌 수 있겠습니다:

1) 노이즈 타일링(Noise tiling) 옵션
2) 보로노이(Voronoi) 노이즈 새로 추가
3) 퍼포먼스 최적화 및 기타 기능 향상

일단 저와 함께 타일링과 보로노이 옵션을 작업해주신 마크 올라노(Marc Olano) 렌더링 엔지니어 겸 교수님께 감사드리고 싶습니다. 또한 올라노 교수님은 퍼포먼스 향상 및 코드 정리도 맡아주셨습니다. 꽤 많은 옵션들도 최적화되었을 뿐더러, 툴팁들도 상당한 양의 설명들을 보여주게 되었습니다. 그러나 이런 최적화가 큰 도움이 되기는 했지만, 아직 프로시저럴 노이즈 대다수는 그냥 렌더링하기에는 부담이 됩니다. 따라서 저희는 먼저 고정 텍스처를 만들 수 있는 타일링 노이즈 옵션부터 이야기해보도록 하겠습니다. 마지막 문단에서는 다양한 노이즈 함수의 상대적인 부하 수준에 대해서도 알아보겠습니다.

타일링 노이즈

4.13 버전에서는 머티리얼 내에 노이즈 노드(Noise node)를 놓고 선택할 경우 화면 하단에 타일링(Tiling)과 리피트 사이즈(Repeat Size)라는 새로운 옵션이 뜨는 것을 볼 수 있습니다.

noiseNode

타일링에 체크가 되어 있다면, 노이즈는 지정된 리피트 사이즈(영역)만큼 반복됩니다. 만약 타일링 노이즈를 굽고 싶다면 매우 간단히 구성할 수 있습니다. 리피트 사이즈를 굽고 싶은 샘플의 사이즈와 맞추면 되는데, 가장 간단한 방법은 인풋 포지션(input Position)을 그냥 기본 설정인 0-1 텍스처 좌표(Texture Coordinates)에 맞춘 다음, 스케일(Scale)과 리피트 사이즈를 위의 샘플 이미지와 맞춰주면 됩니다.

포지션(position)에 기본 설정인 0-1 UV를 사용하는 이유는, 렌더링 엔지니어인 Daniel Wright가 제공해주신 Draw Material to Render Target(머티리얼을 렌더 타겟에 그리기) 기능을 사용하여 텍스처를 구울 수 있도록 하기 위해서입니다. 이번 포스트에서 보여드리는 활용안은 그저 맛보기만 보여드리는 것뿐입니다. 일단 아래의 설정을 한 번 해두면, 다음에 비슷한 작업을 할 때에도 언제든 활용할 수 있으니 잘 배워두시기 바랍니다.

먼저 콘텐츠 브라우저에서 새로운 액터 블루프린트를 만들어야 합니다. 신규 추가를 클릭하고 블루프린트 클래스로 갑니다. 새 대화창이 열리면, 액터를 선택하고 애셋의 이름을 지어줍니다.

그 다음, 콘텐츠 브라우저에서 렌더 타겟을 만들어야 합니다. 신규 추가를 클릭하고 머티리얼&텍스처를 선택한 다음, 렌더 타겟을 클릭합니다. 새로 만들어진 렌더 타겟을 더블클릭한 후 해상도를 굽고 싶은 크기로 설정합니다. 이제 거의 끝났습니다!

이제 새로 추가된 블루프린트를 찾아 이벤트 그래프로 이동합니다. 커스텀 이벤트를 만든 다음 "Bake"라고 이름을 지어줍니다. 굽고 싶은 머티리얼과 방금 만든 렌더 타겟을 지정합니다. 

이제 컨스트럭션 스크립트(Construction Script)로 이동해 커스텀 이벤트 Bake를 불러옵니다.

bakeNode

constructionNode

블루프린트를 컴파일 하셨다면, 이제 머티리얼을 렌더 타겟에 작성할 수 있습니다. 그냥 렌더 타겟을 우클릭하신 다음 스태틱 텍스처 생성을 선택하면 텍스처가 만들어질 것입니다.

createStaticTex

보로노이 노이즈(Voronoi Noise)

보로노이 노이즈는 뭉게구름이나 부식된 표면 등 다양한 자연 효과를 표현하는 데에 아주 좋습니다. 월리(Worley) 또는 셀룰러(Cellular) 노이즈라고도 불리나 기능은 모두 똑같습니다. 바로 활용할 수 있는 기능은 다음과 같습니다.

voroniNoise

좌측부터 각각
1) 1 옥타브(Octave), 제곱(Power) = 2
2) 1 옥타브, 반전 (1-x)
3) 3 옥타브, 반전

다음 사진은 언리얼 엔진 4의 보로노이 노이즈만으로 그려낸 쩍쩍 갈라진 사막의 표면입니다.

crackedFloor1

crackedFloor2

위 사진은 다음과 같은 방법으로 만들어졌습니다.

noiseBreakdown

좌측부터
1) 원본 보로노이 노이즈(Raw Voronoi noise), 1 옥타브, 반전
2) "그레디언트(Gradient)" 노이즈를 인풋 포지션에 추가한 다음 왜곡을 가한 보로노이 노이즈
3) 에지 디테일(edge detail)을 이퀄라이즈(equalize)한 "하이패스(High Pass)" 머티리얼로 샘플링한 보로노이 노이즈
4) Normal from Heightmap (하이트맵에서 노멀 구하기) 함수로 노멀맵 생성

마지막 모래 이미지는 위의 3번 단계에서 만들어진 텍스처를 패럴랙스 오클루전 매핑(Parallax Occlusion Mapping) 머티리얼의 하이트맵(heightmap)으로 사용해 만들어졌습니다.

"하이패스는" 새로운 머티리얼 함수인 “하이패스 텍스처(High Pass Texture)”를 활용해 만들어졌습니다. 에지 베리에이션(Edge variation) 효과는 그레디언트 노이즈를 또 하나 추가하여 오프셋의 폭을 다변화시키는 것으로 얻어냈습니다. 이 버전의 하이패스 함수는 텍스처를 기대하므로, 이 시점의 텍스처를 저장하여 다음과 같이 사용하도록 했습니다.

materialSetup

텍스처보다 함수가 편한 분들을 위해, 텍스처 대신 함수를 받는 "하이패스 함수"버전도 있습니다.

노멀 텍스처를 구우려면 그냥 위의 3단계에서 만든 결과물을 렌더 타겟으로 구워, Normal From Heightmap 함수를 쓴 다음 이 머티리얼을 다시 렌더 타겟으로 렌더링합니다.

normalFromHeightMap

참고로 하이패스 오프셋을 줄이거나 하이패스 강도(strength)를 늘이는 아주 사소한 조정만으로도 이 정도 수준의 텍스처 베리에이션이 가능합니다.

caustics

다음은 뭉게뭉게 피어오르는 연기 기둥의 샘플입니다.

smokeyPillar

이 효과는 2가지의 단순한 보로노이 텍스처를 패닝 텍스처(panning textures)로 샘플링하여 만들어졌습니다. 두 텍스처를 곱한 뒤 제곱근을 구해 뭉게뭉게 솟는 모양을 유지하도록 처리하여 테셀레이션 실린더 메시(tessellated cylinder mesh)에 적용시킨 것입니다. 최종 하이트에 월드 스페이스 노멀을 곱한 뒤, 월드 포지션 오프셋에 연결된 것을 볼 수 있습니다. 

materialSetuo

다음은 보로노이를 기반으로 만든 대리석 텍스처입니다.

voroniMarble

이 텍스처는 보로노이 텍스처를 기반으로 다음과 같은 과정을 통해 만들어졌습니다. 

voroniMarbleWorkflow

좌측부터 각각
1) 표준 보로노이 노이즈, 1 옥타브
2) 보로노이에 "그레디언트" 노이즈를 인풋 포지션에 추가한 다음, 0.05로 설정
3) 그레디언트 노이즈에 0.3을 곱한 다음 보로노이 인풋 포지션에 추가
4) 3단계에서 얻은 결과물을 엔진 컨텐츠에서 나온 무작위 텍스처의 텍스처 좌표(texture coordinates)로 사용

Texture2D'/Engine/Engine_MI_Shaders/T_Base_Tile_Specular.T_Base_Tile_Specular'

이것은 그레디언트 매핑이라 알려진 기법입니다. 정확한 색상의 범위는 텍스처에 입력하기 전에 결과물을 더하거나 곱하여 설정할 수 있습니다. 자신이 사용하고 싶은 색상을 임의로 정해 입력하거나, 원하는 이미지를 아무거나 불러와 해당 이미지에 있는 색상을 끌어다 쓸 수도 있습니다. 

marbleMaterial

이 예제들은 인풋 포지션의 왜곡만으로 얻어낸 변화입니다. 위 이미지를 통해 알 수 있듯이 대각선 줄무늬 패턴입니다. 대리석을 만들 때에는 완벽하지만, 다른 효과를 넣고 싶다면 다른 노이즈 패턴을 X와 Y에 넣고 왜곡을 하거나 노멀 맵을 사용하는 오프셋을 활용하시면 됩니다.

보로노이 노이즈에 걸리는 부하

보로노이 노이즈는 사양이 높으며, 현재 퀄리티 수준은 4단계로 나누어져 있습니다. 각 단계는 구성된 셀의 숫자를 기준으로 나눈 것입니다. 퀄리티가 높아질수록 각진 부작용의 수는 줄어듭니다. 노이즈 노드를 배치할 때에는 기본값으로 6옥타브가 설정되어 있지만, 인스트럭션(instruction) 수는 한 옥타브에 대해서만 확인할 수 있다는 점 명심해주시기 바랍니다.

퀄리티 1, 8셀, 옥타브당 최대 160 인스트럭션
퀄리티 2, 16셀, 옥타브당 최대 320 인스트럭션
퀄리티 3, 27셀, 옥타브당 최대 540 인스트럭션
퀄리티 4, 32셀, 옥타브당 최대 640 인스트럭션

참고로 일반적인 머티리얼의 인스트럭션 수는 100 정도입니다. 6옥타브와 퀄리티 4의 보로노이 노이즈로 구운 머티리얼은 거의 3800 인스트럭션에 달하며, 일반적인 렌더링에 비해 30배 이상 부하를 더 주게 됩니다. 1옥타브와 퀄리티 1의 보로노이 노이즈의 경우에는 인스트럭션 수가 겨우 160이라, 기본 머티리얼에 비해서도 합리적인 수준입니다

octaves

좌측부터 차례로
1) 퀄리티 1
2) 퀄리티 2
3) 퀄리티 3
4) 퀄리티 4

퀄리티 2의 경우 다른 퀄리티들에 비해 좀 어두워보입니다. 이는 2x2x2 그리드로 되어있는 오프셋을 2개 사용하여 좀 더 높은 밀도를 보여주기 때문입니다. 이 경우 2를 곱해주면 쉽게 해결할 수 있습니다.

퍼포먼스 특징

노이즈 노드를 사용할 때 걸리는 실질적인 부하를 보여드리기 위해, 풀스크린 쿼드(quad)를 사용하여 1~6옥타브에서의 함수 부하를 측정해 보았습니다. 또한 일반 텍스처 샘플과의 비교도 추가했습니다. 일반적인 텍스처 샘플에도 옥타브 샘플을 추가했습니다.

noisePerformance

예상대로 대부분의 노이즈 옵션들은 단순한 텍스처 묘사에도 퍼포먼스를 심각한 수준으로 느리게 만들었습니다. “패스트 그레디언트(Fast Gradient) - 3D 텍스처”는 볼륨(volume) 텍스처로 구워졌기 때문에 노이즈 함수 중에서도 가장 빠릅니다. “텍스처를 기반으로 한” 경우에는 2D 노이즈 텍스처로 3D 샘플링을 뜨기 위핸 무작위 연산과 추가적인 계산을 수행하여야만 합니다. 따라서 프로시저럴 노이즈(procedural noise)를 사용하면서 동시에 씬 렌더링을 빠르게 하려면, 현재로써는 “패스트 그레디언트(Fast Gradient)”가 최선이라고 할 수 있습니다. 하지만 너무 넓은 영역에 사용하거나 타일링이 너무 크게 할 경우 반복 현상이 나타난다는 점 유념해 주시기 바랍니다.

보로노이 노이즈 함수의 퀄리티가 높아질수록 부하도 심해집니다. 따라서 퍼포먼스가 제한되어 있는 환경에 적용시키고 싶다면, 반드시 텍스처로 먼저 구워야 할 것입니다.

이 정보가 여러분의 프로젝트에서 실제로 노이즈를 활용할 때 좋은 정보로 사용되었으면 좋겠습니다.

Recent Posts

2018년 4월 NVIDIA Edge 프로그램 수상자

4월에도 NVIDIA Edge 프로그램에 멋진 작품들이 많이 제출되었으며, 그 중에서 세 개의 작품을 뽑아 수상작으로 선정하였습니다. ...

언리얼 엔진으로 BMW 차량 디자인에 혼합 현실 구현

리얼타임 기술과 VR이 자동차 제조의 새로운 시대를 열고 있는 가운데, 자동차 디자인 분야는 빠르게 변화하고 있습니다. BMW와 MIN...

스모 디지털이 말하는 닌텐도 스위치 게임 출시하기

언리얼 엔진으로 Snake Pass 를 개발한 스튜디오가, 닌텐도 스위치 플랫폼으로 게임을 발매하는 것에 대해 이야기합니다.