역자의 말.
2023년이라는 시대(?)에 아직도 Pre-Integrated Skin 을 놓을 수 없다는 것이 문제가 아닌가~ 라는 생각을 하게 되는 요즘입니다.
Scalability 에 맞춰서 셰이딩 모델 자동 변경 디파인 작업을 하다가 여기까지 오게 되었는데요....
Penner 의 BRDF lut 과 Unreal Engine 의 BRDF lut 의 차이가 있음으로 간단히 이 기사를 번역 해 봤습니다. 알쓸신잡 일 수도 있지만요~
원문
최근 저는 스킨 셰이딩 모델에 관한 논문 / UE4 셰이더 코드 / 다양한 웹 페이지를 읽으며 시간을 보냈습니다. 매우 흥미로웠고 몇 가지 성과가 있어서 공유하고자 합니다.
Sub Surface Scattering
피부는 반투명 표면이며 일반적으로 산란 이론에 기반한 셰이딩 모델을 사용하여 렌더링됩니다.
Light enters at some point and travels inside of translucent tissue and comes out at other point. This looks simple but needs some tricks to work in real time renderer.
Diffusion Profile
모든 적절한 스킨 셰이딩 모델은 이 이론과 데이터를 기반으로 합니다. 이 이론은 입사점에서의 거리에 따라 빛이 어떻게 산란되는지를 설명합니다.
사람들은 실제 피부를 사용하여 빛이 얼마나 산란되는지 데이터를 측정합니다.
그리고 커브는 가우시안 함수의 합에 맞춰져 있습니다. 이 맞춰진 함수는 인접한 확산 색상 픽셀을 흐리게 하거나 확산 BRDF 텍스처를 사전 통합하는 데 사용됩니다. 인터넷에 아시아계 또는 아프리카계 미국인의 측정 데이터가 있는지 궁금하지만 성공하지 못했습니다. 피가 파란색인 외계인은 어떨까요? 나중에 걱정해야 할지도 모르겠네요.
Screen Space Sub Surface Scattering
Jorge Jimenez's method.
핵심 아이디어는 장착된 가우시안 커널을 사용하여 화면 공간의 확산 조도를 흐리게 하는 것입니다. 물론 블러 거리는 깊이와 각도에 따라 조정되어 정확합니다.
이 기법은 디퍼드 렌더러에 매우 적합하며 품질도 매우 우수합니다.
그러나 기본 확산 조도가 낮고 블러가 너무 많이 보이는 낮은 품질로 인해 이것이 최선의 방법이라는 데 동의하지 않는 사람들도 있지만 여전히 훌륭한 피부 렌더링 방법입니다.
제 생각에는 UE4 버전의 서브서피스 프로파일이 완벽하기 때문에 이에 대해 많은 연구를 하지 않았습니다.
Pre-Integrated Skin (Penner)
Another popular method is Penner's Pre-Integrated Skin.
기본 아이디어는 피부 표면을 원으로 가정하고 두 가지 매개 변수(피부 표면의 경사각과 곡률)에 따라 확산 프로파일을 통합하는 것입니다. 그는 이 두 가지 요소가 피부 산란에서 가장 중요한 부분이라고 생각합니다.
이렇게 하면 아래와 같은 텍스처가 생성됩니다.
실제 hlsl 셰이더 코드는 다음과 같습니다,
float3 ScatteredLight = Texture2DSampleLevel(PreIntegratedBRDF, PreIntegratedBRDFSampler, float2(saturate(dot(N, L) * .5 + .5), Curvature), 0).rgb;
전체적인 구조는 동일합니다,
-사전 통합 BRDF 텍스처(파라미터와 같은 코사인 및 곡률에 의한 인덱스)
하지만 UE4 버전과 원본 사이에는 몇 가지 차이점이 있습니다.
-사전 통합 스킨 BRDF는 그림자가 있는 영역에만 적용됩니다.
음영이 없는 영역은 기본적으로 라이팅되어 음영 처리됨(이는 잘못되어 피부를 너무 밝게 만듭니다).
-BRDF 텍스처는 컬러 채널(주파수)에 따라 디퓨전 프로파일이 달라지지 않습니다.
사실 아티스트가 제공하는 서브서피스 컬러는 나쁘지 않은 아이디어입니다. 하지만 UE4의 사전 통합된 스킨 셰이딩 모델을 사용하여 사실적인 사람의 피부를 만드는 것은 매우 어렵습니다.
원본 논문에 따라 제대로 구현하면 아래와 같은 결과를 얻을 수 있습니다.
이 두 가지 방법을 사용하면 렌더링된 사람의 피부가 이미 피부처럼 보입니다. 하지만 더 많은 것이 필요합니다.
피부는 반투명 조직이기 때문에 입사광은 실제로 얇은 부분을 투과합니다.
그리고 아래와 같은 효과가 있어야 합니다,
가장 중요한 아이디어는 빛이 입사하는 지점부터 실제 음영 지점까지의 두께를 계산하는 것입니다. 이 두께를 통해 얼마나 많은 빛이 투과되는지 알 수 있습니다.
그림자 투영 셰이더에서 이 두 점을 알고 있습니다. (그림자 깊이 값과 셰이딩된 월드 포인트)
사실 UE4는 이미 이 투과율 값을 계산하고 있으며, 이를 "서브서피스 섀도 텀"으로 정의합니다. 이 텀은 보통 다양한 서브서피스 라이팅 텀에 곱해집니다. (예: TWO_SIDED_FOILAGE). 하지만 두 스킨 셰이딩 모델 모두 이 효과가 부족한 것 같습니다.
그래서 미리 통합된 스킨 셰이딩 모델에 Jorge Jimenez의 반투명 효과를 추가했습니다.
그림자 깊이 범위 정밀도 문제로 인해 두께(투과율 또는 표면 아래 그림자 항)를 계산하는 데는 스팟 라이트가 가장 정확한 것으로 보입니다. 포인트 라이트에는 이 기능이 없습니다.
간접광을 사용한 스킨 BRDF
위의 방법은 모두 직접 조명에 대한 것입니다. 가끔 게임 캐릭터가 간접 조명(그림자 영역)만 있는 조명 조건에 있을 수 있습니다. 그러면 이 모든 멋진 스킨 셰이딩이 사라집니다.
UE4는 서브서피스 컬러를 (구형 하모닉스 프로브에서) 확산 조도에 곱합니다. 이 정도면 괜찮을 수 있습니다. 하지만 이 슬픈 상황에 대해 우리가 할 수 있는 일이 있습니다. 레디 앳 던의 그래픽 프로그래머들은 간접 프로브를 사용하여 피부 BRDF를 적용하는 훌륭한 기술을 제안합니다.
아이디어는 다음과 같습니다,
조도 구형 고조파 프로브로 점을 찍는 전달 함수로 클램핑된 코사인을 사용합니다. 이것은 클램핑 코사인 함수를 나타내기 위해 투영된 구역 고조파 계수입니다.
RAD 프로그래머의 아이디어는 확산 피부 BRDF를 표현하기 위해 투영된 특수 영역 고조파 전달 함수를 사용하는 것입니다. 그들은 논문에서 그들의 아이디어를 친절하게 설명했습니다.
이를 구현한 아래 이미지는 곡률에 따라 인덱싱된 영역 고조파 계수를 생성한 것입니다.
X축은 곡률, Y축은 영역 고조파 순서입니다.
그리고 이것이 그 결과입니다. 결과는 꽤 인상적이었습니다.
라이트 프로브의 일반 확산 조도와 비교할 수 있습니다.
사용된 조명 조건입니다.
아래 생성 코드를 사용하여 3개의 구역 고조파 계수를 투영합니다.
Order 0
_func = [this](double theta, double rInv)
{
float R = rInv * 255;
float radius = 2.0f * 1.f / ((R + 1) / (float)SizeX);
float cosTheta = FMath::Cos(theta);
auto BRDF = IntegrateDiffuseScatteringOnRing(cosTheta, radius);
return 0.28209479177 * BRDF.X *sin(theta);
};
D0R = 2 * PI * MonteCarloIntegral1D(0, PI / 2, NumMonteCarloSample, rInv);
Order 1
_func = [this](double theta, double rInv)
{
float R = rInv * 255;
float radius = 2.0f * 1.f / ((R + 1) / (float)SizeX);
float cosTheta = FMath::Cos(theta);
auto BRDF = IntegrateDiffuseScatteringOnRing(cosTheta, radius);
return 0.4886025119 * cos(theta) * BRDF.X * sin(theta);
};
D1R = 2 * PI * MonteCarloIntegral1D(0, PI / 2, NumMonteCarloSample, rInv);
Order 2
_func = [this](double theta, double rInv)
{
float R = rInv * 255;
float radius = 2.0f * 1.f / ((R + 1) / (float)SizeX);
float cosTheta = FMath::Cos(theta);
auto BRDF = IntegrateDiffuseScatteringOnRing(cosTheta, radius);
return 0.31539156525 * (3 * pow(cos(theta), 2) -1) * BRDF.X *sin(theta);
};
D2R = 2 * PI * MonteCarloIntegral1D(0, PI / 2, NumMonteCarloSample, rInv);
저는 이 링크에서 스킨 BRDF 통합을 사용했습니다.
나중에 더 발전된 스킨 렌더링 기술이 나올 것 같습니다. 하지만 지금은 이 정도면 충분합니다.
'TECH.ART.FLOW.IO' 카테고리의 다른 글
[번역]UE5로 만드는 셀 셰이딩 제2회: 셀 셰이딩의 다양한 표현법 (1) | 2023.10.05 |
---|---|
[Fork][Pipeline] File and Folder Management, Create, Find, Delete (0) | 2023.10.05 |
[FORK] PyQt for Maya and Unreal (0) | 2023.10.02 |
[간단정리?]Voxelizations of Shadow for mobile. Case Study. (0) | 2023.09.27 |
[지인찬스]오랜 지인 김수빈님의 언리얼 바캉스 유투브 체널 오픈. (0) | 2023.09.26 |