본문으로 바로가기
반응형

원문링크 : https://bgolus.medium.com/generating-perfect-normal-maps-for-unity-f929e673fc57

2020.2.3일 기사이므로 현재 버젼과 차이가 많을수 있음. 원문의 불필요한 내용은 걷어내고 구글 번역기를 돌려 필요한 사항만 번역.

하이폴 메시와 엔진에서 import 후 메시

The Basis of Tangent Space

문제는 탄젠트 공간 노멀 맵이 작동하는 방식에 있습니다. 특히, 탄젠트 공간 노멀맵의 해당 탄젠트 공간(또는 탄젠트 기준) 부분이 작동하는 방식입니다. 짧은(?)탄젠트 공간(short tangent space)은 노멀맵에서 표현해야 하는 방향을 결정하는 것입니다. 노멀 맵에서 "앞으로", "위로", "오른쪽"의 실제 방향은 대략적으로 텍스처 UV와 버텍스 노멀의 방향입니다.

 

이해해야 할 더 중요한 것은 노멀맵을 하이 폴리 메시에서 로우 폴리 메시로 굽는데 사용되는 프로그램은 노멀맵이 사용되는 프로그램과 정확히 같은 방식으로 탄젠트 공간을 계산해야 한다는 것입니다. 다른 프로그램은 탄젠트 공간을 다르게 사용할 수 있으므로, 메시용으로 베이크된 노멀맵은 프로그램 간에 보편성이 보장되지 않습니다. 동일한 탄젠트 공간을 사용하는 응용 프로그램의 경우에도!

 

Flipping Out Over an Obvious Error(명백한 오류에 대해 뒤집기)

가장 일반적인 오류는 "OpenGL" 대 "Direct3D" 문제입니다. 이것은 각각 "Y+" 및 "Y-" 노멀맵이라고도 합니다. 한 방향으로 생성된 노멀맵은 기본적으로 다른 방향을 사용하도록 설계된 애플리케이션에서 사용되는 경우 제대로 그려지지 않습니다. 

OpenGL 방향을 예상하는 Unity의 Direct3D 방향 노멀 맵
OpenGL 방향을 예상하는 Unity의 Direct3D 방향 노멀 맵

이것은 상당히 직관적입니다. 노멀맵을 굽는 대부분의 응용 프로그램에는 OpenGL/Direct3D간에 전환하거나 Y 방향 설정이 있는 멋진 큰버튼이나 드롭다운 메뉴가 있습니다. 최종 응용 프로그램이 사용하는 방향을 파악하고 그 방향으로 베이킹하는지 확인하면 해결됩니다. Unity는 OpenGL, Y+, 언리얼은 Direct3D, Y-입니다. 노멀맵 텍스처 자체를 보면 쉽게 구별할 수 있습니다. 녹색 채널의 "위"에서 조명을 받는 것처럼 보이면 OpenGL, 아래에서 보면 Direct3D입니다.

 

sRGBeing Funny

또 다른 일반적인 실수는 sRGB 텍스처로 표시된 텍스처를 사용하는 것입니다. 이것은 GPU가 텍스처를 샘플링하는 방식을 변경하여 사람들이 색상 값을 선택하는데 익숙한 sRGB 공간에서 리니어 색상 공간으로 색상 값을 변환하도록 지시합니다. 노멀맵에서는 이것을 원하지 않습니다. Unity에서 텍스처 유형을 "normal map"으로 설정하면 이 옵션이 자동으로 비활성화되지만 "sRGB(색상 텍스처)" 옵션을 끌 수도 있으며 노멀 맵으로 제대로 작동합니다. 역자주. Normal map type이 아닌 RG채널같이 2개의 채널만 사용하는 경우 임의로 sRGB체크를 해제하고 사용해야 합니다.

 

MikkTSpace vs Autodesk

