www.pudn.com > SnowAccumulation.zip > SnowShaderUtils.fxh, change:2007-08-14,size:4426b
/*
A couple of functions used by the different classes of snow techniques.
*/
/*
Implements a perlin-style noise lookup using a 3D texture. Returns a (-1..1) value
*/
#ifdef NOISESAMPLER
#ifndef NOISEOCTAVES
#define NOISEOCTAVES 3.0
#endif
FPTYPE noise(FPTYPE3 uvw)
{
// $$ Note, these values, are tweakable. I tweaked a little off the standard because I liked these better. YMMV
FPTYPE sum = 0;
FPTYPE amp = 1;
FPTYPE3 p = uvw;
FPTYPE lacunarity = 2;
FPTYPE gain = 0.75;
int octaves = (int)NOISEOCTAVES;
for(int i=0;i<octaves;i++)
{
sum += amp * abs(tex3D(NOISESAMPLER, p.xyz));
p *= lacunarity;
amp *= gain;
}
return 2*sum-1;
}
#endif
/*
This is used by the vertex shader in the SM3.0 technique to get the exposure for a vertex.
*/
#ifdef EXPOSURESAMPLER_VERTEX
float exposureAtVertex(float2 uv, float depth)
{
float exposure = 0;
if(uv.x > 0.0 && uv.x 1.0 && uv.y > 0.0 && uv.y 1.0 )
{
float sampledepth = tex2Dlod(EXPOSURESAMPLER_VERTEX,float4(uv.xy,0,0));
if(depth sampledepth+SnowBias) // SnowBias is for depth fighting artifacts
{
exposure = 1;
}
}
return exposure;
}
#endif
#ifdef EXPOSURESAMPLER_PIXEL
FPTYPE exposureAtPixel(FPTYPE2 uv, FPTYPE depth)
{
FPTYPE exposure = 0;
FPTYPE sampledepth = tex2D(EXPOSURESAMPLER_PIXEL,FPTYPE4(uv.xy,0,0));
if(depth sampledepth+SnowBias) // SnowBias is for depth fighting artifacts
{
exposure = 1;
}
return exposure;
}
#endif
/*
Lights a pixel using the exposure map, and noise to produce a really nice effect.
*/
FPTYPE4 SnowPixel(FPTYPE2 TextureUV, FPTYPE3 Normal, FPTYPE3 OrthoUVnDepth, FPTYPE3 ToView,
const bool bNoiseNormal, const bool bNoiseIncline, const bool bMultiSample)
{
// Prescale UV for noise, to have it tile a little more.
FPTYPE3 noiseUVW = 30.0*OrthoUVnDepth.xyz;
// Then just deterministically remap the coords to get 2 noise values to offset the normal
FPTYPE3 noiseVec = FPTYPE3(noise(noiseUVW),0,noise(noiseUVW.yzx));
// Calculate the per pixel exposure value. multi-sampling around us to average
FPTYPE exposure = 0;
FPTYPE pixelOrthoDepth = OrthoUVnDepth.z;
// current position
exposure += exposureAtPixel(OrthoUVnDepth,pixelOrthoDepth);
if(bMultiSample) // We want to sample the exposure map a couple times to blur the egdes a little
{
// A box around us.
FPTYPE2 direction;
FPTYPE2 texelSize = SampleDistance / FPTYPE2(SceneWidth,SceneHeight);
direction = FPTYPE2(0,1);
exposure += exposureAtPixel(OrthoUVnDepth.xy+direction*texelSize,pixelOrthoDepth);
direction = FPTYPE2(1,0);
exposure += exposureAtPixel(OrthoUVnDepth.xy+direction*texelSize,pixelOrthoDepth);
direction = FPTYPE2(0,-1);
exposure += exposureAtPixel(OrthoUVnDepth.xy+direction*texelSize,pixelOrthoDepth);
direction = FPTYPE2(-1,0);
exposure += exposureAtPixel(OrthoUVnDepth.xy+direction*texelSize,pixelOrthoDepth);
exposure /= 5;
}
FPTYPE3 vNormalWorldSpace = ((2*Normal)-FPTYPE3(1,1,1));
if(bNoiseNormal) vNormalWorldSpace = normalize(normalDistortionAmount*noiseVec + vNormalWorldSpace);
FPTYPE dotNorm = vNormalWorldSpace.y; // effectively dot the normal with the up vector
if(dotNorm = 0) dotNorm = 0;
else
{
if(bNoiseIncline)
{
dotNorm = saturate(dotNorm+dotNormalDistortionAmount*noiseVec.x);
}
}
FPTYPE3 Vn = normalize(2*ToView-1);
FPTYPE3 Hn = normalize(Vn + g_LightDir);
FPTYPE hdn = dot(Hn,vNormalWorldSpace);
FPTYPE ldn = dot(g_LightDir,vNormalWorldSpace);
FPTYPE4 litVec = lit(ldn,hdn,SpecExpon);
FPTYPE3 diffContrib = litVec.y * g_LightDiffuse;
// $$4 Note this is calculated before the full exposure and is thus not based on incline...
// This is because we dont want to tie the specular highlight to the noise function too directly, it doesn't look good.
FPTYPE3 specContrib = exposure*((litVec.y * litVec.z * Ks) * g_LightDiffuse);
// now also tweak based on angle of incline, add in a base %
exposure = BaseSnowPct + exposure*dotNorm*(1-BaseSnowPct);
// choose a color based on exposure
FPTYPE3 diffuseColor = exposure*g_SnowColor + (1-exposure)*tex2D(MeshTextureSampler, TextureUV);
FPTYPE diffuseSpec = saturate(g_LightAmbient+Kd)*diffContrib+Ks*specContrib;
return FPTYPE4(diffuseColor.xyz*(diffuseSpec),1);
}