You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

442 lines
12 KiB

#ifndef FOG_VOLUME_COMMON_INCLUDED
#define FOG_VOLUME_COMMON_INCLUDED
float3 VolumeSpaceCoords = 0;
half VerticalGrad;
half2 heightGradient;
half HeightAtten;
float3 VolumeSpaceCoordsWorldSpace;
//#ifdef VOLUMETRIC_SHADOWS
half3 VolumeShadow = 1;
#define _GeneralShadowOffset 0.001f
#define bias 0
//Shadow params
uniform float4 _ShadowCameraPosition;
uniform float4x4 _ShadowCameraProjection;
uniform float _ShadowCameraSize;
uniform sampler2D _ShadowTexture;
//#define _VolumetricShadowsEnabled 0
uniform int _VolumetricShadowsEnabled = 0;
float4 when_eq(float4 x, float4 y) {
return 1.0 - abs(sign(x - y));
}
float3 when_eq(float3 x, float3 y) {
return 1.0 - abs(sign(x - y));
}
float when_eq(float x, float y) {
return 1.0 - abs(sign(x - y));
}
float FrameShadow(in float2 shadowUVs, in float3 worldPos) {
float FinalShadow = 1;
float2 ShadowMap = tex2Dlod(_ShadowTexture, float4(shadowUVs, 0, 0)).rg;
float d = ShadowMap.x;
//if (d < .0001)FinalShadow = 1.0;
//else
//{
float theLength = distance(worldPos, _ShadowCameraPosition);
FinalShadow = theLength < d + bias ? 1.0f : 0.0f;
//}
//fade before reaching the end
half edges = ShadowMap.y;
return lerp(1,FinalShadow, edges);
}
//#endif
float sdSphere(float3 p, float s)
{
return (length(p) - s);
}
float sdBox(float3 p, float3 b)
{
float3 d = abs(p) - b;
d = (min(max(d.x, max(d.y, d.z)), 0.0) + length(max(d, 0.0)));
return d;
}
float udBox(float3 p, float3 b)
{
return length(max(abs(p) - b, 0.0));
}
float PrimitiveShape(fixed ShapeType, float3 p, float3 s)
{
if (ShapeType <= 1.0f)//Box
return sdBox(p, s);
else
if (ShapeType <= 2.0f)//Sphere
return sdSphere(p, s);
else return .0f;
}
float nrand(float2 ScreenUVs)
{
return frac(sin(ScreenUVs.x * 12.9898 + ScreenUVs.y * 78.233) * 43758.5453);
}
float remap_tri(float v)
{
float orig = v * 2.0 - 1.0;
v = max(-1.0, orig / sqrt(abs(orig)));
return v - sign(orig) + 0.5;
}
bool IntersectBox(float3 startpoint, float3 direction, float3 boxmin, float3 boxmax, out float tnear, out float tfar)
{
// compute intersection of ray with all six bbox planes
float3 invR = 1.0 / direction;
float3 tbot = invR * (boxmin.xyz - startpoint);
float3 ttop = invR * (boxmax.xyz - startpoint);
// re-order intersections to find smallest and largest on each axis
float3 tmin = min(ttop, tbot);
float3 tmax = max(ttop, tbot);
// find the largest tmin and the smallest tmax
float2 t0 = max(tmin.xx, tmin.yz);
tnear = max(t0.x, t0.y);
t0 = min(tmax.xx, tmax.yz);
tfar = min(t0.x, t0.y);
// check for hit
bool hit;
if ((tnear > tfar))
hit = false;
else
hit = true;
return hit;
}
half3 ToneMap(half3 x, half exposure)
{
//Photographic
return 1 - exp2(-x * exposure);
}
#define PI 3.1416
//http://zurich.disneyresearch.com/~wjarosz/publications/dissertation/chapter4.pdf
float Henyey(float3 E, float3 L, float mieDirectionalG)
{
float theta = saturate(dot(E, L));
return (1.0 / (4.0 * PI)) * ((1.0 - mieDirectionalG * mieDirectionalG) / pow(1.0 - 2.0 * mieDirectionalG * theta + mieDirectionalG * mieDirectionalG, 1.5));
}
half3 ContrastF(half3 pixelColor, fixed contrast)
{
return saturate(((pixelColor.rgb - 0.5f) * max(contrast, 0)) + 0.5f);
}
float3 rotate(float3 p, float rot)
{
float3 r = 0;
#ifdef Twirl_X
float3x3 rx = float3x3(1.0, 0.0, 0.0, 0.0, cos(rot), sin(rot), 0.0, -sin(rot), cos(rot));
r = mul(p, rx);
#endif
#ifdef Twirl_Y
float3x3 ry = float3x3(cos(rot), 0.0, -sin(rot), 0.0, 1.0, 0.0, sin(rot), 0.0, cos(rot));
r = mul(p, ry);
#endif
#ifdef Twirl_Z
float3x3 rz = float3x3(cos(rot), -sin(rot), 0.0, sin(rot), cos(rot), 0.0, 0.0, 0.0, 1.0);
r = mul(p, rz);
#endif
return r;
}
half HeightGradient(float H, half H0, half Hmax)
{
return saturate((H - H0) / (Hmax - H0));
}
half Threshold(float a, float Gain, float Contrast)
{
float input = a * Gain;
//float thresh = input - Contrast;
float thresh = ContrastF(input, Contrast);
return saturate(lerp(0.0f, input, thresh));
}
half PrimitiveAccum = 1;
#ifdef _FOG_VOLUME_NOISE
float NoiseSamplerLoop(float3 p)
{
float n = 0, iter = 1;
for (int i = 0; i < Octaves; i++)
{
p /= 1 + i*.06;
p += Speed.rgb *_BaseRelativeSpeed * (i*.15 + 1);
#ifdef EARTH_CLOUD_STYLE
n += tex3Dlod(_NoiseVolume, float4(p * float3(.5, 1, .5), 0));
n += tex3Dlod(_NoiseVolume, float4(p*.3, 0))*2+ (heightGradient.x);
n = (n-1); //n *= n*.57;
#else
n += tex3Dlod(_NoiseVolume, float4(p, 0));
#endif
}
n = n / Octaves;
/*if (Octaves > 1)
{
n++;
n *= tex3Dlod(_NoiseVolume, float4(p *.75, 0));
}*/
return n;
}
float noise(in float3 p, half DistanceFade)
{
float Volume = 0;
float lowFreqScale = BaseTiling;
half NoiseBaseLayers = 0;
if (Coverage > 0.01)
NoiseBaseLayers = NoiseSamplerLoop(p * lowFreqScale);
#ifdef DF
NoiseBaseLayers = Threshold(NoiseBaseLayers, Coverage * NoiseAtten*PrimitiveAccum, threshold);
#else
NoiseBaseLayers = Threshold(NoiseBaseLayers, Coverage * NoiseAtten, threshold);
#endif
half NoiseDetail = 0;
half BaseMask = saturate((1 - NoiseBaseLayers * _DetailMaskingThreshold));
if (DistanceFade > 0 && NoiseBaseLayers>0 && BaseMask>0)//no me samplees donde ya es opaco del tó
{
NoiseDetail += BaseMask*DistanceFade*(tex3Dlod(_NoiseVolume, float4(p*DetailTiling + Speed * _DetailRelativeSpeed, 0)).r);
if (Octaves > 1 )
NoiseDetail += DistanceFade*(tex3Dlod(_NoiseVolume,
//size and offset
float4(p * .5 * DetailTiling + .5
//distortion
+ NoiseDetail * _Curl * BaseMask * 2.0 - 1.0
//animation
+ Speed * _DetailRelativeSpeed, 0)).r) * 1.5 * BaseMask;
NoiseDetail = Threshold(NoiseDetail, 1, 0);
}
//base layer (coverage)
Volume += NoiseBaseLayers;
//add detail layer
Volume -= NoiseDetail * _NoiseDetailRange;
Volume *= 1 + _NoiseDetailRange;
Volume *= NoiseDensity;
return saturate(Volume);
}
//http://flafla2.github.io/2016/10/01/raymarching.html
float3 calcNormal(in float3 pos, half DistanceFade)
{
// epsilon - used to approximate dx when taking the derivative
const float2 eps = float2(NormalDistance, 0.0);
// The idea here is to find the "gradient" of the distance field at pos
// Remember, the distance field is not boolean - even if you are inside an object
// the number is negative, so this calculation still works.
// Essentially you are approximating the derivative of the distance field at this point.
float3 nor = float3(
noise(pos + eps.xyy, DistanceFade).x - noise(pos - eps.xyy, DistanceFade).x,
noise(pos + eps.yxy, DistanceFade).x - noise(pos - eps.yxy, DistanceFade).x,
noise(pos + eps.yyx, DistanceFade).x - noise(pos - eps.yyx, DistanceFade).x);
return normalize(nor);
}
#endif
#if _FOG_VOLUME_NOISE && _SHADE
half ShadowGrad(half ShadowThreshold, half SampleDiff)
{
return saturate(ShadowThreshold / (ShadowThreshold - SampleDiff));
}
half ShadowShift = .05;
//#define _SelfShadowSteps 20
float Shadow(float3 ShadowCoords, v2f i, half detailDist, half3 LightVector, half NoiseAtten)
{
float ShadowThreshold = noise(ShadowCoords, detailDist);
float3 LightStep = /*_LightLocalDirection*/LightVector / (float)_SelfShadowSteps;
float accum = 0;
float3 ShadowCoordsStep = ShadowCoords;
for (int k = 0; k <= _SelfShadowSteps && NoiseAtten>0; k++, ShadowCoordsStep += LightStep)
{
float NoiseSample = 0;
float SampleDiff = 0;
if (ShadowThreshold > 0 && accum < 1)
{
NoiseSample = noise(ShadowCoordsStep, detailDist);
SampleDiff = ShadowThreshold - NoiseSample;
if (SampleDiff <= 0)
{
if (ShadowThreshold > 0)
{
accum += 1 - ShadowGrad(ShadowThreshold, SampleDiff);
}
else
{
accum += 1;
}
}
else
if (ShadowThreshold <= 0)
{
accum += ShadowGrad(ShadowThreshold, SampleDiff);
}
}
}
//return accum;
return saturate(1 - accum);
}
#endif
float4 PointLight(float3 LightPosition, float3 VolumePosition,
half size, half3 color, half LightAttenuation, v2f i)
{
//#define ATTEN_METHOD_2
half d = distance(LightPosition, VolumePosition) / size;
float Attenuation = 0;
half UnityScaleMatch = 5;
//https://en.wikipedia.org/wiki/Optical_depth
#ifdef ATTEN_METHOD_1
Attenuation = exp(-d)*UnityScaleMatch;
#endif
#ifdef ATTEN_METHOD_2
Attenuation = UnityScaleMatch / (4 * PI*d*d);
#endif
//Linear
#ifdef ATTEN_METHOD_3
Attenuation = saturate(1 - d / UnityScaleMatch);
#endif
return float4(Attenuation * LightAttenuation * color, Attenuation* LightAttenuation);
}
float4 SpotLight(float3 LightPosition, float3 VolumePosition,
half size, half3 color, half LightAttenuation, float4 Direction, half Angle, half fallof, v2f i)
{
float3 spotDir = normalize(Direction.xyz);
Angle *= .5;//Unity match
float coneAngle = Angle;//inner angle
float coneDelta = Angle + fallof;//outer angle
float3 lray = normalize(LightPosition - VolumePosition);
float SpotCone = (dot(lray, -spotDir) - cos(radians(coneDelta))) / (cos(radians(coneAngle)) - cos(radians(coneDelta)));
SpotCone = max(0, SpotCone);
float4 _PointLight = PointLight(LightPosition, VolumePosition,
size, color, LightAttenuation, i);
return SpotCone * _PointLight;
// half d = distance(LightPosition, VolumePosition) / size;
// float Attenuation = 0;
// half UnityScaleMatch = 5;
// //https://en.wikipedia.org/wiki/Optical_depth
//#ifdef ATTEN_METHOD_1
// Attenuation = exp(-d)*UnityScaleMatch;
//#endif
//
//#ifdef ATTEN_METHOD_2
// Attenuation = UnityScaleMatch / (4 * PI*d*d);
//#endif
//
// //Linear
//#ifdef ATTEN_METHOD_3
// Attenuation = saturate(1 - d / UnityScaleMatch);
//
//
//#endif
// return float4(Attenuation * SpotCone * LightAttenuation * color, Attenuation* LightAttenuation);
}
#if UNITY_LIGHT_PROBE_PROXY_VOLUME
// normal should be normalized, w=1.0
half3 FVSHEvalLinearL0L1_SampleProbeVolume(half4 normal, float3 worldPos)
{
const float transformToLocal = unity_ProbeVolumeParams.y;
const float texelSizeX = unity_ProbeVolumeParams.z;
//The SH coefficients textures and probe occlusion are packed into 1 atlas.
//-------------------------
//| ShR | ShG | ShB | Occ |
//-------------------------
float3 position = (transformToLocal == 1.0f) ? mul(unity_ProbeVolumeWorldToObject, float4(worldPos, 1.0)).xyz : worldPos;
float3 texCoord = (position - unity_ProbeVolumeMin.xyz) * unity_ProbeVolumeSizeInv.xyz;
texCoord.x = texCoord.x * 0.25f;
// We need to compute proper X coordinate to sample.
// Clamp the coordinate otherwize we'll have leaking between RGB coefficients
float texCoordX = clamp(texCoord.x, 0.5f * texelSizeX, 0.25f - 0.5f * texelSizeX);
// sampler state comes from SHr (all SH textures share the same sampler)
texCoord.x = texCoordX;
half4 SHAr = UNITY_SAMPLE_TEX3D_SAMPLER_LOD(unity_ProbeVolumeSH, unity_ProbeVolumeSH, texCoord, 0);
texCoord.x = texCoordX + 0.25f;
half4 SHAg = UNITY_SAMPLE_TEX3D_SAMPLER_LOD(unity_ProbeVolumeSH, unity_ProbeVolumeSH, texCoord, 0);
texCoord.x = texCoordX + 0.5f;
half4 SHAb = UNITY_SAMPLE_TEX3D_SAMPLER_LOD(unity_ProbeVolumeSH, unity_ProbeVolumeSH, texCoord, 0);
// Linear + constant polynomial terms
half3 x1;
x1.r = dot(SHAr, normal);
x1.g = dot(SHAg, normal);
x1.b = dot(SHAb, normal);
return x1;
}
#endif
half3 ShadeSHPerPixel(half3 normal, half3 ambient, float3 worldPos)
{
half3 ambient_contrib = 0.0;
// L2 per-vertex, L0..L1 & gamma-correction per-pixel
// Ambient in this case is expected to be always Linear, see ShadeSHPerVertex()
#if UNITY_LIGHT_PROBE_PROXY_VOLUME
if (unity_ProbeVolumeParams.x == 1.0)
ambient_contrib = FVSHEvalLinearL0L1_SampleProbeVolume(half4(normal, 1.0), worldPos);
else
ambient_contrib = SHEvalLinearL0L1(half4(normal, 1.0));
#else
ambient_contrib = 1;// SHEvalLinearL0L1(half4(normal, 1.0));
#endif
ambient = max(half3(0, 0, 0), ambient + ambient_contrib); // include L2 contribution in vertex shader before clamp.
#ifdef UNITY_COLORSPACE_GAMMA
ambient = LinearToGammaSpace(ambient);
#endif
return ambient;
}
#endif