WorleyUtilities文件路径如下:
D:…\Library\PackageCache\com.unity.render-pipelines.high-definition@14.0.8\Runtime\Lighting\VolumetricClouds\WorleyUtilities.hlsl
文件代码如下
#ifndef WORLEY_UTILITIES_H #define WORLEY_UTILITIES_H // Implementation inspired from https://www.shadertoy.com/view/3dVXDc // Hash by David_Hoskins #define UI0 1597334673U #define UI1 3812015801U #define UI2 uint2(UI0, UI1) #define UI3 uint3(UI0, UI1, 2798796415U) #define UIF (1.0 / float(0xffffffffU)) float3 hash33(float3 p) { uint3 q = uint3(int3(p)) * UI3; q = (q.x ^ q.y ^ q.z) * UI3; return -1. + 2. * float3(q) * UIF; } // Density remapping function float remap(float x, float a, float b, float c, float d) { return (((x - a) / (b - a)) * (d - c)) + c; } // Gradient noise by iq (modified to be tileable) float GradientNoise(float3 x, float freq) { // grid float3 p = floor(x); float3 w = frac(x); // quintic interpolant float3 u = w * w * w * (w * (w * 6. - 15.) + 10.); // gradients float3 ga = hash33(fmod(p + float3(0., 0., 0.), freq)); float3 gb = hash33(fmod(p + float3(1., 0., 0.), freq)); float3 gc = hash33(fmod(p + float3(0., 1., 0.), freq)); float3 gd = hash33(fmod(p + float3(1., 1., 0.), freq)); float3 ge = hash33(fmod(p + float3(0., 0., 1.), freq)); float3 gf = hash33(fmod(p + float3(1., 0., 1.), freq)); float3 gg = hash33(fmod(p + float3(0., 1., 1.), freq)); float3 gh = hash33(fmod(p + float3(1., 1., 1.), freq)); // projections float va = dot(ga, w - float3(0., 0., 0.)); float vb = dot(gb, w - float3(1., 0., 0.)); float vc = dot(gc, w - float3(0., 1., 0.)); float vd = dot(gd, w - float3(1., 1., 0.)); float ve = dot(ge, w - float3(0., 0., 1.)); float vf = dot(gf, w - float3(1., 0., 1.)); float vg = dot(gg, w - float3(0., 1., 1.)); float vh = dot(gh, w - float3(1., 1., 1.)); // interpolation return va + u.x * (vb - va) + u.y * (vc - va) + u.z * (ve - va) + u.x * u.y * (va - vb - vc + vd) + u.y * u.z * (va - vc - ve + vg) + u.z * u.x * (va - vb - ve + vf) + u.x * u.y * u.z * (-va + vb + vc - vd + ve - vf - vg + vh); } // There is a difference between the original implementation's mod and hlsl's fmod, so we mimic the glsl version for the algorithm #define Modulo(x,y) (x-y*floor(x/y)) // Tileable 3D worley noise float WorleyNoise(float3 uv, float freq) { float3 id = floor(uv); float3 p = frac(uv); float minDist = 10000.; for (float x = -1.; x <= 1.; ++x) { for (float y = -1.; y <= 1.; ++y) { for (float z = -1.; z <= 1.; ++z) { float3 offset = float3(x, y, z); float3 idOffset = id + offset; float3 h = hash33(Modulo(idOffset.xyz, freq)) * .5 + .5; h += offset; float3 d = p - h; minDist = min(minDist, dot(d, d)); } } } return minDist; } float EvaluatePerlinFractalBrownianMotion(float3 position, float initialFrequence, int numOctaves) { const float G = exp2(-0.85); // Accumulation values float amplitude = 1.0; float frequence = initialFrequence; float result = 0.0; for (int i = 0; i < numOctaves; ++i) { result += amplitude * GradientNoise(position * frequence, frequence); frequence *= 2.0; amplitude *= G; } return result; } #endif // WORLEY_UTILITIES_H
Implementation inspired from:https://www.shadertoy.com/view/3dVXDc
:Hash by David_Hoskins
于是我找了一下:
然后转译到ShaderLab中:
Shader "Unlit/Smoke" { Properties { _MainTex ("Texture", 2D) = "white" {} } SubShader { Tags { "RenderType"="Opaque" } LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag // make fog work #pragma multi_compile_fog #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; sampler2D _MainTex; float4 _MainTex_ST; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv,_MainTex); return o; } float remap(float a,float b,float c,float d,float e) { return d + (a - b) * (e - d) / (c - b); } fixed4 frag (v2f i) : SV_Target { fixed2 st = i.uv; fixed2 uv = i.uv; st.x *= 5.; // 5 columns for different noises uv -= .02 * _Time.y; fixed3 col = fixed3(0,0,0); float perlinWorley = tex2D(_MainTex, uv * 0.5).x; // worley fbms with different frequencies fixed3 worley = tex2D(_MainTex, uv ).yzw; float wfbm = worley.x * .625 + worley.y * .125 + worley.z * .25; // cloud shape modeled after the GPU Pro 7 chapter float cloud = remap(perlinWorley, wfbm - 1., 1., 0., 1.); cloud = remap(cloud, .85, 1., 0., 1.); // fake cloud coverage if (st.x < 1.) col += perlinWorley; else if(st.x < 2.) col += worley.x; else if(st.x < 3.) col += worley.y; else if(st.x < 4.) col += worley.z; else if(st.x < 5.) col += cloud; // column dividers float div = smoothstep(.01, 0., abs(st.x - 1.)); div += smoothstep(.01, 0., abs(st.x - 2.)); div += smoothstep(.01, 0., abs(st.x - 3.)); div += smoothstep(.01, 0., abs(st.x - 4.)); col = lerp(col, fixed3(0., 0., .866), div); fixed4 fragColor = fixed4(col,1.0); return fragColor; } ENDCG } } }
存档:
在GLSL着色语言内“remap”函数,在ShaderLab中报错:
float remap(float a,float b,float c,float d,float e) { return d + (a - b) * (e - d) / (c - b); }
在GLSL着色语言内mix函数,在Unity ShaderLab中对应的是lerp。
col = lerp(col, fixed3(0., 0., .866), div);