Game Dev – Voxel Horizon 외곽선 처리 개선

현재 외곽선 렌더링에 사용하는 팩터는 normal map이다.
렌더링된 Normal Map에 Laplacian filter를 먹여서 외곽선을 추출한다.
전반적으로 괜찮은 방식이지만 약간 문제가 있다.

첫번째 스샷을 보면 미쿠의 넥타이에는 외곽선이 표시되지 않는다. 왜냐하면 뒤에있는 상의와 normal이 거의 비슷하기 때문이다. Normal.a에 선형 depth값을 넣어도 소용없다. z값의 차이가 너무 작다. 그렇다고 그 차이를 뻥튀기시키면 멀리 떨어진 물체들이 문제가된다.
Diffuse map에서 외곽선을 추출해서 Normal map으로 추출한 외곽선과 섞어주는 방법도 써봤는데 이것도 나쁘진 않지만 특수한 경우, 그러니까 텍스쳐 상에 색차이가 명확할 경우 지저분해보이는 문제가 있다.

어떻게 할까. 일단 넥타이가 어떤 기하구조를 가지고 있는지 보자.

  1. 현재 넥타이 부분은 상반신 오브젝트의 일부이다. 즉 같은 변환계에 속한다.
  2. 넥타이와 상반신의 Material ID (3ds max에서 지정한)는 같다. 따라서 Material로는 구분할 수 없다.
  3. 하지만 삼각형 매시상으로 보면 edge를 한개도 공유하지 않는 분리된 삼각형 집합이다.
  4. 이걸 3ds max에선 element라 부른다…고 기억하고 있다.

모델링 데이터를 이렇게 저렇게 손보면 넥타이 부분에만 외곽선을 줄 수 있도록 아이디를 지정한다든가 하는 방식을 사용할수도 있다. 하지만 그래픽 디자이너가 없어서 모델링 데이터는 손볼수 없다. 아니 손봐서 될 방법은 피해야 한다. 앞으로도 디자이너는 없을테니까.

그래서 다음과 같이 하기로 했다.

  1. 3ds max에서 익스포트 하거나 엔진에서 모델 데이터를 로드할때 삼각형 리스트를 분석해서 element그룹으로 나눈다. 각 element그룹은 한개의 edge도 공유하지 않는 기하구조상 완전 분리된 모델이다.
  2. 버텍스버퍼에 버텍스 데이터를 채울때 Element ID를 써넣는다.
  3. GBuffer를 만들때 추가적으로 8비트짜리 텍스쳐를 하나 만든다 이하 Element ID Map이라 부른다.
  4. 외곽선을 추출할때 Normal Map과 Element ID Map양쪽을 모두 사용하여 외곽선 컬러값을 구한다. max()명령으로 이중 큰 값을 취하고 inverse한다.
    이런식으로…

    LaplColor = max(LaplColor, float3(ElementID_Diff, ElementID_Diff, ElementID_Diff));
    float3	InvLaplColor = 1.0f - LaplColor;
    float	OutLineColor = dot(InvLaplColor, float3(0.333, 0.333, 0.333));
    float4	outColor = float4(OutLineColor,0,0,0);
    

순전히 외곽선 하나 때문에, 그것도 현재 상태에선 넥타이 빼고는 딱히 이상해보이지도 않는데 그놈의 넥타이에 외곽선 하나 그리려고 이렇게까지 해야하나 상당히 고민했다.
무엇보다 기본 렌더링시에 RTV를 3개나 사용하고 싶지 않았다. 하지만 아무리 짱돌을 굴려봐도 이 방법밖에 생각이 나지 않았다. Normal Map의 4채널중 알파채널은 이미 속성값으로 사용중이다. 그러니 별도의 텍스쳐에 ID를 써넣을 수 밖에.

하여간 그렇게 구현해서 일단 잘 돌아간다.
넥타이에 외곽선 나온다. -_-;

스샷의 왼쪽 상단에 사용중인 렌더타겟을 그려주고 있다. 첫번째는 Element ID를 그린 Element ID Map , 두번째는 Element ID Map과 Normal Map을 이용해서 만든 외곽선 텍스쳐이다.

[Normal Map + Depth] – 넥타이 외곽선 안나옴
outline_old_2017_0818

[Normal Map + Element ID Map] – 넥타이 외곽선 나옴
outline_new_2017_0818


답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

%s에 연결하는 중