#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch // Shadows #pragma kernel TraceVolumetricCloudsShadows #pragma multi_compile _ CLOUDS_SIMPLE_PRESET // #pragma enable_d3d11_debug_symbols #define TRACE_CLOUDS_SHADOWS 1 #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/VolumetricClouds/VolumetricCloudsUtilities.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/GeometricTools.hlsl" RW_TEXTURE2D(float4, _VolumetricCloudsShadowRW); [numthreads(8, 8, 1)] void TraceVolumetricCloudsShadows(uint3 currentCoords : SV_DispatchThreadID, int groupIndex : SV_GroupIndex) { // If we can, load the cloud lut into the LDS #if defined(CLOUDS_SIMPLE_PRESET) LoadCloudLutToLDS(groupIndex); #endif // Compute the normalized coordinate on the shadow plane float2 normalizedCoord = currentCoords.xy / (float)(_ShadowCookieResolution - 1); // Compute the origin of the ray properties in the planet space float3 rayOriginPS = _CloudShadowSunOrigin.xyz + (normalizedCoord.x * _CloudShadowSunRight.xyz + normalizedCoord.y * _CloudShadowSunUp.xyz); float3 rayDirection = -_CloudShadowSunForward.xyz; // Compute the attenuation float transmittance = 1.0f; float closestDistance = FLT_MAX; float farthestDistance = FLT_MIN; bool validShadow = false; // Intersect the outer sphere float2 lowestAltitudeIntersections, highestAltitudeIntersections; bool lowBoundOk = IntersectRaySphere(rayOriginPS, rayDirection, _LowestCloudAltitude, lowestAltitudeIntersections); bool highBoundOk = IntersectRaySphere(rayOriginPS, rayDirection, _HighestCloudAltitude, highestAltitudeIntersections); if (lowBoundOk && highBoundOk) { // Compute the integration range float startDistance = highestAltitudeIntersections.x; float totalDistance = max(lowestAltitudeIntersections.x - highestAltitudeIntersections.x, highestAltitudeIntersections.x - lowestAltitudeIntersections.x); rayOriginPS += startDistance * rayDirection; float stepSize = totalDistance / 16; for (int i = 1; i < 16; ++i) { // Compute the sphere intersection position float dist = (stepSize * i); float3 positionPS = rayOriginPS + rayDirection * dist; // Get the coverage at intersection point CloudCoverageData cloudCoverageData; GetCloudCoverageData(positionPS, cloudCoverageData); // Compute the cloud density CloudProperties cloudProperties; EvaluateCloudProperties(positionPS, 0.0, 0.0, true, true, cloudProperties); // Apply the camera fade it to match the clouds perceived by the camera cloudProperties.density *= DensityFadeValue(length(positionPS - _CameraPositionPS.xyz)); if (cloudProperties.density > CLOUD_DENSITY_TRESHOLD) { // Apply the extinction closestDistance = min(closestDistance, totalDistance - stepSize * (i + 1)); farthestDistance = max(farthestDistance, totalDistance - stepSize * i); const float3 currentStepExtinction = exp(-_ScatteringTint.xyz * cloudProperties.density * cloudProperties.sigmaT * stepSize); transmittance *= Luminance(currentStepExtinction); validShadow = true; } } } // If we didn't manage to hit a non null density, we need to fix the distances float4 result = validShadow ? float4(closestDistance, lerp(1.0 - _ShadowIntensity, 1.0, transmittance), farthestDistance, 1.0) : float4(0.0, 1.0, 0.0, 0.0); _VolumetricCloudsShadowRW[currentCoords.xy] = result; }