// The following comment prevents Unity from auto upgrading the shader. Please keep it to keep backward compatibility. // UNITY_SHADER_NO_UPGRADE #ifndef _VLB_SHADER_UTILS_INCLUDED_ #define _VLB_SHADER_UTILS_INCLUDED_ #include "ShaderMaths.cginc" // https://docs.unity3d.com/Manual/SL-UnityShaderVariables.html #define VLB_CAMERA_NEAR_PLANE _ProjectionParams.y #define VLB_CAMERA_FAR_PLANE _ProjectionParams.z #define VLB_CAMERA_ORTHO unity_OrthoParams.w // w is 1.0 when camera is orthographic, 0.0 when perspective // Z buffer to 0..1 depth (0 at eye, 1 at far plane) float VLB_ZBufferTo01(float depth, float near, float far) { float x = 1 - far / near; float y = far / near; return 1.0 / (x * depth + y); } // Z buffer to linear depth float VLB_ZBufferToLinear(float depth, float near, float far) { float x = 1 - far / near; float y = far / near; float z = x / far; float w = y / far; return 1.0 / (z * depth + w); } inline float4 Depth_VS_ComputeProjPos(float3 vertexViewSpace, float4 vertexClipSpace) { float4 projPos = ComputeScreenPos(vertexClipSpace); projPos.z = -vertexViewSpace.z; // = COMPUTE_EYEDEPTH return projPos; } inline float Depth_PS_GetLinearDepthOrtho(float rawDepth) { rawDepth = lerp(rawDepth, 1.0f - rawDepth, _VLB_UsesReversedZBuffer); return (VLB_CAMERA_FAR_PLANE - VLB_CAMERA_NEAR_PLANE) * rawDepth + VLB_CAMERA_NEAR_PLANE; } inline float Depth_PS_GetSceneDepthFromNearPlane(float4 uv) { float rawDepth = VLBSampleDepthTexture(uv); float linearDepthPersp = VLBLinearEyeDepth(rawDepth); float linearDepthOrtho = Depth_PS_GetLinearDepthOrtho(rawDepth); return lerp(linearDepthPersp, linearDepthOrtho, VLB_CAMERA_ORTHO); } inline float Depth_PS_GetSceneDepthFromEye(float4 uv, float3 posViewSpace) { float rawDepth = VLBSampleDepthTexture(uv); float linearDepthPersp = VLBLinearEyeDepth(rawDepth); // transform perspective depth from near plane to distance based on the eye float acosViewDirZ = abs(normalize(posViewSpace.xyz).z); // TODO precompute that in VS? linearDepthPersp /= acosViewDirZ; float linearDepthOrtho = Depth_PS_GetLinearDepthOrtho(rawDepth); return lerp(linearDepthPersp, linearDepthOrtho, VLB_CAMERA_ORTHO); } #if VLB_DEPTH_BLEND || VLB_DITHERING inline float DepthFade_PS_BlendDistance(float4 projPos, float3 posViewSpace, float distance) { // Use FromNearPlane instead of FromEye for SD beams, it looks better specially in QA tests 'BlendWithGeom' and 'BlendWithGeomDisableAtSrc' float sceneDepth = Depth_PS_GetSceneDepthFromNearPlane(projPos); float sceneZ = max(0, sceneDepth - VLB_CAMERA_NEAR_PLANE); float partZ = max(0, projPos.z - VLB_CAMERA_NEAR_PLANE); return saturate((sceneZ - partZ) / distance); } #endif // VLB_DEPTH_BLEND || VLB_DITHERING #if VLB_NOISE_3D uniform sampler3D _VLB_NoiseTex3D; uniform float _VLB_NoiseCustomTime; float3 Noise3D_GetUVW(float3 posWorldSpace, float3 posLocalSpace) { float4 noiseVelocityAndScale = VLB_GET_PROP(_NoiseVelocityAndScale); float2 noiseParam = VLB_GET_PROP(_NoiseParam); float3 velocity = noiseVelocityAndScale.xyz; float scale = noiseVelocityAndScale.w; float3 posRef = lerp(posWorldSpace, posLocalSpace, noiseParam.y); // 0 -> World Space ; 1 -> Local Space // use _VLB_NoiseCustomTime if it's equal or higher than 0.0 float currentTime = lerp(_Time.y, _VLB_NoiseCustomTime, isEqualOrGreater(_VLB_NoiseCustomTime, 0.0f)); //return frac(posRef.xyz * scale + (currentTime * velocity)); // frac doesn't give good results on VS return (posRef.xyz * scale + (currentTime * velocity)); } float Noise3D_GetFactorFromUVW(float3 uvw) { float2 noiseParam = VLB_GET_PROP(_NoiseParam); float intensity = noiseParam.x; float noise = tex3D(_VLB_NoiseTex3D, uvw).a; return lerp(1, noise, intensity); } #endif // VLB_NOISE_3D inline float ComputeAttenuationSD(float pixDistZ, float fallOffStart, float fallOffEnd, float lerpLinearQuad) { float distFromSourceNormalized = invLerpClamped(fallOffStart, fallOffEnd, pixDistZ); // Almost simple linear attenuation between Fade Start and Fade End: Use smoothstep for a better fall to zero rendering float attLinear = smoothstep(0, 1, 1 - distFromSourceNormalized); // Unity's custom quadratic attenuation https://forum.unity.com/threads/light-attentuation-equation.16006/ float attQuad = 1.0 / (1.0 + 25.0 * distFromSourceNormalized * distFromSourceNormalized); const float kAttQuadStartToFallToZero = 0.8; attQuad *= saturate(smoothstep(1.0, kAttQuadStartToFallToZero, distFromSourceNormalized)); // Near the light's range (fade end) we fade to 0 (because quadratic formula never falls to 0) return lerp(attLinear, attQuad, lerpLinearQuad); } inline float ComputeAttenuationHD(float pixDistZ, float fallOffStart, float fallOffEnd) { float distFromSourceNormalized = invLerpClamped(fallOffStart, fallOffEnd, pixDistZ); float att = -1.0f; #if VLB_ATTENUATION_LINEAR // Simple linear attenuation att = (1 - distFromSourceNormalized); #elif VLB_ATTENUATION_QUAD // Unity's custom quadratic attenuation // https://forum.unity.com/threads/light-attentuation-equation.16006/ // https://forum.unity.com/threads/light-distance-in-shader.509306/#post-3326818 att = saturate(1.0 / (1.0 + 25.0 * distFromSourceNormalized * distFromSourceNormalized) * saturate((1 - distFromSourceNormalized) * 5.0)); #endif return att; } #if VLB_COLOR_GRADIENT #if VLB_COLOR_GRADIENT_MATRIX_HIGH || VLB_COLOR_GRADIENT_MATRIX_LOW #if VLB_COLOR_GRADIENT_MATRIX_HIGH #define FLOAT_PACKING_PRECISION 64 #else #define FLOAT_PACKING_PRECISION 8 #endif inline float4 UnpackToColor(float packedFloat) { float4 color; color.a = packedFloat % FLOAT_PACKING_PRECISION; packedFloat = floor(packedFloat / FLOAT_PACKING_PRECISION); color.b = packedFloat % FLOAT_PACKING_PRECISION; packedFloat = floor(packedFloat / FLOAT_PACKING_PRECISION); color.g = packedFloat % FLOAT_PACKING_PRECISION; packedFloat = floor(packedFloat / FLOAT_PACKING_PRECISION); color.r = packedFloat; return color / (FLOAT_PACKING_PRECISION - 1); } inline float GetAtMatrixIndex(float4x4 mat, uint idx) { return mat[idx % 4][floor(idx / 4)]; } inline float4 DecodeGradient(float t, float4x4 colorMatrix) { #define kColorGradientMatrixSize 16 float sampleIndexFloat = t * (kColorGradientMatrixSize - 1); float ratioPerSample = sampleIndexFloat - (int)sampleIndexFloat; uint sampleIndexInt = min((uint)sampleIndexFloat, kColorGradientMatrixSize - 2); float4 colorA = UnpackToColor(GetAtMatrixIndex(colorMatrix, sampleIndexInt + 0)); float4 colorB = UnpackToColor(GetAtMatrixIndex(colorMatrix, sampleIndexInt + 1)); return lerp(colorA, colorB, ratioPerSample); } #elif VLB_COLOR_GRADIENT_ARRAY inline half4 DecodeGradient(float t, float4 colorArray[kColorGradientArraySize]) { uint arraySize = kColorGradientArraySize; float sampleIndexFloat = t * (arraySize - 1); float ratioPerSample = sampleIndexFloat - (int)sampleIndexFloat; uint sampleIndexInt = min((uint)sampleIndexFloat, arraySize - 2); float4 colorA = colorArray[sampleIndexInt + 0]; float4 colorB = colorArray[sampleIndexInt + 1]; return lerp(colorA, colorB, ratioPerSample); } #endif // VLB_COLOR_GRADIENT_* inline float4 ComputeColorGradient(float pixDistFromSource) { float distanceFadeEnd = VLB_GET_PROP(_DistanceFallOff).y; float4x4 colorGradientMatrix = VLB_GET_PROP(_ColorGradientMatrix); float distFromSourceNormalized = invLerpClamped(0, distanceFadeEnd, pixDistFromSource); return DecodeGradient(distFromSourceNormalized, colorGradientMatrix); } #elif VLB_COLOR_FLAT inline float4 ComputeColorFlat() { return VLB_GET_PROP(_ColorFlat); } #endif // VLB_COLOR_GRADIENT / VLB_COLOR_FLAT inline float4 ApplyAlphaToColor(float4 color) { #if VLB_ALPHA_AS_BLACK color.rgb *= color.a; #endif return color; } inline float4 ApplyAlphaToColor(float4 color, float additionalAlpha) { #if VLB_ALPHA_AS_BLACK color.rgb *= color.a; color.rgb *= additionalAlpha; #else color.a *= additionalAlpha; #endif return color; } #endif // _VLB_SHADER_UTILS_INCLUDED_