2017년 9월 29일

언리얼 엔진에서 크로마키 머티리얼 구성

저자: Ryan Brucks

대략 2년 전, 언리얼 엔진 4 앤서헙(AnswerHub)에서 누군가가 머티리얼 내 크로마 키(chroma key - 일명 그린 스크린)에 대해 질문했습니다. 저는 이 포스트로 인해 크로마 키 알파(Chroma Key Alpha)라는 아주 기본적인 크로마 키 함수를 제작해 언리얼 엔진 4에 추가했습니다. 이 함수의 추가 소식도 릴리즈 노트에 있었지만, 우리의 릴리즈 노트는 분량이 상당해서 그 사이에 끼어있는 기능들을 완전히 잊혀지게 만들기 십상입니다. 특히 당장 사용할 이유가 없었던 기능이라면 더욱 그렇습니다.

AR은 지금껏 존재했던 수많은 새 툴 및 디바이스의 지원을 받으며 상승세를 타고 있습니다; 언리얼 엔진 4가 최근 AR킷(ARKit)AR코어(ARCore)에 대한 지원을 시작한 것이 바로 그 증거입니다. 여러분은 팀 스위니가 WWDC에 대해 작성한 포스트에서 위 주제와 더불어 몇 가지 놀라운 프로젝트들에 대해 읽어보실 수 있습니다.

이런 진행이 이루어지고 있으니, 언리얼 엔진 4에서 크로마 키 머티리얼을 구성하는 방법에 대한 몇 가지 사례를 보여드리려면 지금이 적기인 것 같습니다. 대부분의 AR 데모는 디지털 오브젝트를 실제 영상에 합성하는 반면, 일부 프로젝트는 실제 오브젝트를 디지털 화면 속에 포함하는 혼합 현실을 요구합니다. 이런 경우 대개 빌트인 알파가 없을 것이므로 상당히 까다로운 그린 스크린 구성 작업까지 수반됩니다.

그린스크린에서 알파를 추출하는 프로세스를 바로 크로마 키라고 합니다. 최근 언리얼 엔진 4에 추가된 컴포셔 플러그인은 포스트 프로세싱과 렌더링 엘리먼트의 믹스 및 매치를 더 쉽게 해주기 때문에, 실제 크로마 키 머티리얼 사용을 시험해보기 아주 좋습니다.

Unreal+Engine%2FblogAssets%2F2017%2FSEPTEMBER+2017%2FRyan+Brucks+Chroma+Key%2F770_RyanBrucks_GreenScreen_Pic1-770x416-c17605cbdee13943cb7ea4164115badd3b98624b

우선 높은 퀄리티의 크로마 키 결과물을 얻기란 어려우며, 종종 다양한 기술을 병용해야 한다는 점을 미리 짚고 넘어가겠습니다. 누크(Nuke) 같은 수많은 소프트웨어 패키지가 이 부분에 상당히 고급 방법들을 제공합니다. 굉장히 높은 퀄리티의 크로마 키 알파를 얻는데 사용되는 누크의 수많은 기능들에는 복잡한 계산이 필요합니다. 생방송과 같은 특정 프로젝트의 경우에는 값비싼 전용 하드웨어 같은 해결책을 사용하기도 합니다.

즉, 우리가 얻게 될 리얼타임 버전의 알파는 비교적 매우 기본적인 수준이 될 것이란 점을 염두에 두어야 하며, 괜찮은 수준으로 보이게 만드려면 콘텐츠와 관련된 조정이 많이 필요할 것입니다. 그렇더라도 에디터 내에서 크로마 키의 프리비즈 및 테스트가 가능하다는 점의 가치는 상당히 유용합니다.

기본적인 방법론

크로마 키의 개념은 알파 마스크를 생성할 색 비교 마스크를 만드는 것입니다. 그러면 두번째 마스크가 '디스필(despill)'이나 오브젝트로부터 녹색 캐스트를 제거하는데 사용됩니다. 이 디스필 마스크는 대개 알파 마스크 결과물의 좀 더 부드럽고 반전된 버전입니다. 마지막으로 디스필 버전의 마스크는 가짜 앰비언트 라이팅을 추가하고, 녹색 캐스트를 합성될 배경과 알맞은 색으로 대체하는 데 사용할 수 있습니다.

