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
}
}
}