TECHARTNOMAD | TECHARTFLOWIO.COM

UNITY3D

Custom Shadow Attenuation Tweak Example

jplee 2024. 9. 25. 01:48

라이팅과 렌더링쪽의 업무 서포트를 하다보면 개인적으로 인상파에 대한 귀결이라고 해야할까요.
픽셀은 병치 이고 빛과 그림자를 기조로 했던 인상파의 영향을 여전히 많이 받는것 같습니다. 그림자의 색조는 전체 톤앤메너부터 더 깊은 부분까지 매우 중요한 요소가 될 수 있습니다.
중국에서 프로젝트를 진행 하면서 이와 관련 된 많은 요구사항을 아트디렉터들에게 받은 경험과 제가 원래 서양화 전공 학도 였다는 점의 공통분모로부터 깊게 이해할 수 있는 대표적인 부분이라고 생각하게 되었습니다.


2019년 쯔음에 몇 가지 프로젝트에 사용했던 그림자에 대한 사용자 어튜네이션 트윅 함수 소개 입니다.
특정 프로젝트의 스타일에 맞추 OnDemanded Feature 정도라고 볼 수 있겠네요.


대략 3개 프로젝트에 사용 됬고 아래 참조 함수는 프로젝트에 따라 좀 더 구체적으로 변경 됬을 가능성이 있습니다. 기본 스켈레톤 코드만을 제시 해 봅니다.

// NPR Custom Lighting Shadow Adjustment
uniform half g_ShadowIntensityPerVolume;

half3 customDirectionalLightShadowVaiableFunction ( Light light , half3 normalWS , half3 color)
{
    half nolmask =saturate(dot(normalize(normalWS), normalize(light.direction)));
    half addShadowAtten = 1 - lerp(0.0, 1, nolmask);
    light.shadowAttenuation = saturate(addShadowAtten + light.shadowAttenuation ) * light.distanceAttenuation;
    half customShadowToggle = ((1.0 - light.shadowAttenuation));
    return lerp(color , (color * _SubtractiveShadowColor.rgb) , customShadowToggle * ( g_ShadowIntensityPerVolume * 0.1));
}

half3 customSpotlightShadowVaiableFunction( Light light , half3 normalWS , half3 color, uint lightIndex )
{
    half nolmask =saturate(dot(normalize(normalWS), normalize(light.direction)));
    half addShadowAtten = 1 - lerp(0.0, 1, nolmask);
    light.shadowAttenuation = saturate(addShadowAtten + light.shadowAttenuation )  * AngleAttenuation(light.direction, light.direction, lightIndex);;
    half customShadowToggle = ((1.0 - light.shadowAttenuation));
    return lerp(color , color * _SubtractiveShadowColor.rgb , customShadowToggle * ( g_ShadowIntensityPerVolume * 0.1) );
}
// NPR Custom Lighting Shadow Adjustment End

위의 코드는 NPR(Non-Photorealistic Rendering) 커스텀 라이팅 그림자 조정 기능을 구현한 hlsl 셰이더 코드입니다.
두 개의 함수로 구성되어 있으며, 각각 customDirectionalLightShadowVaiableFunctioncustomSpotlightShadowVaiableFunction 입니다. 이 함수들은 방향성 조명과 스포트라이트에 대한 커스텀 그림자 처리를 수행합니다. 코드를 단계별로 분석해 보겠습니다.
g_ShadowIntensityPerVolume 은 로컬 볼륨에 따른 그림자 강도를 조절하는 유니폼 변수입니다.

1. customDirectionalLightShadowVaiableFunction

half3 customDirectionalLightShadowVaiableFunction (Light light, half3 normalWS, half3 color)
{
    half nolmask = saturate(dot(normalize(normalWS), normalize(light.direction)));
    half addShadowAtten = 1 - lerp(0.0, 1, nolmask);
    light.shadowAttenuation = saturate(addShadowAtten + light.shadowAttenuation) * light.distanceAttenuation;
    half customShadowToggle = ((1.0 - light.shadowAttenuation));
    return lerp(color, (color * _SubtractiveShadowColor.rgb), customShadowToggle * (g_ShadowIntensityPerVolume * 0.1));
}

이 함수는 다음의 인자를 받습니다:
Light light: 조명 정보.
half3 normalWS: 월드 스페이스에서의 노멀 벡터.
half3 color: 기본 컬러.

nolmask 는 조명 방향과 노멀 벡터의 내적(dot product)을 사용하여 그림자의 기초 마스크를 계산합니다. 이 값은 0과 1 사이로 제한(saturate)됩니다.
addShadowAtten은 그림자 감쇠값을 계산합니다.
light.shadowAttenuation은 현재 그림자 감쇠값에 거리 감쇠값(조명과의 거리)도 곱합니다.
customShadowToggle은 최종 그림자 스위치 값을 계산합니다.
마지막으로, lerp 함수를 사용하여 그림자 색상과 기본 색상 사이를 보간합니다.
그림자 강도는 _ShadowIntensityPerVolume 값을 조절하여 반영합니다.

2. customSpotlightShadowVaiableFunction

half3 customSpotlightShadowVaiableFunction (Light light, half3 normalWS, half3 color, uint lightIndex)
{
    half nolmask = saturate(dot(normalize(normalWS), normalize(light.direction)));
    half addShadowAtten = 1 - lerp(0.0, 1, nolmask);
    light.shadowAttenuation = saturate(addShadowAtten + light.shadowAttenuation) * AngleAttenuation(light.direction, light.direction, lightIndex);
    half customShadowToggle = ((1.0 - light.shadowAttenuation));
    return lerp(color, color * _SubtractiveShadowColor.rgb , customShadowToggle * (g_ShadowIntensityPerVolume * 0.1));
}

이 함수는 방향성 조명 함수와 구조는 유사하지만 스포트라이트에 대한 특화된 연산을 수행합니다. 추가된 lightIndex 인자를 통해 각 스포트라이트의 각도 감쇠 값(AngleAttenuation)을 적용합니다.
단계별 코드 설명:
nolmask와 addShadowAtten은 위 함수와 유사하게 계산됩니다.
light.shadowAttenuation에서는 각도 감쇠(AngleAttenuation)가 추가로 곱해집니다.
나머지 부분은 방향성 조명 함수와 동일하게 계산됩니다.
이와 같은 방식으로 NPR 스타일의 커스텀 그림자 처리가 이루어집니다.


함수 설명을 위한 간단한 프리뷰.


사용 된 프로젝트

https://www.youtube.com/channel/UCnD7Nyd9ALhjKImJfiz-DBA

Dragonheir: Silent Gods

Dragonheir: Silent Gods is an open-world high-fantasy strategy RPG that takes Travelers on an epic journey. Here you'll discover a dynamic world with diverse exploration possibilities. Character customization options and branching storylines will bring you

www.youtube.com