TECHARTNOMAD | TECHARTFLOWIO.COM

UNITY3D

[번역]Firewatch multi-coloured fog

jplee 2023. 8. 30. 13:50

원문

 

My take on shaders: Firewatch multi-colored fog – Harry Alisavakis

 

halisavakis.com

이 토픽도 2022년 봄에 포그 시스템 개발 요소를 수집 하는 과정에서 번역 했던 것 같다.사실 이 기사는 꽤 오래 된 것으로 GDC 2015 에서 발표 됬던 내용이다.
https://youtu.be/ZYnS3kKTcGg

최근에 저는 카메라의 깊이 텍스처를 만지작거리기 시작했고 몇 가지 흥미로운 발견을 발견했습니다.

물론 이러한 발견은 다른 셰이더 애호가에게는 매우 분명할 것이지만 저에게는 새롭고 흥미로운 것이었습니다.

카메라 깊이 텍스처 사용에서 제가 가장 좋아하는 요소는 깊이를 0에서 1로 매핑한다는 사실입니다.

이제 [0.0,1.0] 스펙트럼에 있는 무언가를 얻는 한 모든 종류의 트릭을 할 수 있습니다.

그것이 UV 좌표, 색상, 거리 또는 그 문제에 대한 어떤것이든 나에게는 흉내내어보고 싶은 효과는 분명했습니다. 대표적으로 Firewatch의 다양한 색상의 안개입니다.

 

Firewatch의 기술에 대한 매우 흥미로운 GDC의 강연을 본 후, 저는 효과가 어떻게 작동하는지에 대해 꽤 좋은 아이디어를 얻었고 어떻게 구현할 수 있을지 추측했습니다. 그리고 몇 가지 문제가 있지만 결과에 매우 만족한다고 말할 수 있습니다.

또한, 이 게시물은 "How I'd it do it" 카테고리에 속할 수 있을 뿐이며 카메라 깊이에 대한 몇 가지를 보여주기 위한 핑계로 사용하기 때문에 다음과 같이 설정하는 것이 더 적절하다고 생각했습니다.

Breakdown

나는 여기서 일부 마스터마인드 작업을 한 것이 아니며 위에서 언급한 비디오에서 모든 것이 거의 설명되었습니다. 색상 램프 텍스처를 사용하여 안개의 색상을 해당 깊이에 매핑했습니다. 그러나 나를 더 흥미롭게 만든 것은 텍스처의 알파 채널에 저장된 안개에 대한 불투명도 또한 다양하다는 사실이었습니다.

 

따라서 내 간단한 접근 방식은 카메라의 깊이 텍스처를 가져와서 색상 램프의 UV.x 좌표로 사용하고 lerp를 사용하여 불투명도 값에 따라 원래 색상에서 램프 텍스처로 페이드하는 것이었습니다. 그 후 안개 효과의 전반적인 기여에 대한 몇 가지 컨트롤을 추가했습니다.

 

그건 그렇고, 효과를 카메라에 적용하려면 스크립트가 필요하지만 카메라의 깊이 텍스처 모드도 DepthTextureMode.Depth로 변경해야 합니다.

The code

Here’s the code:

Shader "Custom/FirewatchFog"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _FogAmount("Fog amount", float) = 1
        _ColorRamp("Color ramp", 2D) = "white" {}
        _FogIntensity("Fog intensity", float) = 1
    }
    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always
 
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
             
            #include "UnityCG.cginc"
 
            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };
 
             
            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
                float4 scrPos : TEXCOORD1;
            };
 
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                o.scrPos = ComputeScreenPos(o.vertex);
                return o;
            }
             
            sampler2D _MainTex;
            sampler2D _CameraDepthTexture;
            sampler2D _ColorRamp;
            float _FogAmount;
            float _FogIntensity;
 
            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 orCol = tex2D(_MainTex, i.uv);
                float depthValue = Linear01Depth (tex2Dproj(_CameraDepthTexture, UNITY_PROJ_COORD(i.scrPos)));
                float depthValueMul = depthValue * _FogAmount;
                fixed4 fogCol = tex2D(_ColorRamp, (float2(depthValueMul, 0)));
                return (depthValue < 1) ? lerp(orCol, fogCol, fogCol.a * _FogIntensity) : orCol;
            }
            ENDCG
        }
    }
}

심도 있는 설명...

(하하...셰이더에서 카메라의 깊이를 사용하고 방금 "심도 있는 설명"이라고 썼기 때문입니다. 저는 말장난을 좋아합니다.)