update : 아래 내용은 3ds Max 2020 및 이전 버전에 해당됩니다. 3ds Max 2021의 경우 Autodesk는 MikkTSpace 베이킹에 대한 적절한 지원을 추가했습니다! 자세한 내용은 기사 끝에 있는 응용 프로그램 목록을 참조하십시오.

더 미묘한 문제는 3ds Max 또는 Maya에서 노멀맵을 베이킹하는 경우 Unity에서 항상 틀릴 수 있다는 것입니다. Unreal 또는 실제로 다른 프로그램에서도 잘못될 것입니다. 3ds Max 노멀맵은 Maya에서 작동하지 않으며 그 반대의 경우도 마찬가지입니다! 이러한 각 응용 프로그램은 다른 응용 프로그램과 일치하지 않는 고유한 방식으로 탄젠트 공간을 계산합니다. 

이 경우에 대한 유일한 해결책은 다른곳에서 사용하려는 경우 이러한 응용 프로그램을 사용하여 노멀맵을 굽지 않는 것입니다. 무료가 필요하면 xNormal을 사용하십시오 . 이를 수행하기 위한 업계 표준 도구입니다. 콘텐츠 파이프라인의 다른 곳에서 Substance를 사용하는 경우 이를 사용합니다.

Autodesk 외부의 많은 응용프로그램은 MikkTSpace 라고 하는 탄젠트 공간을 계산하는 특정 방법을 사용하도록 이동했습니다 . Blender, Unity, Unreal, Godot, Marmoset, Houdini, Modo 및 기타 여러 xNormal 및 Substance는 기본적으로 MikkTSpace를 사용하거나 최소한 어떤 방식으로든 지원하여 호환성을 크게 높입니다. 기본적으로 지난 10년 동안 탄젠트 공간 노멀맵이 정기적으로 사용되는 모든 곳에서 기본적으로 업계 표준이 되었습니다.(3DS MAX는 2020버젼 이후)

 

Mesh Exports & Substance Painter

3ds Max 및 Maya의 다른 문제는 메쉬를 익스포트하는 경우 "tangent and binormal"으로 익스포트 할수 있다는 것입니다. 이것은 적절한 MikkTSpace 탄젠트가 아닌 기반이 됩니다. 일부 응용 프로그램은 이를 재정의하고 기본적으로 올바른 MikkTSpace를 다시 계산합니다(예: xNormal, Unity 및 Unreal). 그러나 다른 응용 프로그램은 메시가 탄젠트값을 가지고 있는 경우 그대로 사용하고 메시에 탄젠트 값이 없는 경우에만 MikkTSpace를 계산합니다. 예를 들어 Substance Painter는 탄젠트가 존재하는 경우 메시에 있는 그대로 탄젠트를 사용합니다. 즉, Painter는 3ds Max에서 구운 것과 매우 유사한 노멀맵을 생성합니다! 비슷하지만 정확히 같지는 않으므로 3ds Max로 다시 가져오면 Max에서 구운 것만큼 좋아 보이지 않습니다.

 

MikkTSpace vs MikkTSpace?

다음 문제는 MikkTSpace의 버전이 두 개 이상 있다는 것입니다! 어떤에서 혼란스럽지 않다면 표준이 아닐 것입니다. MikkTSpace는 버텍스당 메쉬에 데이터를 저장하는 방법과 렌더링할 때 데이터를 사용하는 방법을 모두 정의합니다. 모든 MikkTSpace 응용 프로그램은 버텍스 메시 데이터당 동일하게 계산합니다. 그러나 렌더링할 때 해당 데이터사용 하는 두 가지 다른 방법이 있습니다 . MikkTSpace는 UV 방향을 기반으로 버텍스당 탄젠트 벡터와 사인을 계산하는 방법을 정의합니다. 그러나 탄젠트 공간을 사용할 때 바이탄젠트는 버텍스 또는 픽셀별로 다시 계산됩니다. 베이킹과 보기 모두 동일해야 합니다.

