WinCNT

Fog가 적용되는 Skybox의 셰이더 만들어보자! 본문

Unity/URP or Shader 관련

Fog가 적용되는 Skybox의 셰이더 만들어보자!

WinCNT_SSS 2024. 2. 28. 11:31

서론

배경 아티스트 분께서 Skybox에 Fog를 표현하고 싶다고 요청한 적이 있다

배경 오브젝트에는 Fog가 걸리지만 그 뒤의 Skybox에는 Fog가 생기지 않아서 위화감이 생긴다는 이유였다

대충 요런 느낌…물체에는 Fog(노란색)이 있지만 위의 Skybox에는 없어서 위화감이 생긴다

 

당시의 필자는 Fog를 그 존재밖에 몰라서 대충 왜 그런지에 대해서 뇌피셜로 얘기하며 대응되는 셰이더를 만들겠다는 말을 남기고 호다닥 그 자리에서 도망쳤었다

다행히 뇌피셜로 떠든 게 대부분 사실이었다


우선은 Fog가 어떻게 적용되는지 알아보자

Default의 스카이박스는 물론이고 내장된 다른 Skybox 셰이더도 유니티에서 바로 볼 순 없다

그렇다고 아예 방법이 없는 것은 아니지!

Download Archive

 

Download Archive

Download Archive

unity.com

예전에도 한 번 작성한 적이 있지만 유니티의 빌트인 셰이더는 위의 사이트에서 다운받을 수 있다

 

이번 타깃은 Skybox-Cubed.shader란 녀석이다

간단하게 프래그먼트 셰이더만 발췌했다

fixed4 frag (v2f i) : SV_Target
{
    half4 tex = texCUBE (_Tex, i.texcoord);
    half3 c = DecodeHDR (tex, _Tex_HDR);
    c = c * _Tint.rgb * unity_ColorSpaceDouble.rgb;
    c *= _Exposure;
    return half4(c, 1);
}

역시 MixFog와 같은 Fog에 관한 처리가 없는 것을 알 수 있었다


그럼 뭐다? 만들어야지…

없는 걸 알았으니 다음은 Fog가 적용된 Skybox 셰이더를 만들 수 밖에…

일단 베이스가 되는 셰이더 코드가 있으니 만드는 건 어렵지 않다

카피닌자가 되어보자!

 

베이스가 되는 셰이더 코드에 ComputeFogFactor와 MixFog를 적용하는 정도이다

그리고 URP 환경에서 CGPROGRAM를 보는 것도 기분이 나쁘므로 겸사겸사 바꿔줬다

 

Tags

SubShader
{
    Tags
    {
        "Queue"="Geometry+225"
        "RenderType"="Background"
        "PreviewType"="Skybox"
    }
}

RenderQueue는 불투명 오브젝트의 가장 마지막 순서인 Geometry(2000)+225 로 설정했다

보통은 Background(1000)으로 설정하겠지만, 어떻게든 Over Draw를 줄여보겠다는 발악(…)

문제 생기면 그냥 머테리얼 쪽에서 조정하면 될 뿐이니 디폴트는 일단 이렇게 설정했다

 

버텍스 셰이더

float3 RotateAroundYInDegrees (float3 vertex, float degrees)
{
    float alpha = degrees * PI / 180.0;
    float sina, cosa;
    sincos(alpha, sina, cosa);
    float2x2 m = float2x2(cosa, -sina, sina, cosa);
    return float3(mul(m, vertex.xz), vertex.y).xzy;
}

v2f vert (appdata_t v)
{
    v2f o;
    ZERO_INITIALIZE(v2f, o);
    
    UNITY_SETUP_INSTANCE_ID(v);
    UNITY_TRANSFER_INSTANCE_ID(v, o);
    UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
    
    float3 rotated = RotateAroundYInDegrees(v.vertex.xyz, _Rotation);
    o.vertex = TransformObjectToHClip(rotated);
    o.texcoord = v.vertex.xyz;
    o.fog_coord = ComputeFogFactor(o.vertex.z);
    
    return o;
}

기존의 처리에 큰 변경 없이 ComputeFogFactor를 추가했다

 

프래그먼 셰이더

half4 frag (v2f i) : SV_Target
{
    UNITY_SETUP_INSTANCE_ID(i);
    UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
    
    half4 tex = texCUBE (_Tex, i.texcoord);
    half3 c = DecodeHDREnvironment(tex, _Tex_HDR);
    c = c * _Tint.rgb * half4(4.59479380, 4.59479380, 4.59479380, 2.0).rgb; // unity_ColorSpaceDouble.rgb의 값
    c *= _Exposure;
    c = MixFog(c, i.fog_coord);
    return half4(c, 1);
}

마찬가지로 기존의 처리에 MixFog만 추가한 느낌이다

URP 환경에 맞는 함수나 값으로 바꾸기 위해 이리저리 찾긴 했다


결과

우선 Lighting의 Skybox Material를 날려주고 Fog를 설정하자

 

적당히 머테리얼을 만들어주고 그걸 적용한 Sphere를 배치해주자

그럼 Fog가 적용된 Skybox가 보인다

Fog가 없는 Skybox(좌) /  Fog가 있는 Skybox(우)


사족

사실 Lighting의 Skybox Material에 이번에 만든 셰이더가 적용된 머티리얼을 배치하고 싶었으나 스크린의 중앙 부분에서 노이즈가 발생했었다

그런데 나중에 다시 해보니 문제가 발생하지 않았다…

일단 문제가 발생하지 않는다면 Lighting의 Skybox Material를 배치하는 방식을 채택하는 것이 더 나을 것이라 생각된다


마무리

순조롭게 마무리할 수 있었던 태스크였다

역시 Built-in 코드는 여러모로 쓸모가 많다


참고 사이트

Download Archive

 

Download Archive

Download Archive

unity.com

Resolved - skybox that displays a flat image

 

Resolved - skybox that displays a flat image

The goal is to display a RenderTexture as flat instead of the sphere skybox. Currently I'm getting a sphere projection of that rendertexture if I use a...

forum.unity.com

Skybox render queue value

 

Skybox render queue value

Hi, I'm currently trying to get a Skybox to be seen through a window. What I do is basically to attach a Skybox to the camera and then render the...

forum.unity.com