그래서, 우리는 몇 가지 속성을 가지고 있습니다. "_MainTex"는 전통적이고, "_FogAmount"는 안개를 카메라에서 더 가깝거나 멀어지게 이동하고, "_ColorRamp"는 안개의 여러 색상과 불투명도를 얻는 데 사용되는 램프 텍스처이고, "_FogIntensity"는 안개의 전역 승수입니다.

불투명도가 색상 램프에 의해서만 결정되도록 하려면 1로 둡니다. 그런 다음 모두 46-50행에서 다시 선언됩니다. 그러나 그들 사이에는 속성에 선언되지 않은 sampler2D가 숨어 있습니다.

카메라 깊이 텍스처를 얻는 것은 매우 간단합니다. 이러한 종류의 내장 변수에 대한 자세한 내용은 이 설명서에서 찾을 수 있습니다.

나중에 우리는 34번째 줄과 42번째 줄에서 약간 이상한 것을 봅니다. "scrPos"라는 변수를 선언한 다음 화면 공간에서 위치를 가져와서 "scrPos"에 저장합니다. 셰이더 비트 포스트. 그런데도 그게 왜 이상해? 이것은 이미지 효과 셰이더이기 때문에 화면 공간에서 정점 위치를 얻는 데 "직접적인" 지점이 없음을 의미합니다. 화면을 나타내는 "쿼드" 외에 실제 모델이 없습니다. 그러나 화면 좌표가 필요한 이유는 나중에 카메라의 선형 깊이를 얻기 위함입니다.

특히, 여기에서 가장 이상해 보이는 라인인 55번째 줄에 있습니다. 여기서 무슨 일이 일어나고 있는지는 다루지 않겠습니다. 지금은 이것이 카메라의 깊이를 깊이 텍스처에서 값으로 추출하는 방법이라고 말하는 것으로 충분합니다.

[0,1] 스펙트럼. 깊이 맵 사용에 대한 자세한 정보는 이 매뉴얼 페이지에서 찾을 수 있습니다. 라인 56에서 깊이 값은 "0에서 1로 빠르게 이동"하기 위해 "_FogAmount" 매개변수와 곱해지며 매우 단순한 용어로 표현됩니다.

57행에서 불투명도를 고려하지 않고 안개의 색상을 계산합니다. UV 좌표로 "float2(depthValueMul, 0)"를 사용하여 램프 텍스처에서 색상을 가져옵니다. 따라서 곱한 깊이가 0에서 1로 갈 때 "tex2D" 함수는 램프의 왼쪽 끝을 0, 오른쪽 끝을 1로 간주하여 램프의 해당 색상을 반환합니다.

또한 [0,1] 스펙트럼의 값을 마음대로 조작할 수 있는 좋은 예입니다.

마지막으로 58행에서 깊이 값이 1보다 작은지 확인합니다.

이것은 효과가 스카이박스에 그려지는 것을 방지하는 해키 솔루션이지만 몇 가지 단점이 있습니다. 가장 멀리 있는 지오메트리 주변에 이상한 앨리어싱이 발생할 수 있고, 충분히 멀면 다른 요소에 남을 수도 있습니다.

그 편법 솔루션 위에 내 편법 솔루션은 가장 먼 색상을 사용하여 앨리어싱 아티팩트와 나머지 불투명한 지오메트리를 덮는 약간의 선형 안개를 추가하는 것입니다.

짜잔!, 안개~~~ 그럼에도 불구하고 깊이가 1보다 작은 경우 해당 지점의 램프 불투명도를 lerping 매개변수로 사용하여 원래 색상과 안개 색상 사이를 보간하는 색상을 반환합니다.

또한 더 밝은 안개 효과를 원할 경우를 대비하여 해당 매개변수에 "_FogIntensity"를 곱합니다.

결론

카메라 깊이는 정말 대단합니다. 깊이 텍스처와 약간의 그라디언트 색상만으로도 정말 독특하고 멋진 효과를 낼 수 있습니다.

추신: 가지고 놀 수 있는 색상 램프가 있습니다! 그러나 투명도를 켜고 Wrap mode를 Clamp로 설정하는 것을 잊지 마십시오!!!

 

'UNITY3D' 카테고리의 다른 글

Tone-mapping assessment guide  (1) 2023.09.01
How to port UE4 ACES to URP  (0) 2023.09.01
[번역]The Fog of Random! Losf of Random 개발 사례.  (0) 2023.08.30
Light-Probe Data manager implementation  (0) 2023.05.16
[번역글] Branching on a GPU  (0) 2023.05.16