위처럼 비교적 간단한 단계 수행에는 거의 무한한 방법을 사용할 수 있습니다. 제가 만든 첫번째 버전은 상당히 기본적인 것이며 꽤 오랫동안 언리얼 엔진 4에 추가되어 있었습니다. 위에서 언급했듯 이것이 바로 크로마 키 알파이며 그 기본 용례는 다음과 같습니다:

Unreal+Engine%2FblogAssets%2F2017%2FSEPTEMBER+2017%2FRyan+Brucks+Chroma+Key%2F770_RyanBrucks_GreenScreen_Pic2-770x507-8ee15c405eb0a8df8272a7f02c041138653c2c54

이미지 컬러(image color)와 크로마컬러(chroma color) 입력이 각각 하나씩 있으며, 알파(alpha) 및 디스필 마스킹(despill masking) 입력이 몇 개 있습니다. 이 노드를 사용한 사례들만 고수하지는 않고, 이 함수의 각 단계가 어떻게 작용하는지 보여드리고, 또 기본 구성의 더 나은 버전들도 보여드리도록 하겠습니다.

색 추출

색 비교 생성의 첫번째 단계는 이미지에서 휘도를 제거하여 그린 스크린의 미묘한 그림자와 주름, 혹은 라이팅 그레디언트가 방해가 되지 않게 하는 것입니다. 이 함수의 첫번째 버전에서는 간단하게 색을 정규화 했었습니다. 이 방법은 그런대로 잘 작동했었지만, 결과물에 에지 아티팩트(edge artifact)가 좀 생겼습니다.

밝기를 제거하는 또 다른 방법은 그냥 컴포넌트의 합계로 나누는 것입니다. 그러면 괜찮고 균등한 톤을 얻을 수 있지만, 플로팅 에지 헤일로 아티팩트(floating edge halo artifacts)가 생기곤 합니다. 저는 포토샵(Photoshop)의 색 레이어를 사용하면 그런 헤일로 아티팩트가 생기지 않는다는 사실을 깨닫고, 이것을 없앨 수 있는 방법을 생각해보기로 했습니다.

그 답은 휘도 기반 채도를 사용해 아주 어둡게 탈색이 된 픽셀이 컬러 맵에서 탈색이 되지 않도록 방지하는 것이었습니다. 알고 보면 이렇게 어둡게 탈색된 픽셀은 바이큐빅 텍스처 리사이징(bicubic texture resizing)에서 나온 것입니다.

테스트 이미지는 TV 프로 로스트 인 타임(Lost in Time)의 한 장면으로, 언리얼 엔진 4를 렌더링 씬으로 사용한 것입니다. 이 테스트 이미지는 그렇게 퀄리티가 높지는 않은, 저퀄리티의 패스드 다운(passed down) jpeg 소재란 점을 염두에 두시기 바랍니다.

Unreal+Engine%2FblogAssets%2F2017%2FSEPTEMBER+2017%2FRyan+Brucks+Chroma+Key%2F770_RyanBrucks_GreenScreen_Pic3-770x809-d21f1752a15e8d6da65efa9656e75e688c25e75e

휘도 기반 채도 맵을 생성하려면, 먼저 이미지가 탈색되고, e ^ -x라는 간단한 지수 함수를 사용해 휘도 커브가 생성됩니다. 휘도값 x는 휘도 마스크의 세기를 정의하는 파라미터에 의해 조정됩니다. 정규화가 되었으므로 1이 좋은 기본값이며 0은 합계로 나눈 버전과 정확히 같은 결과를 냅니다. 다음은 이 기능을 위한 코드입니다:

float3 ExtractColor(float3 Color, float LumaMask)

 

{
	float Luma = dot(Color, 1);
	float ColorMask = exp(-Luma * 2 * PI / LumaMask);
	Color = lerp( Color, Luma, ColorMask);
	return Color / (dot(Color, 2));
}

 

일단 컬러 맵을 추출했다면, 다음 단계는 비교를 해서 마스크를 생성하는 것입니다. 이번 단계는 꽤 간단합니다. 우선 크로마컬러(ChromaColor)는 반드시 같은 익스트랙트컬러(ExtractColor) 함수를 거쳐야 합니다(만약 사용될 경우 정규화 등을 거칩니다). 그러면 컬러맵과 크로마컬러 간의 차이점을 구할 수 있습니다. 그러면 이 차이점의 길이가 계산되고 샤프 마스크가 브로드 그레디언트로부터 추출되어 원하는 특정 오류 범위를 고립시킵니다.

