Shader "Unlit/VolumetricFog"
{
Properties
{
_Color("Color",Color)=(1,1,1,1)
_MaxDistance("Max distance",float) = 100
_StepSize("Step size",Range(0.1,20)) = 1
_DensityMultiplier("Density Multiplier", Range(0,10)) = 1
_NoiseOffset("noise offset",float) = 0
_FogNoise("Fog noise", 3D)="white"{}
_NoiseTiling("Noise tiling",float)=1
_DensityThreshold("Density threshold",Range(0,1))=0.1
[HDR] _LightContribution("Light contribution",Color)=(1,1,1,1)
_LightScattering("Light scattering",Range(0,1))=0.2
_fogOffset("fog Offset",float)=0
_fogFalloff("fog fallof",float)=1
_LightPower("added light Power",float)=100
_totalLights("script value Lights",int)=0
}
SubShader
{
Tags{"RenderType"="Transparent""RenderPipeline" ="UniversalPipeline" "UniversalMaterialType" = "Lit" "LightMode" = "UniversalForward"}
Pass{
HLSLPROGRAM
#pragma vertex Vert
#pragma fragment frag
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE _MAIN_LIGHT_SHADOWS_SCREEN
#pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
#include "Packages/com.unity.render-pipelines.core/RunTime/Utilities/Blit.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
float4 _Color;
float _MaxDistance;
float _DensityMultiplier;
float _StepSize;
float _NoiseOffset;
TEXTURE3D(_FogNoise);
float _DensityThreshold;
float _NoiseTiling;
float4 _LightContribution;
float _LightScattering;
float _fogOffset;
float _fogFalloff;
float _LightPower;
int _totalLights;
float henyey_greenstein(float angle,float scattering)
{
return (1.0-angle*angle)/(4.0*PI*pow(1.0+scattering*scattering-(2.0*scattering)*angle,1.5f));
}
float get_density(float3 worldPos )
{
float4 noise=_FogNoise.SampleLevel(sampler_TrilinearRepeat,worldPos*0.01*_NoiseTiling,0);
float density=dot(noise,noise);
density=saturate(density-_DensityThreshold)*_DensityMultiplier;
return density;
}
half4 frag(Varyings IN) :SV_Target
{
float4 col= SAMPLE_TEXTURE2D(_BlitTexture,sampler_LinearClamp,IN.texcoord);
float depth=SampleSceneDepth(IN.texcoord);
float3 worldPos= ComputeWorldSpacePosition(IN.texcoord,depth,UNITY_MATRIX_I_VP);
float3 entryPoint=_WorldSpaceCameraPos;
float3 viewDir = worldPos - _WorldSpaceCameraPos;
float viewLength = length(viewDir);
float3 rayDir = normalize(viewDir);
float2 pixelCoords = IN.texcoord* _BlitTexture_TexelSize.zw;
float distLimit = min(viewLength,_MaxDistance);
float distTravelled= InterleavedGradientNoise(pixelCoords, (int)(_Time.y/max(unity_DeltaTime.x,HALF_EPS)))*_NoiseOffset;
int totalLights=GetAdditionalLightsCount();
float transmittance=1;
float4 fogCol =_Color;
while(distTravelled<distLimit)
{
float3 rayPos=entryPoint + rayDir*distTravelled;
float density = get_density(rayPos);
float lightDensityReduction = 0; // Accumulate the total effect of all lights
for(int i=0; i<totalLights;++i)
{
Light addLight = GetAdditionalLight(i, rayPos);
lightDensityReduction += addLight.distanceAttenuation * _LightPower;
fogCol.rgb += addLight.color.rgb * addLight.distanceAttenuation * _LightPower * _LightContribution.rgb;
}
// Apply accumulated light reduction to the density
density = max(0, density - lightDensityReduction);
if(density>0)
{
Light mainLight = GetMainLight(TransformWorldToShadowCoord(rayPos));
fogCol.rgb +=mainLight.color.rgb*_LightContribution.rgb*henyey_greenstein(dot(rayDir,mainLight.direction),_LightScattering)*density*mainLight.shadowAttenuation *_StepSize;
density-= max(_fogOffset-distTravelled*_fogFalloff,0);
transmittance *=exp(-density*_StepSize);
}
distTravelled += _StepSize;
}
return lerp(col,fogCol,1.0-saturate(transmittance));
// return 1.0-SAMPLE_TEXTURE2D();
}
ENDHLSL
}
}
}
The code works great for creating a thick fog based on a 3dTexture and it reacts to mainlight direction and color but it only ever grabs one additional light (the light closest to the camera). It can access light data and use it correctly to cut throught the fog and add color but the getAdditionalLightsCount() allways returns 0 and if i force an increase to check for more lights it only calculates one light. All the sources I find get the desired result using additional lights pragma and a forward added render pass but no setting i change gives me the effect i want, an example:
the color should blend and the cutout area should be much larger