Aetheria/Assets/Shaders/Volumetric.cginc
Reinier Vens 47e500e1ce Playability
Fixed loadout generator tutorial edge cases
Recreated missing items
Created field shader & test scene
2022-08-08 22:43:55 +01:00

247 lines
7.9 KiB
HLSL

#pragma multi_compile __ FLOW_GLOBAL
#pragma multi_compile __ FLOW_SLOPE
#pragma multi_compile __ NOISE_SLOPE
#include "UnityCG.cginc"
uniform sampler2D _NebulaSurfaceHeight;
float4 _NebulaSurfaceHeight_TexelSize;
uniform sampler2D _NebulaPatch;
uniform sampler2D _NebulaPatchHeight;
uniform sampler2D _NebulaTint;
float4 _NebulaTint_TexelSize;
uniform sampler2D _FluidVelocity;
uniform float3 _GridTransform;
uniform float3 _FluidTransform;
uniform half _NebulaFillDensity,
_NebulaFillDistance,
_NebulaFillExponent,
_NebulaFillOffset,
_NebulaPatchDensity,
_NebulaFloorOffset,
_NebulaFloorBlend,
_NebulaPatchBlend,
_NebulaLuminance,
_TintExponent,
_TintLodExponent,
_NebulaNoiseScale,
_NebulaNoiseExponent,
_NebulaNoiseAmplitude,
_NebulaNoiseSpeed,
_NebulaNoiseSlopeExponent,
_FlowScale,
_FlowAmplitude,
_FlowScroll,
_FlowPeriod,
_FlowSlopeAmplitude,
_FlowSwirlAmplitude,
_SafetyDistance,
_DynamicLodLow,
_DynamicLodHigh,
_DynamicIntensity,
_DynamicSkyBoost;
inline float tri(in float x){return abs(frac(x)-.5);}
inline float3 tri3(in float3 p){return float3( tri(p.z+tri(p.y*1.)), tri(p.z+tri(p.x*1.)), tri(p.y+tri(p.x*1.)));}
float triNoise3d(in float3 p)
{
float z=1.4;
float rz = 0.001;
float3 bp = p;
for (float i=0.; i<=1.; i++ )
{
float3 dg = tri3(bp * 2.);
p += dg + _Time.y * _NebulaNoiseSpeed;
bp *= 1.8;
z *= 1.5;
p *= 1.2;
rz+= tri(p.z+tri(p.x+tri(p.y)))/z;
bp += 0.14;
}
return rz;
}
float3 Tri3D( float3 P )
{
float3 t1 = normalize(tri3(P));
float3 t2 = normalize(tri3(P * 1.61803398875));
return cross(t1,t2);
}
float parabola( float x, float k )
{
return pow( 4.0*x*(1.0-x), k );
}
float2 getUV(float2 pos)
{
return -(pos-_GridTransform.xy)/_GridTransform.z + float2(.5,.5);
}
float2 getUVFluid(float2 pos)
{
return (pos-_FluidTransform.xy)/_FluidTransform.z + float2(.5,.5);
}
float cloudDensity(float3 pos, float surfaceDisp)
{
float2 uv = getUV(pos.xz);
const float dist = pos.y + surfaceDisp - _NebulaFloorOffset;
const float patch = tex2Dlod(_NebulaPatch, half4(uv, 0, 0)).r;
const float patchDisp = tex2Dlod(_NebulaPatchHeight, half4(uv, 0, 0)).r;
const float patchDensity = saturate((-abs(pos.y+patchDisp - _NebulaFloorOffset)+patch)/_NebulaPatchBlend)*_NebulaPatchDensity;
const float floorDist = -dist;
const float floorDensity = floorDist/_NebulaFloorBlend;
return patchDensity + max(0,floorDensity);
}
// TODO: Get this working?
float2 texFlow(float3 pos)
{
const float2 fluidUv = getUVFluid(pos.xz);
if(any(fluidUv<0)||any(fluidUv>1)) return 0;
const float2 fluidSample = tex2Dlod(_FluidVelocity, half4(fluidUv, 0, 0)).xy;
// TODO: remove magic number for fluid texture dimensions
return float3(fluidSample.x,0,fluidSample.y) * (512 / _FluidTransform.z);
}
float2 gravGradient (float2 uv)
{
return float2(
tex2Dlod(_NebulaSurfaceHeight, float4(uv.x + _NebulaSurfaceHeight_TexelSize.x, uv.y, 0, 0)).r -
tex2Dlod(_NebulaSurfaceHeight, float4(uv.x - _NebulaSurfaceHeight_TexelSize.x, uv.y, 0, 0)).r,
tex2Dlod(_NebulaSurfaceHeight, float4(uv.x, uv.y + _NebulaSurfaceHeight_TexelSize.y, 0, 0)).r -
tex2Dlod(_NebulaSurfaceHeight, float4(uv.x, uv.y - _NebulaSurfaceHeight_TexelSize.y, 0, 0)).r
);
}
float3 gravNormal (float2 grad)
{
float3 normal = float3(-grad.x, _NebulaSurfaceHeight_TexelSize.x*2*_GridTransform.z, -grad.y);
return normalize(normal);
}
float3 globalFlow(float3 pos)
{
float3 flowSample = Tri3D( pos / _FlowScale - float3(0,_FlowScroll,0) ) * _FlowAmplitude;
flowSample.y *= .5;
return flowSample;
}
float3 slopeFlow(float2 grad)
{
float2 ngrad = normalize(grad);
return float3(ngrad.y, 0, -ngrad.x) * _FlowSwirlAmplitude + float3(ngrad.x, 0, ngrad.y) * _FlowSlopeAmplitude;
}
float3 slopeFlow(float3 pos)
{
return slopeFlow(gravGradient(getUV(pos.xz)));
}
float3 flow(float3 pos)
{
float3 flow = 0;
#if FLOW_GLOBAL
flow += globalFlow(pos);
#endif
#if FLOW_SLOPE
flow += slopeFlow(pos);
#endif
return flow;
}
float tri2(in float x){return 1-2*abs(frac(x)-.5);}
float density(float3 pos)
{
const float2 uv = getUV(pos.xz);
const float surfaceDisp = tex2Dlod(_NebulaSurfaceHeight, half4(uv, 0, 0)).r;
const float dist = pos.y + surfaceDisp;
float d = pow(smoothstep(0, _NebulaFillDistance, abs(dist+_NebulaFillOffset)),-_NebulaFillExponent) * _NebulaFillDensity;
if(dist < _SafetyDistance)
{
float heightFade = smoothstep(_SafetyDistance,_SafetyDistance*.75,dist);
float exponent = _NebulaNoiseExponent;
#if NOISE_SLOPE
const float2 grad = gravGradient(uv);
const float3 normal = gravNormal(grad);
float flatness = 1 - dot(normal,float3(0,1,0));
flatness = pow(flatness,_NebulaNoiseSlopeExponent);
heightFade *= flatness;
exponent *= flatness;
#endif
#if FLOW_GLOBAL || FLOW_SLOPE
float3 fl = 0;
#if FLOW_GLOBAL
fl += globalFlow(pos);
#endif
#if FLOW_SLOPE
#if NOISE_SLOPE
fl += slopeFlow(grad);
#else
fl += slopeFlow(pos);
#endif
#endif
const float lerp1 = frac(_Time.y / _FlowPeriod);
const float lerp2 = frac(_Time.y / _FlowPeriod + .5);
const float noise1 = pow(triNoise3d((pos+fl.xyz * (lerp1 - .5) * _FlowPeriod) / _NebulaNoiseScale),exponent) * tri2(lerp1);
const float noise2 = pow(triNoise3d((pos+fl.xyz * (lerp2 - .5) * _FlowPeriod) / _NebulaNoiseScale),exponent) * tri2(lerp2);
pos.y += (noise1 + noise2) * heightFade * _NebulaNoiseAmplitude;
const float lerp3 = frac(_Time.y / _FlowPeriod * 2 + .25);
const float lerp4 = frac(_Time.y / _FlowPeriod * 2 + .75);
const float noise3 = pow(triNoise3d((pos+fl.xyz * (lerp3 - .5) * _FlowPeriod / 2) / _NebulaNoiseScale * 8), exponent) * tri2(lerp3);
const float noise4 = pow(triNoise3d((pos+fl.xyz * (lerp4 - .5) * _FlowPeriod / 2) / _NebulaNoiseScale * 8), exponent) * tri2(lerp4);
pos.y -= (noise3 + noise4) * heightFade * _NebulaNoiseAmplitude / 2;
#else
const float noise1 = pow(triNoise3d(pos / _NebulaNoiseScale), exponent) * _NebulaNoiseAmplitude;
const float noise2 = pow(triNoise3d(pos / _NebulaNoiseScale * 8), exponent) * _NebulaNoiseAmplitude / 2;
pos.y += (noise1 - noise2) * heightFade;
#endif
d += cloudDensity(pos, surfaceDisp);
}
return d;
}
float4 VolumeSampleColor(float3 pos)
{
float d = density(pos);
float2 uv = getUV(pos.xz);
float3 tint = tex2Dlod(_NebulaTint, float4(uv.x, uv.y, 0, pow(max(.01,d), _TintLodExponent)));
return float4(tint, d);
}
float2 tintGradient (float2 uv)
{
return float2(
length(tex2Dlod(_NebulaTint, float4(uv.x + _NebulaTint_TexelSize.x, uv.y, 0, 0))) - length(tex2Dlod(_NebulaTint, float4(uv.x - _NebulaTint_TexelSize.x, uv.y, 0, 0))),
length(tex2Dlod(_NebulaTint, float4(uv.x, uv.y + _NebulaTint_TexelSize.y, 0, 0))) - length(tex2Dlod(_NebulaTint, float4(uv.x, uv.y - _NebulaTint_TexelSize.y, 0, 0)))
);
}
float3 VolumeSampleColorSimple(float3 pos, float3 normal)
{
float2 uv = getUV(pos.xz);
float3 low = tex2Dlod(_NebulaTint, float4(uv.x, uv.y, 0, _DynamicLodLow)).rgb;
float3 high = tex2Dlod(_NebulaTint, float4(uv.x, uv.y, 0, _DynamicLodHigh)).rgb * _DynamicSkyBoost;
float upness = dot(normal, float3(0,1,0));
//float lambert = 2 - dot(normalize(normal.xz), normalize(tintGradient(uv)));
return lerp(low,high,sqrt((upness+1)/2)) * _DynamicIntensity / (density(pos)+1);
}