Unreal+Engine%2FblogAssets%2F2017%2FSEPTEMBER+2017%2FRyan+Brucks+Chroma+Key%2F770_RyanBrucks_GreenScreen_Pic4-770x817-3f4733fa169b4bb447102b78da75d28d91731635

다음은 노드 속에 있는 그 사례와 위에서 언급한 익스트랙트컬러 함수입니다:

Unreal+Engine%2FblogAssets%2F2017%2FSEPTEMBER+2017%2FRyan+Brucks+Chroma+Key%2F770_RyanBrucks_GreenScreen_Pic5-770x246-4cc2fcfc7c1d7786ee9eec54248b86cdff489ef4

위 사례에서 '크로마 알파 스트렝스'를 배수로 사용했다는 점을 명심하시기 바랍니다. 저는 이것이 에지 샤프니스를 보다 직관적으로 명시할 수 있는 방법이라고 생각합니다. 또한 언리얼 엔진 4 패키지 머티리얼 함수에서 최대값과 최소값을 사용해 크로마 알파 스트렝스를 지정했습니다. 결과는 같지만, 이것은 최대값이 언제나 최소값보다 높게 설정되어야 한다는 것을 뜻하므로, 최소값은 일정하게 조정되어야 합니다.

디스필

크로마 키를 사용해 알파 마스크를 추출한 다음은, 남은 픽셀을 디스필하는 중요한 단계입니다. 이는 즉 대상의 실루엣으로부터 모든 녹색 캐스트를 없앤다는 뜻입니다. 이것은 라이팅 및 카메라 모두의 다양한 효과로 인해 필수적입니다. 그린 스크린이 커질수록 서브젝트에 캐스트 되는 녹색 바운스 라이트도 많아집니다. 또한 카메라는 바운스 라이트가 최소로 설정되어 있더라도 밝은 픽셀에서 피사체로 약간의 블룸을 발생시킬 수 있는 여러 렌즈 아티팩트를 포착하는 경향이 있습니다.

디스필을 잘 처리하기 위한 좋은 시작으로는 알파 마스크와 동일한 구성을 사용하는 것이지만, 더 넓은 범위의 값을 사용하면 더 부드러운 마스크를 주게 됩니다. 빌트인 함수에서, 이것은 별도의 디스필 최대값을 노출시키는 것으로 수행할 수 있습니다. 디스필에 사용되는 최소값은 알파에 사용되는 것과 동일할 것입니다.

일단 디스필 알파를 구했다면, 이미지에서 크로마컬러의 캐스트를 제거하는 데 사용할 수 있습니다. 원래는 그냥 디스필 알파를 사용해 탈색을 하지만, 원본 이미지의 크로마컬러와 일치하는 색의 상당 부분을 빼면 더 나은 결과를 얻을 수 있습니다.

Unreal+Engine%2FblogAssets%2F2017%2FSEPTEMBER+2017%2FRyan+Brucks+Chroma+Key%2F770_RyanBrucks_GreenScreen_Pic6-770x821-b4adda5df76b9c6a8443fc1f7f73b7fd5708628f

이것은 디스필 알파가 이미지로부터 크로마 스필을 없애는 데 사용하는 방법의 기본 로직입니다:

Unreal+Engine%2FblogAssets%2F2017%2FSEPTEMBER+2017%2FRyan+Brucks+Chroma+Key%2F770_RyanBrucks_GreenScreen_Pic7-770x253-59f858884bacbec47411b37ea73c6c098e6dd635

이 이미지처럼 훨씬 높은 퀄리티의 결과물은 두 개의 크로마컬러와 두 개의 크로마 키 알파 노드를 사용해 얻은 것이란 점을 명심하시기 바랍니다. 컬러맵은 바닥과 벽의 색깔이 상당히 다르기 때문에, 단일 크로마 비교만 사용할 때는 반드시 훨씬 넓은 경계선을 사용해야만 합니다. 즉 수정하기가 까다로운 모션 블러 레버같은 것을 만드는 에지 소프트니스에서 유연성을 잃는다는 뜻입니다. 2개를 사용하기 위해, 각 알파의 결과가 최소값을 사용해서 결합됩니다. 디스필 알파는 최대값을 사용해 결합될 것입니다.

