미싱 텍스쳐(Missing Texture)에 대한 이야기

ounols·2021년 11월 20일
0

CSEngine 프로젝트

목록 보기
8/17
post-thumbnail

🤔 왜 Missing Texture 인가요?

언리얼에서의 미싱 텍스쳐유니티에서의 미싱 텍스쳐

머테리얼이 깨지거나 텍스쳐가 사라진 경우엔 위와 같이 미싱 텍스쳐가 씌워지는 모습을 많이 보셨을 겁니다.
만약 여기서 '왜 미싱 텍스쳐가 나타날까요?' 라고 물으면 당연하게 '텍스쳐나 머테리얼이 없어서요!' 라고 답할 수 있습니다.

하지만 여기서는 이런 단순한 문제를 넘어 '왜 하필 미싱 텍스쳐를 보여줄까?'를 알아보도록 하겠습니다.

😮 미싱 텍스쳐가 가지는 의미

미싱 텍스쳐가 가지고 있는 의미는 이미 다들 아시다시피 텍스쳐나 머테리얼을 찾을 수 없다는 표시를 하기 위한 UX적인 의미가 있습니다. 다시 말하면 개발자가 텍스쳐의 누락을 빠르게 눈치챌 수 있도록 UX를 설계했다고 할 수 있습니다.

그런데 이보다 더 근본적인 렌더링 파이프라인에서의 의미가 존재했습니다!

😕 미싱 텍스쳐는 최소한의 예외처리?

위 사진은 하프라이프 알릭스(Half-Life: Alyx)라는 VR게임 입니다.
일부 텍스쳐가 깨졌지만 그래도 빛 계산은 정상적으로 작동하여 오브젝트의 메인 텍스쳐만 존재하지 않는 것 처럼 보입니다.

여기서 만약 미싱 텍스쳐 조차 존재하지 않고 렌더링을 시도한다면 어떻게 될까요?
GLSL 기준으로 텍스쳐(sampler2D 등)가 존재하지 않는다면 렌더링이 되지 않습니다!

🤨 GLSL에서 sampler2D가 존재하지 않는다면?

이 링크는 GLSL에서 sampler2D가 절대 비어있지 않도록 해야한다는 답변이 달린 질문 글 입니다.

여기에 채택된 답변을 유심히 읽어봐야 하는 부분이 바로 해당 텍스쳐를 읽을지 여부를 따로 전달하면서, 텍스쳐를 비어있는 상태로 절대 두지마라 입니다.

저는 제 엔진에 텍스쳐를 읽을지에 대한 여부만 판단하고 텍스쳐가 없으면 그냥 알아서 코드도 돌지 않을테니 괜찮을 것이라고 생각했었습니다. 그러나 glsl은 예외처리를 할 수 없다면서 렌더링이 아예 되지 않았습니다!

사실 지금까진 텍스쳐 사용 여부를 확실한 조건문으로 해결했기 때문에 쉐이더 컴파일 시 관련 코드를 아예 생략해버렸기 때문에 문제가 발생하지 않았지만
uniform 형태로 받아온 데이터로 조건문을 사용하니 쉐이더 컴파일 시 관련 코드도 컴파일 되면서 렌더링이 불가능한 형태로 나타나게 되었습니다.

아래의 쉐이더 코드를 통해 제가 무슨 말을 하는건지 알아보도록 하겠습니다.

렌더링이 불가능한 문제의 코드

/** 디퍼드 렌더링의 픽셀 쉐이더 **/

// i번째 광원의 그림자가 활성화 되었는지 여부
if(u_shadowMode[i] == 1) {
    ...
    // 깊이값을 받아오는 코드도 같이 컴파일되므로 렌더링을 시도하면 문제 발생!
    float closestDepth = texture(u_shadowMap[i], projUV).r;
    ...
}

디퍼드 렌더링의 광원 렌더링 단계에서 위와 같은 문제가 생겨버렸으므로 디퍼드 렌더링 자체가 렌더링 되지 않는 모습이 나타나고 있습니다!
그나마 다행인 점은 지오메트리 렌더링 단계는 멀쩡하게 되었기 때문에 깊이버퍼는 정상적으로 작동하여 포워드 렌더링에 깊이값이 적용된 모습을 볼 수 있습니다.

이처럼 컴파일은 정상적으로 되지만 렌더링을 진행하면 문제가 생기는 고질적인 문제가 존재합니다.

정상적으로 렌더링 된 코드

/** 디퍼드 렌더링의 픽셀 쉐이더 **/

// 변하지 않는 확실한 조건문이므로 코드가 컴파일되지 않습니다.
if(false) {
    ...
    // 문제의 코드는 알아서 생략되어 정상적으로 렌더링 됨
    float closestDepth = texture(u_shadowMap[i], projUV).r;
    ...
}

아이러니하게도 문제의 코드는 생략되어 컴파일 된 쉐이더 입장에선 전혀 문제가 없으므로 정상적으로 디퍼드 렌더링이 진행됩니다.

어쨌든 결국엔 저 코드에선 i번째의 광원이 그림자 텍스쳐를 가지고 있는지를 판단해야하기 때문에 u_shadowMap이라는 2D 텍스쳐 변수에 미싱 텍스쳐를 대신해서 넣는 것이 가장 베스트가 되겠습니다!

🧐 결론

디퍼드 렌더링이 기본인 언리얼에서 텍스쳐가 없더라도 빛 계산은 정상적으로 된 모습포워드 렌더링인 하프라이프 알릭스에서 광원 텍스쳐가 없더라도 빛 계산이 깨지지 않고 제 역할을 하는 모습

미싱 텍스쳐는 아예 렌더링이 되지 않을 문제를 어느정도 잡아주어 누락된 텍스쳐를 제외한 나머지 쉐이더 계산을 최대한 해주는 아주 중요한 역할이라 할 수 있겠습니다.
특히 디퍼드 렌더링은 한번에 모든 라이팅 연산을 하기 때문에 포워드 렌더링보다 치명적이라고 할 수 있을 것 같습니다.

그와 동시에 개발자가 누락된 텍스쳐를 확인할 수 있도록 특별한 형태의 미싱 텍스쳐를 입혀 알아챌 수 있도록 UX를 설계했다는 점에서
렌더링 문제를 예외처리 한 김에 자연스럽게 UX 설계라는 이점도 얻었다고 생각하니 참 신기한 것 같습니다!

유니티는 빛 계산 그런거 없이 그냥 분홍색으로 나오는데요?
제 뇌피셜이긴 한데 아마 개발자가 좀 더 잘 알아볼 수 있도록 일부러 빛의 영향을 받지않는 분홍색의 머테리얼을 대신 쓰는게 아닐까 생각이 듭니다.

참고로 유니티의 이런 개발자 UX 친화적인 사례는 이 곳 블로그에서 한 번 다룬 적이 있습니다!


이제 텍스쳐가 깨져서 분홍빛이 나타나더라도 '엔진이 터지지 않아서 다행이야!'라는 긍정적인 마인드를 가져보는건 어떨까요?

음 다시보니 이건 좀 선넘는 것 같군요... 죄송합니다...😥
어쨌든 지금까지 통해 미싱 텍스쳐가 가지고 있는 의미에 대해 조금 심층적(?)으로 알아보았습니다!

profile
(게임 엔진 프로그래머가 되고싶은) 게임 클라이언트 프로그래머

0개의 댓글