xNormal 및 Substance에는 둘 중 하나의 방법을 사용하여 노멀맵을 굽는 옵션이 있습니다. 이러한 옵션은 Substance의 "compute tangent space per fragment"와 xNormal의 "compute binormal in the pixel shader"로 나열됩니다. 레거시가 아닌 SRPs를 사용한다면 둘중하나를 사용해야 합니다.

xNormal “pixel shader binormals” in Unity’s built in forward renderer

이것은 완전히 다른 탄젠트 공간을 사용하는 것과 시각적으로 유사하지만 일반적으로 훨씬 더 미묘합니다. 어떤 면은 큰 보조개가 있는 것이 아니라 노멀이 약간 뒤틀려 있는 것처럼 보일 수 있습니다. 여기에서 해결책은 간단합니다. Unity의 레거시 렌더러를 사용하기 위해 베이킹 할 경우 해당 옵션을 선택하지 마십시오. Unreal 또는 Unity의 HDRP를 베이킹하는 경우에만 확인하십시요.

블렌더와 Unity가 동일하다고 말하는 것들이 많이 있지만 사실 이것은 사실이 아닙니다! Blender는 Unity와 같은 MikkTSpace 및 OpenGL 방향을 사용하지만 Unreal과 같은 per fragment binormal을 사용합니다.

좋은 소식은 현재 LWRP, URP 및 셰이더 그래프 셰이더가 모두 정점당 사용하지만 HDRP의 내장 셰이더는 픽셀당 사용한다는 것입니다. 셰이더 그래프(7.2.0)의 향후 업데이트에서는 픽셀당으로 전환되어야 하며 그 이후에는 URP의 내장 셰이더가 필요합니다. 그리고 해당 경로를 선택하는 경우 사용자 정의 셰이더로 기본 렌더링 경로를 수정할 수 있습니다.

 

Triangulate, Triangulate, Triangulate!

마지막으로 다룰 것은 다른 삼각 측량입니다. 메시를 사전 삼각 측량하지 않고 내보내는 경우 해당 모델을 사용하는 다른 응용 프로그램이 동일한 방식으로 메시를 삼각 측량할 것이라는 보장이 없습니다. 이것은 또한 노멀맵을 깨뜨립니다! 따라서 익스포트 설정의 일부로 또는 삼각 측량 수정자를 사용하여 메시를 삼각 측량해야 합니다.

Substance Painter는 3ds Max에서 쿼드(quard)로 내보낸 메시의 Unity에서 노멀맵을 베이크

이것은 3ds Max에서 구운 노멀맵과 같이 완전히 잘못된 탄젠트 공간을 사용하는 것과 매우 유사하게 나타납니다. 그러나 일반적으로 부드러운 보조개(soft dimple)보다 약간 더 날카로운, 거의 주름으로 나타납니다. 이 메쉬에서 외부면에 나타나는 X 모양을 볼 수 있습니다. 이것은 메쉬를 삼각 측량하지 않고 멋지게 보이는 다각형을 유지하는 것(editorble poly)이 종종 매우 유용하기 때문에 유지하기도 합니다. 이 경우에는 그 편의성 상실을 처리하거나 게임을 위해 모델을 내보내기 전에 파이프라인의 마지막 도구가 법선을 굽는 데 사용되는 메시를 생성하는 데도 사용되는지 확인해야 합니다. 접선 공간 및 정점 법선(접선 공간의 일부임)과 마찬가지로 삼각 측량도 정확히 일치해야 합니다.

 

The List For Perfect Normal Maps for Unity