가짜 바운스 추가는 굉장히 간단합니다. 기본 이미지 색은 직접 명시한 바운스 혹은 배경 색과 병용하기 전에 미리 탈색시켜두는 것이 좋습니다. 여기에는 두 가지 이유가 있습니다. 첫째로, 원본의 기존 캐스트는 전부 없애야 하며, 정말 필요한 것은 휘도 뿐입니다. 둘째로, 대부분의 캐스트는 바라보는 각도로 인해 스페큘러 표면에서 나오며, 모든 비 금속의 경우 스페큘러는 완전히 탈색이 되며 라이팅에 의해서만 색을 얻습니다.

Unreal+Engine%2FblogAssets%2F2017%2FSEPTEMBER+2017%2FRyan+Brucks+Chroma+Key%2F770_RyanBrucks_GreenScreen_Pic8-770x435-d0b0a3de816258b08c660f0ccaaa7f20bb4fe045

전문적으로 합성을 하시는 분들은 탈색 렌더링 된 엘리먼트를 사용해 올바른 라이팅 반응을 얻는 등, 마스크 작업 및 가짜 라이팅 추가에 대해 상당히 자세한 정보를 알고 계실 수도 있습니다. 이 부분은 이 포스팅의 취지에서 살짝 벗어나는 것이기는 하지만, 여러분에게 실제 합성 처리에 접근하는 방법에 대한 아이디어 정도는 제공할 수 있길 바랍니다.

또 다른 사례로, 이번에는 에픽게임즈 영상 제작팀 소속 조 윌슨(Joe Wilson)에게서 받은 더 높은 퀄리티의 이미지를 사용하겠습니다. 이것은 툴 프로그래머 로렌 리지(Lauren Ridge)가 WWDC(이 페이지 맨 위에 링크가 있습니다)에서 선보인 스타워즈 VR 경험(Star Wars VR Experience) 데모를 제작하던 과정에서 촬영된 이미지입니다. 더 높은 퀄리티의 원본이 있다면, 더 나은 결과를 얻을 수 있습니다. 이 예제는 크로마 키 알파의 기존 버전을 사용한 것입니다.

Unreal+Engine%2FblogAssets%2F2017%2FSEPTEMBER+2017%2FRyan+Brucks+Chroma+Key%2F770_RyanBrucks_GreenScreen_Pic9-770x365-fc30c77692da035135bef776aa12ef63d51f31bb

마지막 프레임에 추가된 바운스는 에지 주위 말고는 알아보기가 힘들 수 있으며, 특히 바이브(Vive) 헤드셋 및 컨트롤러와 같은 더 어두운 반사 부위(reflective bits) 상에서는 더욱 알아보기 힘듭니다. 추가 바운스는 하늘의 반사를 이 엘리먼트들에 가져와 합성에 잘 어울리도록 도와준다는 점을 명심하시기 바랍니다.

다음은 위 구성의 전체 머티리얼에 디스필과 바운스/에지블리드 컬러까지 추가한 것입니다:

Unreal+Engine%2FblogAssets%2F2017%2FSEPTEMBER+2017%2FRyan+Brucks+Chroma+Key%2F770_RyanBrucks_GreenScreen_Pic10-770x395-a0d26587038e162706257bc0b89bbdc27e18a215

컴포셔

위에서 컴포셔에 대해 간단히 언급했었습니다. 아직 컴포셔에 크로마 키 모드를 추가하려 해 보지는 않았지만, 몇 가지 사례를 분석한 결과 구성하기도 상당히 간단해 보입니다. 이제 다양한 합성 구성을 처리하는 최종 합성 머티리얼이 있습니다. 사례로 든 프로젝트에서는 모든 컬러마스크가 누크같은 프로그램으로부터 임포트 되었지만, 머티리얼에서의 용도는 여기서 설명한 것과 같은 크로마 키 노드 구성만으로 간단하게 대체할 수 있었습니다.

지금은 여기까지가 전부입니다. 커뮤니티가 혼합현실과 언리얼 엔진으로 과연 무엇을 해낼지 확인하고 싶어 정말 기대됩니다.

--

편집자 각주: 이 블로그 포스트는 원래 라이언의 개인 블로그 ShaderBits.com에 올라왔던 글로, 언리얼 엔진 커뮤니티가 더 폭넓게 접할 수 있도록 알맞은 수정을 거쳐 이 블로그에도 다시 올라오게 되었습니다. 라이언은 트위터(Twitter) 계정 @ShaderBits으로 팔로우하실 수 있습니다.