体积云复刻

体积云复刻。
在unity中复刻了这个ShaderToy中的效果。添加了视角的移动以及平面的反射。
Clouds by iq

wasd qe移动 鼠标右键旋转

Shader "KM/Cloud"
{
    Properties
    {
        iChannel0("iChannel0", 2D) = "black" {}
        iChannel1("iChannel1", 2D) = "black" {}
        _StepTime("_StepTime", Range(0,10)) = 1
        [HDR] LightColor("LightColor", Color) = (1.0, 0.95, 0.8)
        [HDR] DarkColor("DarkColor", Color) = (0.25, 0.3, 0.35)
        [HDR] Color01("Color01", Color) =  (1.0, 0.6, 0.3)
        [HDR] Color02("Color02", Color) =  (0.91, 0.98, 1.05)
        height("height", Range(0,2)) =  1.5
        hd("hd", Range(0,2)) =  1.75
        index("index", Range(-2,2)) =  -1
        sunDiff("sunDiff", Range(0,10)) =  0.3
        skyIndex("skyIndex", Range(-0.003,0)) =  -0.003
    }
    SubShader
    {
        Tags
        {
            "RenderType"="Transparent" "RenderPeipeline" = "UniversalPepeline" "Queue"="Transparent"
        }
        LOD 100

        Pass
        {
            name "ShaderToy"
            blend one zero
            ZWrite off
            ZTest always
            Cull off
            HLSLPROGRAM
            #pragma  vertex vert
            #pragma  fragment frag

            #define iTime   (0.5*_Time.y%100)


            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"

            TEXTURE2D_X(iChannel0);
            SAMPLER(sampler_iChannel0);

            TEXTURE2D_X(iChannel1);
            SAMPLER(sampler_iChannel1);


            CBUFFER_START(UnityPerMaterial)
            float4 iChannel1_TexelSize;
            float4 LightColor;
            float4 DarkColor;
            float4 Color01;
            float4 Color02;
            float height;
            float hd;
            float index;
            float sunDiff;
            float skyIndex;
            
            float _StepTime;

            CBUFFER_END

            //

            // Copyright Inigo Quilez, 2013 - https://iquilezles.org/
            // I am the sole copyright owner of this Work.
            // You cannot host, display, distribute or share this Work in any form,
            // including physical and digital. You cannot use this Work in any
            // commercial or non-commercial product, website or project. You cannot
            // sell this Work and you cannot mint an NFTs of it.
            // I share this Work for educational purposes, and you can link to it,
            // through an URL, proper attribution and unmodified screenshot, as part
            // of your educational material. If these conditions are too restrictive
            // please contact me and we'll definitely work it out.


            // Volumetric clouds. Not physically correct in any way - 
            // it does the wrong extintion computations and also
            // works in sRGB instead of linear RGB color space. No
            // shadows are computed, no scattering is computed. It is
            // a volumetric raymarcher than samples an fBM and tweaks
            // the colors to make it look good.
            //
            // Lighting is done with only one extra sample per raymarch
            // step instead of using 3 to compute a density gradient,
            // by using this directional derivative technique:
            //
            // https://iquilezles.org/articles/derivative


            // 0: one 3d texture lookup
            // 1: two 2d texture lookups with hardware interpolation
            // 2: two 2d texture lookups with software interpolation
            #define NOISE_METHOD 1

            // 0: no LOD
            // 1: yes LOD
            #define USE_LOD 1

            // 0: sunset look
            // 1: bright look
            #define LOOK 1

            float noise(in float3 x)
            {
                float3 p = floor(x);
                float3 f = frac(x);
                f = f * f * (3.0 - 2.0 * f);
                float2 uv = (p.xy + float2(37.0, 239.0) * p.z) + f.xy;

                float2 rg = SAMPLE_TEXTURE2D_X_LOD(iChannel0, sampler_iChannel0, (uv + 0.5) / 256.0, 0.0).yx;
                return lerp(rg.x, rg.y, f.z) * 2.0 - 1.0;
            }

            float map5(in float3 p)
            {
                float3 q = p - float3(0.0, 0.1, 1.0) * iTime;
                float f;
                f = 0.50000 * noise(q);
                q = q * 2.02;
                f += 0.25000 * noise(q);
                q = q * 2.03;
                f += 0.12500 * noise(q);
                q = q * 2.01;
                f += 0.06250 * noise(q);
                q = q * 2.02;
                f += 0.03125 * noise(q);
                return clamp(height +index* p.y  + hd * f, 0.0, 1.0);
            }

            float map4(in float3 p)
            {
                float3 q = p - float3(0.0, 0.1, 1.0) * iTime;
                float f;
                f = 0.50000 * noise(q);
                q = q * 2.02;
                f += 0.25000 * noise(q);
                q = q * 2.03;
                f += 0.12500 * noise(q);
                q = q * 2.01;
                f += 0.06250 * noise(q);
                return clamp(height +index* p.y  + hd * f, 0.0, 1.0);
            }

            float map3(in float3 p)
            {
                float3 q = p - float3(0.0, 0.1, 1.0) * iTime;
                float f;
                f = 0.50000 * noise(q);
                q = q * 2.02;
                f += 0.25000 * noise(q);
                q = q * 2.03;
                f += 0.12500 * noise(q);
                return clamp(height +index* p.y   + hd * f, 0.0, 1.0);
            }

            float map2(in float3 p)
            {
                float3 q = p - float3(0.0, 0.1, 1.0) * iTime;
                float f;
                f = 0.50000 * noise(q);
                q = q * 2.02;
                f += 0.25000 * noise(q);;
                return clamp(height +index* p.y   + hd * f, 0.0, 1.0);
            }

            static float3 sundir ;

            #define MARCH(STEPS,MAPLOD) for(int i=0; i<STEPS; i++) { t += max(0.06,0.05*t); float3 pos = ro + t*rd;  if( sum.a>0.99 ) continue; float den = MAPLOD( pos ); if( den>0.01 ) { float dif = clamp((den - MAPLOD(pos+sunDiff*sundir))/0.6, 0.0, 1.0 ); float3 lin = Color01 * dif + Color02; float4  col = float4( lerp( LightColor.rgb, DarkColor, den ), den ); col.xyz *= lin; col.xyz = lerp( col.xyz, bgcol, 1.0-exp(skyIndex*t*t) ); col.w *= 0.4; col.rgb *= col.a; sum += col*(1.0-sum.a); }  }

            float4 raymarch(in float3 ro, in float3 rd, in float3 bgcol, in int2 px)
            {
                float4 sum = (0.0);
                
                float2 uv = (floor((px)) + 0.5) * iChannel1_TexelSize.xy;
                float t = 0.05 * SAMPLE_TEXTURE2D_X_LOD(iChannel1, sampler_iChannel1,uv, 0).x;
                MARCH(40 * _StepTime, map5);
                MARCH(40* _StepTime, map4);
                MARCH(30* _StepTime, map3);
                MARCH(30* _StepTime, map2);
                return clamp(sum, 0.0, 1.0);
            }

            float MAPLOD(float3 p)
            {
                return map2(p);
            }

            float4 test(int STEPS, in float3 ro, in float3 rd, in float3 bgcol)
            {
                float4 sum = (0.0);
                float t = 0.05*0.5;
                
                for (int i = 0; i < STEPS; i++)
                {
                    t += max(0.06, 0.05 * t);
                    float3 pos = ro + t * rd;
                    if (pos.y < -3.0 || pos.y > 2.0 || sum.a > 0.99) continue;
                    float den = MAPLOD(pos);
                    if (den > 0.01)
                    {
                        // 沿光照方向的浓度差
                        float dif = clamp((den - MAPLOD(pos + sunDiff * sundir)) / 0.6, 0.0, 1.0);
                        // 光照
                        float3 lin = Color01 * dif + Color02;

                        // 亮部和暗部颜色用浓度来Lerp
                        float4 col = float4(lerp(LightColor.xyz, DarkColor.xyz, den), den);
                        col.xyz *= lin;
                        // 和背景色随距离混合
                        col.xyz = lerp(col.xyz, bgcol, 1.0 - exp(-0.003 * t * t));
                        
                        col.w *= 0.4;
                        col.rgb *= col.a;
                        sum += col * (1.0 - sum.a);
                    }
                }
                
                return sum;
            }

            float4 render(in float3 ro, in float3 rd, in int2 px)
            {
                // background sky         
                float sun = clamp(dot(sundir, rd), 0.0, 1.0);
                float3 col = float3(0.6, 0.71, 0.75) - rd.y * 0.2 * float3(1.0, 0.5, 1.0) + 0.15 * 0.5;
                col += 0.2 * float3(1.0, .6, 0.1) * pow(sun, 8.0);
                // clouds        
                float4 res = raymarch(ro, rd, col, px);
                col = col * (1.0 - res.w) + res.xyz;
                // sun glare        
                col += float3(0.2, 0.08, 0.04) * pow(sun, 3.0);
                // col = res.xyz;
                return float4(col, 1.0);
            }

            float3 mainImage(in float2 screen_pos)
            {
                float2 uv = screen_pos / _ScreenParams;

                // camera
                float3 ro = _WorldSpaceCameraPos;

                float3 rd = ComputeWorldSpacePosition(uv, 0, UNITY_MATRIX_I_VP);

                rd = rd - ro;
                rd = normalize(rd);

                return render(ro, rd, int2(screen_pos - 0.5));
            }

            


            struct Attributes
            {
                float4 positionOS : POSITION;
                float2 uv : TEXCOORD0;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            struct Varyings
            {
                float4 positionHCS : SV_POSITION;
                float2 uv : TEXCOORD0;
                float3 viewPos : TEXCOORD1;
                UNITY_VERTEX_OUTPUT_STEREO
            };

            Varyings vert(Attributes input)
            {
                Varyings output;
                UNITY_SETUP_INSTANCE_ID(input);
                UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
                output.positionHCS = float4(input.positionOS.xy, 0.5, 0.5);
                output.viewPos = mul(UNITY_MATRIX_I_P, output.positionHCS).xyz;
                output.uv = input.uv;
                return output;
            }

            half4 frag(Varyings input):SV_Target
            {
                UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);

                sundir = GetMainLight().direction;

                const float2 screen_pos = input.positionHCS.xy;

                float3 color = mainImage(screen_pos);
                // post
                return float4(color, 1.0);
            }
            ENDHLSL
        }
    }
}

体积云复刻
https://www.kuanmi.top/2022/07/14/Cloud/
作者
KuanMi
发布于
2022年7月14日
许可协议