요약하자면 Unity에서 사용하기 위해 하이 폴리 소스 모델에서 로우 폴리 메시에 대한 탄젠트 공간 노멀맵을 생성하려면:

  • 3ds Max, Maya 또는 MikkTSpace 탄젠트에 대한 옵션이 없는 응용 프로그램을 사용하여 노멀 맵을 굽지 마십시오.
  • export 옵션에서 triangles와 with normal, 그리고 tangents를 생략합니다.
  • 베이킹할 때 노멀맵 방향으로 OpenGL 또는 X+Y+Z+를 선택(또한 Substance Painter용 프로젝트를 생성할 때도).
  • 레거시 렌더러를 사용할 경우(forward 또는 deferred) 또는 URP에 대해 베이킹할 때 "Per pixel"/ "per fragment" 바이탄젠트 옵션을 활성화하지 마십시오.
  • HDRP 및 URP에 대해 베이킹할 때 "per pixel"/ "per fragment" 바이탄젠트 옵션을 활성화합니다.
  • Unity의 model import 설정은 Normals가 "Import"로 설정되고 Tangents가 "Calculate Mikktspace"로 설정된 기본값으로 둡니다.

 

More on MikkTSpace

준공식 웹사이트 mikktspace.com은 MikkTSpace의 기본적인 이점을 잘 설명하고 있습니다. 즉, 결과를 일관되게 유지하면서 다른 메시 처리를 사용하는 프로그램 간에 탄젠트 데이터를 다시 계산하거나 전송하는 데 모두 잘 작동합니다. 이 사이트의 텍스트는 Morten S. Mikkelsen이 직접 작성한 블렌더 위키 페이지의 사본입니다. 불행히도 Unity 및 xNormal의 기본값에서 사용되는 버텍스별 버전이 아닌 픽셀당 바이탄젠트 버전만 언급합니다. 블렌더는 픽셀 도함수별로만 사용하기 때문에 언급된 유일한 것이 의미가 있습니다.

다음은 두 가지 옵션에 대한 원본 mikktspace.h 파일의 몇 가지 설명입니다.

--------------------------------------

노멀맵의 경우 픽셀/버텍스 수준에서 생성되는 다음 단순화된 버전의 바이탄젠트를 사용하는 것으로 충분합니다.   bitangent = fSign * cross(vN, tangent);

...

시각적 오류(원치않는 하드엣지에 의한 라이팅 왜곡)를 피하기 위해 샘플링된 노멀맵을 사용할 때 노멀 맵 샘플러는 픽셀 셰이더 변환의 정확한 역을 사용해야 합니다.

픽셀 셰이더에서 할 수 있는 가장 효율적인 변환은 "비정규화" 보간된 탄젠트, 바이탄젠트 및 버텍스 노멀 : vT, vB 및 vN을 직접 사용하여 달성됩니다.

픽셀 셰이더(빠른 변환 출력)
vNout = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN );
여기서 vNt는 탄젠트 공간 노멀입니다. 노멀맵 샘플러는 마찬가지로 픽셀 셰이더와 호환되도록 보간 및 "정규화되지 않은" 탄젠트, 바이탄젠트 및 버텍스 노멀을 사용해야 합니다.

...

앞에서 설명한 것처럼 버텍스 셰이더 대신 픽셀 셰이더에서 바이탄젠트를 재구성하도록 선택했다면 노멀맵 샘플러에서도 이 작업을 수행해야 합니다.

따라서 원래 예제는 버텍스 셰이더에서 바이탄젠트를 재구성하고 이를 다른 보간값으로 픽셀 셰이더에 전달하는 것입니다. 이것이 Unity의 내장 셰이더가 현재 노멀맵을 처리하는 방식입니다.

픽셀당 구현의 이점은 약간의 추가 ALU(픽셀 셰이더 수학) 비용으로 두 개의 보간된 값을 제거할 수 있다는 것입니다. 이것은 3개의 Vector3 값, 탄젠트, 바이탄젠트 및 노멀 대신 Vector4 및 Vector3, 탄젠트 w/ 기호 및 노멀만 필요함을 의미합니다. 최신 GPU에서는 실제로 조금 더 빠릅니다. 실시간 렌더러가 아닐 수 있으므로 CPU에서 수행되는 경우 확실히 더 빠릅니다. 이를 위해 대부분의 업계에서는 버텍스당이 아닌 픽셀에서 바이탄젠트를 재구성하기로 선택했습니다.

반응형