Files
3d-tower/Assets/Enviro 3 - Sky and Weather/Resources/Shader/Includes/VolumetricCloudsInclude.cginc
2026-05-09 09:10:52 +08:00

883 lines
27 KiB
HLSL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#ifndef PI
#define PI 3.14159265
#endif
#ifndef TWO_PI
#define TWO_PI 6.28318530
#endif
#ifndef INV_PI
#define INV_PI 0.31830989
#endif
uniform Texture3D _Noise;
SamplerState sampler_Noise;
uniform Texture3D _DetailNoise;
SamplerState sampler_DetailNoise;
uniform Texture2D _WeatherMap;
SamplerState sampler_WeatherMap;
uniform Texture2D _CurlNoise;
SamplerState sampler_CurlNoise;
uniform sampler2D _BottomsOffsetNoise;
uniform sampler2D _BlueNoise;
float4 _BlueNoise_TexelSize;
float3 _WorldOffset;
uniform float4x4 _InverseProjection;
uniform float4x4 _InverseRotation;
uniform float4x4 _InverseProjectionRight;
uniform float4x4 _InverseRotationRight;
float4x4 _LeftWorldFromView;
float4x4 _RightWorldFromView;
float4x4 _LeftViewFromScreen;
float4x4 _RightViewFromScreen;
uniform float4 _CloudsParameter;
uniform float4 _CloudsParameter2;
uniform float4 _Steps;
uniform float4 _CloudsLighting;
uniform float4 _CloudsLighting2;
uniform float4 _CloudsLightingExtended;
uniform float4 _CloudsLightingExtended2;
uniform float4 _CloudsMultiScattering;
uniform float4 _CloudsMultiScattering2;
uniform float4 _CloudsErosionIntensity; //x = Base, y = Detail
uniform float4 _CloudsNoiseSettings; //x = Base, y = Detail
uniform float4 _CloudsShape1;
uniform float4 _CloudsShape2;
uniform float4 _CloudDensityScale;
uniform float4 _CloudsCoverageSettings; //x = _GlobalCoverage, y = Bottom Coverage Mod, z = Top coverage mod, w = Clouds Up Morph Intensity
uniform float _GlobalCoverage;
uniform float4 _CloudsAnimation;
uniform float4 _CloudsWindDirection;
uniform float3 _LightDir;
uniform float _stepsInDepth;
uniform float _LODDistance;
uniform float3 _CameraPosition;
uniform float4 _Resolution;
uniform float4 _Randomness;
uniform float _EnviroDepthTest;
uniform float _SolarTime;
////
const float env_inf = 1e10;
struct RaymarchParameters
{
//Lighting
float scatteringCoef;
float silverLiningIntensity;
float silverLiningSpread;
float edgeHighlightStrength;
float directIndirectBalance;
float exposure;
float attenuation;
float lightStep;
float lightAbsorb;
float multiScatterStrength;
float multiScatterFalloff;
float ambientFloor;
//Height
float4 cloudsParameter;
//Density
float density;
float densitySmoothness;
//Erosion
float baseErosion;
float detailErosion;
int minSteps, maxSteps;
float baseNoiseUV;
float detailNoiseUV;
float baseErosionIntensity;
float detailErosionIntensity;
float baseNoiseMultiplier;
float detailNoiseMultiplier;
float bottomShape;
float midShape;
float topShape;
float topLayer;
float rampShape;
float cloudTypeShaping;
};
void InitRaymarchParameters(inout RaymarchParameters parameters)
{
parameters.scatteringCoef = _CloudsLighting.x;
parameters.silverLiningIntensity = _CloudsLighting.y;
parameters.silverLiningSpread = _CloudsLighting.w;
parameters.multiScatterStrength = _CloudsMultiScattering.x;
parameters.multiScatterFalloff = _CloudsMultiScattering.y;
parameters.ambientFloor = _CloudsMultiScattering.z;
parameters.exposure = _CloudsMultiScattering.w;
parameters.directIndirectBalance = _CloudsLightingExtended.x;
parameters.attenuation = _CloudsLightingExtended.y;
parameters.lightStep = _CloudsLightingExtended.z;
parameters.lightAbsorb = _CloudsLightingExtended.w;
parameters.edgeHighlightStrength = _CloudsLighting.z;
parameters.cloudsParameter = _CloudsParameter;
parameters.density = _CloudDensityScale.x;
parameters.densitySmoothness = _CloudDensityScale.z;
parameters.baseErosion = _CloudsErosionIntensity.x;
parameters.detailErosion = _CloudsErosionIntensity.y;
parameters.baseNoiseMultiplier = _CloudsNoiseSettings.z;
parameters.detailNoiseMultiplier = _CloudsNoiseSettings.w;
parameters.minSteps = _Steps.x;
parameters.maxSteps = _Steps.y;
parameters.baseNoiseUV = _CloudsNoiseSettings.x;
parameters.detailNoiseUV = _CloudsNoiseSettings.y;
parameters.baseErosionIntensity = _CloudsErosionIntensity.x;
parameters.detailErosionIntensity = _CloudsErosionIntensity.y;
parameters.bottomShape = _CloudsShape1.x;
parameters.midShape = _CloudsShape1.y;
parameters.topShape = _CloudsShape1.z;
parameters.topLayer = _CloudsShape1.w;
parameters.rampShape = _CloudsCoverageSettings.w;
parameters.cloudTypeShaping = _CloudsCoverageSettings.z;
}
float HenryGreensteinNorm(float cosTheta, float g)
{
float g2 = g * g;
return (1.0 - g2) / (4.0 * PI * pow(1.0 + g2 - 2.0 * g * cosTheta, 1.5));
}
float RemapEnviro(float org_val, float org_min, float org_max, float new_min, float new_max)
{
return new_min + saturate(((org_val - org_min) / (org_max - org_min))*(new_max - new_min));
}
float4 GetWeather(float3 pos)
{
float2 uv = pos.xz * 0.0000025;
return _WeatherMap.SampleLevel(sampler_WeatherMap,uv, 0);
}
float GetSamplingHeight(float3 pos, float3 center, float4 parameters)
{
return (length(pos - center) - (parameters.w + parameters.x)) * parameters.z;
}
float3 ScreenSpaceDither(float2 vScreenPos, float lum)
{
float d = dot(float2(131.0, 312.0), vScreenPos.xy); //+ _Time TODO
float3 vDither = float3(d, d, d);
vDither.rgb = frac(vDither.rgb / float3(103.0, 71.0, 97.0)) - float3(0.5, 0.5, 0.5);
return (vDither.rgb / 15.0) * 1.0 * lum;
}
float GetRaymarchEndFromSceneDepth(float sceneDepth, float maxRange)
{
float raymarchEnd = 0.0f;
#if ENVIRO_DEPTH_BLENDING
if (sceneDepth >= 0.99f)
{
raymarchEnd = maxRange;
}
else
{
raymarchEnd = sceneDepth * _ProjectionParams.z;
}
#else
if(_EnviroDepthTest > 0 )
{
if (sceneDepth >= 0.99f)
{
raymarchEnd = maxRange;
}
else
{
raymarchEnd = sceneDepth * _ProjectionParams.z;
}
}
else
{
raymarchEnd = maxRange;
}
#endif
return raymarchEnd;
}
float4 GetHeightGradient(float cloudType)
{
// x,y = bottom smoothstep, z,w = top smoothstep
const float4 CloudGradient1 = float4(0.0, 0.07, 0.08, 0.15); // Strato
const float4 CloudGradient2 = float4(0.0, 0.20, 0.42, 0.60); // Cumulus
const float4 CloudGradient3 = float4(0.0, 0.08, 0.75, 0.98); // Nimbus
float a = 1.0 - saturate(cloudType * 2.0); // 0→0.5 strato
float b = 1.0 - abs(cloudType - 0.5) * 2.0; // around 0.5 cumulus
float c = saturate(cloudType - 0.5) * 2.0; // 0.5→1 nimbus
return CloudGradient1 * a + CloudGradient2 * b + CloudGradient3 * c;
}
float GradientStep(float a, float4 g)
{
return smoothstep(g.x, g.y, a) - smoothstep(g.z, g.w, a);
}
// ---------- Final profile with varying bottom ----------
float CloudTypeShaping(float3 worldPos, float cloudType, RaymarchParameters p)
{
float _BottomVariation = 1000; // e.g. 500.0 m of random variation
float _NoiseScale = 0.000025; // e.g. 0.001 for slow world-scale noise
// noise-based base variation
float baseOffset = 0;
#if ENVIRO_VARIABLE_BOTTOM
baseOffset = tex2Dlod(_BottomsOffsetNoise, float4(worldPos.xz * _NoiseScale,0,0)).r * _BottomVariation;
#endif
float bottom = p.cloudsParameter.x + baseOffset;
float top = bottom + (p.cloudsParameter.y - p.cloudsParameter.x);
// normalized height
float h = saturate((worldPos.y - bottom) / (top - bottom));
// choose gradient band based on type
float4 gradient = GetHeightGradient(cloudType);
// final vertical profile
return GradientStep(h, gradient);
}
float CloudVerticalShaping(float heightNorm,
float bottomCtrl,
float midCtrl,
float topCtrl,
float ramp)
{
// --- Define segments ---
float2 bottomRange = float2(-0.1, 0.25);
float2 midRange = float2(0.20, 0.45);
float2 topRange = float2(0.40, 0.8); // top segment fades before 1.0
// --- Compute smooth ramps ---
float bottom = smoothstep(bottomRange.x, bottomRange.y, heightNorm) *
(1.0 - smoothstep(bottomRange.x + ramp, bottomRange.y + ramp, heightNorm));
float mid = smoothstep(midRange.x, midRange.y, heightNorm) *
(1.0 - smoothstep(midRange.x + ramp, midRange.y + ramp, heightNorm));
float top = smoothstep(topRange.x, topRange.y, heightNorm) *
(1.0 - smoothstep(topRange.x + ramp, topRange.y + ramp, heightNorm));
// --- Fade top influence out at absolute top ---
//top *= 1.0 - smoothstep(0.95, 1.0, heightNorm);
// --- Normalize weights so controls are balanced ---
float sum = bottom + mid + top + 1e-5;
bottom /= sum;
mid /= sum;
top /= sum;
// --- Apply coverage controls ---
float bias = bottomCtrl * bottom + midCtrl * mid + topCtrl * top;
// --- Map to envelope multiplier ---
// center at 1.0 = no change, limit to avoid full fill
float envelope = 1.0 + bias * 0.5; // adjust scale as needed
//envelope = envelope;
//Bottom Round
float edgeRound = 1.0 - exp(-heightNorm * 8.0);
envelope *= lerp(1.0, edgeRound, 0.9 * bottom);
// --- Subtle round-top modifier ---
float edgeRoundTop = 1.0 - exp(-(1.0 - heightNorm) * 8.0); // only affects highest ~0.81.0
envelope *= lerp(1.0, edgeRoundTop, 1.5 * top);
if(heightNorm > 0.90)
envelope = 0;
return envelope;
}
float CloudTopLayer(float heightNorm, float baseNoise, float topLayerAdd)
{
const float topMin = 0.90;
const float topMax = 0.94;
float verticalFalloff = smoothstep(topMin, topMax, heightNorm) - smoothstep(topMax, 1.0, heightNorm);
float coverage = baseNoise;
return verticalFalloff * coverage * topLayerAdd;
}
// Sample Cloud Density
float CalculateCloudDensity(float3 pos, float3 PlanetCenter, RaymarchParameters parameters, float4 weather, float mip, float lod, bool details)
{
const float baseFreq = 1e-5;
// Get Height fraction
float height = GetSamplingHeight(pos, PlanetCenter, parameters.cloudsParameter);
// wind settings
float cloud_top_offset = 2000.0;
float3 wind_direction = float3(_CloudsWindDirection.x, 0.0, _CloudsWindDirection.y);
// skew in wind direction
pos += height * wind_direction * cloud_top_offset;
float mip1 = mip + lod;
float4 coord = float4(pos * baseFreq * parameters.baseNoiseUV, mip1);
// Animate Wind
coord.xyz += float3(_CloudsWindDirection.z, 0.0f, _CloudsWindDirection.w) * 14;
float4 baseNoise = _Noise.SampleLevel(sampler_Noise, coord.xyz,coord.w) * parameters.baseNoiseMultiplier;
float low_freq_fBm = (baseNoise.g * 0.625) + (baseNoise.b * 0.25) + (baseNoise.a * 0.125);
float base_cloud = RemapEnviro(baseNoise.r, -(1.0 - low_freq_fBm) * (parameters.baseErosionIntensity), 1.0, 0.0, 1.0) ;
float targetShape = CloudVerticalShaping(height,parameters.bottomShape,parameters.midShape,parameters.topShape,parameters.rampShape);
float heightGradient = CloudTypeShaping(pos,saturate(weather.g + 0.1), parameters);
float shapedCloud = base_cloud * targetShape;
shapedCloud *= lerp(1.0, heightGradient, parameters.cloudTypeShaping);
shapedCloud += CloudTopLayer(height, base_cloud, parameters.topLayer);
float cloud_coverage = saturate(1-weather.r);
if(height > 0.90)
cloud_coverage = saturate(1-weather.b);
float cloudDensity = RemapEnviro(shapedCloud, cloud_coverage, 1.0, 0.0, 1.0);
//DETAIL
[branch]
if (details)
{
float mip2 = mip + lod;
coord = float4(pos * baseFreq * parameters.detailNoiseUV, mip2);
//Curl
float distToCam = distance(pos, _WorldSpaceCameraPos);
float curlFade = saturate(1.0 - distToCam / 20000.0f);
float2 curlA = _CurlNoise.SampleLevel(sampler_CurlNoise, coord.xz * 2, 0).rg * 2 - 1;
float2 curlB = _CurlNoise.SampleLevel(sampler_CurlNoise, coord.xy * 3, 0).rg * 2 - 1;
float2 curl = lerp(curlA, curlB, 0.5);
float curlAmp = 0.5 * parameters.attenuation * curlFade;
curl *= curlAmp * saturate(height * 2);
coord.xy += curl;
coord.xz += curl * 0.5;
coord.xyz += float3(_CloudsWindDirection.z * 14, _CloudsAnimation.z, _CloudsWindDirection.w * 14);
float3 detailNoise = _DetailNoise.SampleLevel(sampler_DetailNoise, coord.xyz, coord.w).rgb * parameters.detailNoiseMultiplier;
float high_freq_fBm = (detailNoise.r * 0.625) + (detailNoise.g * 0.25) + (detailNoise.b * 0.125);
float high_freq_noise_modifier = lerp(high_freq_fBm, 1.0f - high_freq_fBm, saturate(height * 8));
cloudDensity = RemapEnviro(cloudDensity, saturate(high_freq_noise_modifier * parameters.detailErosionIntensity), 1.0, 0.0, 1.0);
}
if(height > 0.9)
cloudDensity *= 0.2;
return cloudDensity;
}
static const float shadowSampleDistance[5] = {0.5, 2, 8, 12, 32};
static const float LightingInfluence[5] = {5, 4, 3, 2, 1};
float GetDensityAlongRay(float3 pos,float3 PlanetCenter,RaymarchParameters parameters,float3 LightDirection,float4 weather,float lod)
{
float mipBiasScale = 0.1;
float opticalDepth = 0.0;
float mipOffset = 0.0;
float distanceTraveled = 0.0;
[loop]
for (int i = 0; i < 5; i++)
{
// Base step size from shadowSampleDistance
float baseStep = shadowSampleDistance[i] * (512.0 * _CloudsLightingExtended.z);
distanceTraveled += baseStep;
// Sample cloud density
float3 samplePos = pos + LightDirection * distanceTraveled;
float density = 0;
if(i < 4)
density = CalculateCloudDensity(samplePos, PlanetCenter, parameters, weather, mipOffset, lod, true) * 0.75;
else
density = CalculateCloudDensity(samplePos, PlanetCenter, parameters, weather, mipOffset, lod, false) * 0.75;
opticalDepth += LightingInfluence[i] * density * baseStep;
// Update mip offset proportionally
mipOffset += saturate(baseStep * mipBiasScale);
}
return opticalDepth;
}
float3 _LightningCenter;
float _LightningRadius;
float _LightningStart;
float _LightningDuration;
float _GlobalTime;
float LightningIntensity(float t)
{
if (t < 0 || t > _LightningDuration) return 0;
// ---- Parameters ----
float flickerStrength = 0.25; // 0..1 amplitude of flicker
float flickerCycles = 3; // number of flickers across duration
float endBoost = 2; // 1 = none, 2 = double brightness at end
// ---- Duration-based scaling ----
float riseRate = 1.0 / max(0.15 * _LightningDuration, 0.001);
float decayRate = 1.0 / max(_LightningDuration, 0.001);
float rise = saturate(t * riseRate);
float decay = exp(-t * decayRate * _LightningDuration);
float envelope = rise * decay;
// ---- Flicker ----
float flickerFreq = flickerCycles / max(_LightningDuration, 0.001);
float flicker = 1.0 + flickerStrength * sin(t * flickerFreq * 6.2831853);
// ---- Late-time boost ----
// Progress through flash (0 → 1)
float progress = saturate(t / _LightningDuration);
// Stronger near the end (ease-in curve)
float lateBoost = 1.0 + (endBoost - 1.0) * pow(progress, 3.0);
return envelope * flicker * lateBoost;
}
float SampleEnergy(
float3 pos, float cosTheta, float3 center,
RaymarchParameters p, float3 LightDirection,
float height, float ds_lod, float step_size,
float4 weather, float lod, float gradApprox)
{
//--------------------------------
// 1. Optical depth along light
//--------------------------------
float tau = GetDensityAlongRay(pos, center, p, LightDirection, weather, lod);
float sigma_t = max(p.lightAbsorb, 0.0005);
float opticalD = sigma_t * tau;
//--------------------------------
// 2. Direct scattering (HG + edge highlight coupled)
//--------------------------------
float T = exp(-opticalD);
float g = 0.85 - p.silverLiningSpread;
float hgForward = HenryGreensteinNorm(cosTheta, g);
float hgIso = 0.25 * INV_PI * p.edgeHighlightStrength;
float phase = hgIso + hgForward;
float direct = T * phase * p.scatteringCoef * 20.0 * max(_SolarTime,0.25) * p.silverLiningIntensity;
//--------------------------------
// 3. Multi-scattering (indirect)
//--------------------------------
float msEnergy = p.multiScatterStrength * (1.0 - T) * exp(-opticalD * p.multiScatterFalloff);
float phaseMS = 0.25 * INV_PI;
float indirect = msEnergy * phaseMS * p.scatteringCoef * 20.0;
//--------------------------------
// 3a Distance Clouds Tweaks
//--------------------------------
float distToCam = length(pos - _WorldSpaceCameraPos);
float distFactor = saturate(distToCam / 7000);
// Push balance toward indirect at distance
float indirectBoost = lerp(1.0, 1.5, distFactor); // 1.0 near, 1.5 far
float directFade = lerp(1.0, 0.7, distFactor); // keep direct a bit weaker far
direct *= directFade;
indirect *= indirectBoost;
//--------------------------------
// 4. Ambient floor
//--------------------------------
float ambientFloor = p.ambientFloor * (1.0 - exp(-opticalD * 0.1));
//--------------------------------
// 5. Lightning
//--------------------------------
float lightning = 0.0;
#if ENVIRO_LIGHTNING
float dist = length(pos - _LightningCenter);
float softness = 0.5;
float falloff = exp(-pow(dist / _LightningRadius, 2.0) * softness);
float flash = LightningIntensity(_Time.y - _LightningStart);
float densityAtten = exp(-tau * 0.004);
lightning = flash * falloff * densityAtten * 100.0 * (10 * saturate(1 - _SolarTime));
#endif
//--------------------------------
// 6. Combine total energy
//--------------------------------
float energy = direct + indirect + ambientFloor + lightning;
return max(energy * p.exposure, 0.0);
}
float2 squareUV(float2 uv)
{
float width = _Resolution.x;
float height = _Resolution.y;
float scale = 400;
float x = uv.x * width;
float y = uv.y * height;
return float2 (x/scale, y/scale);
}
bool ray_trace_sphere(float3 center, float3 rd, float3 offset, float radius, out float t1, out float t2) {
float3 p = center - offset;
float b = dot(p, rd);
float c = dot(p, p) - (radius * radius);
float f = b * b - c;
if (f >= 0.0) {
float dem = sqrt(f);
t1 = -b - dem;
t2 = -b + dem;
return true;
}
return false;
}
bool resolve_ray_start_end(float3 ws_origin, float3 ws_ray, float3 center, RaymarchParameters parameter, out float start, out float end)
{
start = 0;
end = 0;
//case includes on ground, inside atm, above atm.
float ot1, ot2, it1, it2;
bool outIntersected = ray_trace_sphere(ws_origin, ws_ray, center, parameter.cloudsParameter.w + parameter.cloudsParameter.y, ot1, ot2);
if (!outIntersected || ot2 < 0.0f)
return false; //you see nothing.
bool inIntersected = ray_trace_sphere(ws_origin, ws_ray, center, parameter.cloudsParameter.w + parameter.cloudsParameter.x, it1, it2);
if (inIntersected)
{
if (it1 * it2 < 0)
{
//we're on ground.
start = max(it2, 0);
end = ot2;
}
else
{
start = 0.0f;
//we're inside atm, or above atm.
if (ot1 * ot2 < 0.0)
{
//Inside atm.
if (it2 > 0.0)
{
//Look down.
end = it1;
}
else
{
//Look up.
end = ot2;
}
start = 0.0f;
}
else
{ //Outside atm
if (ot1 < 0.0)
{
return false;
}
else
{
start = ot1;
end = it1;
}
}
}
}
else
{
end = ot2;
start = max(ot1, 0);
}
return true;
}
int inside = 0;
float2 ResolveRay(float3 pos, float3 ray, float3 center, float raymarchEnd, RaymarchParameters parameter)
{
float sampleStart = 0;
float sampleEnd = 0;
if (!resolve_ray_start_end(pos, ray,center, parameter, sampleStart, sampleEnd))
{
return float2(0,0);
}
float3 sampleStartPos = pos + (ray * sampleStart);
if (sampleEnd <= sampleStart)
{
return float2(0,0);
}
float ch = length(pos - center) - parameter.cloudsParameter.w;
//float height = RemapEnviro(pos.y, parameter.cloudsParameter.x, parameter.cloudsParameter.y * 0.75, 0, 1);
//float end = lerp(_CloudsCoverageSettings.y * 0.85,_CloudsCoverageSettings.y * 1.25,height);
raymarchEnd = min(raymarchEnd, _CloudsCoverageSettings.y);
if (ch < parameter.cloudsParameter.x)
{
sampleEnd = min(raymarchEnd, sampleEnd);
inside = 0;
if(ray.y < 0)
return float2(0,0);
}
else if (ch > parameter.cloudsParameter.y)
{
sampleEnd = min(raymarchEnd, sampleEnd);
inside = 0;
}
else
{
sampleEnd = min(raymarchEnd, sampleEnd);
inside = 0;
}
return float2(max(0.0f,sampleStart), min(raymarchEnd, sampleEnd));
}
float CalculateLodMips(float distanceToCamera)
{
return lerp(0.0, lerp(5.0,0.0,_LODDistance), saturate((distanceToCamera - 3000.0) / (100000.0 - 3000.0)));
}
float3 Raymarch (float3 cameraPos, float3 ray, float2 hitDistance, float3 center, RaymarchParameters parameters, float offset)
{
float cloud_test = 0.0;
int zero_density_sample_count = 0;
float sampled_density_previous = -1.0;
float alpha = 1.0;
float intensity = 0.0;
float depth = 0.0;
float depthWeightSum = 0.000001;
float trans = 1.0f;
int steps = (int)lerp(parameters.minSteps, parameters.maxSteps, ray.y);
//int steps = parameters.maxSteps;
float rayStepLength = (hitDistance.y - hitDistance.x) / steps;
float3 rayStep = ray * rayStepLength;
float3 pos = (cameraPos + (hitDistance.x) * ray);
pos += (offset * rayStepLength) * ray;
//pos += rayStep;
pos += rayStep;
float3 sampleEndPos = cameraPos + ray * hitDistance.y;
float eyeToEnd = distance(cameraPos, sampleEndPos);
float cosTheta = dot(ray, normalize(_LightDir));
[loop]
for (int i = 0; i < steps; i++)
{
//Calculate projection height
float height = GetSamplingHeight(pos, center, parameters.cloudsParameter);
//Get out of expensive raymarching
if (alpha <= 0.01 || height > 1.0 || height < 0.0 || _CloudsCoverageSettings.x <= -0.9)
break;
// Get Weather Data
float4 weather = GetWeather(pos);
float distanceToCamera = length(pos - cameraPos);
float lod = CalculateLodMips(distanceToCamera);
if (cloud_test > 0.0)
{
float sampled_density = CalculateCloudDensity(pos, center, parameters, weather, 0, lod, true);
if (sampled_density == 0.0 && sampled_density_previous == 0.0)
{
zero_density_sample_count++;
}
if (zero_density_sample_count < 8 && sampled_density != 0.0)
{
float extinction = pow(max(parameters.density * sampled_density,0.001),parameters.densitySmoothness);
float clampedExtinction = max(extinction, 1e-7);
float transmittance = exp(-extinction * rayStepLength);
float gradApprox = abs(sampled_density - sampled_density_previous);
// edge-sensitive ds_lod
float ds_lod_local = sampled_density * (1.0 + lod * 0.8);
float luminance = SampleEnergy(pos, cosTheta, center, parameters, _LightDir, height, sampled_density, rayStepLength,weather,lod,gradApprox);
float integScatt = (luminance - luminance * transmittance);
float depthWeight = trans;
depth += depthWeight * distanceToCamera;
depthWeightSum += depthWeight;
intensity += trans * integScatt;
trans *= transmittance;
alpha *= max(transmittance, 0.0);
if (alpha <= 0.01)
alpha = 0.0;
}
// if not, then set cloud_test to zero so that we go back to the cheap sample case
else if(zero_density_sample_count >= 8)
{
cloud_test = 0.0;
zero_density_sample_count = 0;
}
sampled_density_previous = sampled_density;
pos += rayStep;
}
else
{
// sample density the cheap way, only using the low frequency noise
cloud_test = CalculateCloudDensity(pos, center, parameters, weather, 0, lod, (bool)inside);
if (cloud_test == 0.0)
{
pos += rayStep * 2;
}
else //take a step back and capture area we skipped.
{
pos -= rayStep;
}
}
}
float distance = depth / depthWeightSum;
if (distance <= 0.0)
{
distance = length(sampleEndPos - cameraPos);
}
alpha = saturate(1.0f - alpha);
return float3(intensity,distance,alpha);
}
float3 CalculateWorldPosition (float2 uv, float depth)
{
float4x4 proj, eyeToWorld;
if (unity_StereoEyeIndex == 0)
{
proj = _LeftViewFromScreen;
eyeToWorld = _LeftWorldFromView;
}
else
{
proj = _RightViewFromScreen;
eyeToWorld = _RightWorldFromView;
}
//bit of matrix math to take the screen space coord (u,v,depth) and transform to world space
float2 uvClip = uv * 2.0 - 1.0;
float clipDepth = depth; // Fix for OpenGl Core thanks to Lars Bertram
clipDepth = (UNITY_NEAR_CLIP_VALUE < 0) ? clipDepth * 2 - 1 : clipDepth;
float4 clipPos = float4(uvClip, clipDepth, 1.0);
float4 viewPos = mul(proj, clipPos); // inverse projection by clip position
viewPos /= viewPos.w; // perspective division
return float3(mul(eyeToWorld, viewPos).xyz);
}
float RaymarchShadows (float3 cameraPos, float3 worldPos,float3 ray,float3 center, RaymarchParameters parameters, float offset,float depth)
{
if(depth == 0.0f)
return 0.0;
int steps = 16;
float worldDotLight = saturate(dot(float3(0, 1, 0), _LightDir));
float bottomDist = max(0, parameters.cloudsParameter.x ) / worldDotLight;
float topDist = max(0, parameters.cloudsParameter.y ) / worldDotLight;
float rayStepLength = (topDist - bottomDist) / steps;
float3 rayStep = _LightDir * rayStepLength;
float3 pos = worldPos + bottomDist * _LightDir;
float4 weather = GetWeather(pos);
float intensity = 0.05;
float shadowIntensity = 0.0;
float _Softness = 2.0f;
[unroll]
for (int i = 0; i < steps; i++)
{
float3 samplePos = rayStepLength * i * _LightDir + pos;
float sampleResult = CalculateCloudDensity(samplePos, center, parameters, weather, 0, 0, true) * intensity;
float result = sampleResult * (rayStepLength / (i + 1));
shadowIntensity += result;
// if (shadowIntensity > 0.99)
// break;
}
return (shadowIntensity);
}