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.
312 lines
13 KiB
312 lines
13 KiB
#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch
|
|
//#pragma enable_d3d11_debug_symbols
|
|
|
|
#pragma kernel WaterClearIndirect
|
|
#pragma kernel WaterClassifyTiles USE_INDIRECT VARIANT=NUM_WATER_VARIANTS
|
|
#pragma kernel PrepareSSRIndirect USE_INDIRECT VARIANT=NUM_WATER_VARIANTS
|
|
|
|
// Indirect water deferred lighting variants
|
|
#pragma kernel WaterDeferredLighting_Variant0 WATER_DEFERRED_LIGHTING=WaterDeferredLighting_Variant0 VARIANT=0 USE_INDIRECT
|
|
#pragma kernel WaterDeferredLighting_Variant1 WATER_DEFERRED_LIGHTING=WaterDeferredLighting_Variant1 VARIANT=1 USE_INDIRECT
|
|
#pragma kernel WaterDeferredLighting_Variant2 WATER_DEFERRED_LIGHTING=WaterDeferredLighting_Variant2 VARIANT=2 USE_INDIRECT
|
|
#pragma kernel WaterDeferredLighting_Variant3 WATER_DEFERRED_LIGHTING=WaterDeferredLighting_Variant3 VARIANT=3 USE_INDIRECT
|
|
#pragma kernel WaterDeferredLighting_Variant4 WATER_DEFERRED_LIGHTING=WaterDeferredLighting_Variant4 VARIANT=4 USE_INDIRECT
|
|
|
|
#pragma kernel WaterFogIndirect USE_INDIRECT VARIANT=NUM_WATER_VARIANTS WATER_FOG_INDIRECT=WaterFogIndirect
|
|
#pragma kernel WaterFogTransmittanceIndirect USE_INDIRECT VARIANT=NUM_WATER_VARIANTS WATER_FOG_INDIRECT=WaterFogTransmittanceIndirect OUTPUT_TRANSMITTANCE_BUFFER
|
|
|
|
// Given that the algorithm requires BSDF evaluation, we need to define this macro
|
|
#define HAS_LIGHTLOOP
|
|
#define SCREEN_SPACE_INDIRECT_DIFFUSE_DISABLED
|
|
#define USE_CLUSTERED_LIGHTLIST
|
|
#define HAS_REFRACTION 1
|
|
#define SUPPORT_WATER_ABSORPTION
|
|
#define WATER_FOG_PASS
|
|
|
|
#ifdef PLATFORM_LANE_COUNT
|
|
#define NR_THREADS PLATFORM_LANE_COUNT
|
|
#else
|
|
#define NR_THREADS 64 // default to 64 threads per group on other platforms..
|
|
#endif
|
|
|
|
// Shadow qualities are supported
|
|
#pragma multi_compile PUNCTUAL_SHADOW_LOW PUNCTUAL_SHADOW_MEDIUM PUNCTUAL_SHADOW_HIGH
|
|
#pragma multi_compile DIRECTIONAL_SHADOW_LOW DIRECTIONAL_SHADOW_MEDIUM DIRECTIONAL_SHADOW_HIGH
|
|
#pragma multi_compile AREA_SHADOW_MEDIUM AREA_SHADOW_HIGH
|
|
#pragma multi_compile _ RENDERING_LAYERS
|
|
|
|
// Include and define the shader pass
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPass.cs.hlsl"
|
|
#define SHADERPASS SHADERPASS_DEFERRED_LIGHTING
|
|
#define LIGHT_EVALUATION_NO_CONTACT_SHADOWS
|
|
|
|
// HDRP generic includes
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/Lighting.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Material.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoopDef.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/NormalSurfaceGradient.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Water/Water.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.hlsl"
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Water/Shaders/UnderWaterUtilities.hlsl"
|
|
|
|
// Input textures of the kernels
|
|
TEXTURE2D_X(_DepthTexture);
|
|
TEXTURE2D_X(_CameraColorTexture);
|
|
|
|
// Output textures of the kernels
|
|
RW_TEXTURE2D_X(float4, _CameraColorTextureRW);
|
|
RW_TEXTURE2D_X(float4, _NormalBufferRW);
|
|
|
|
#if defined(OUTPUT_TRANSMITTANCE_BUFFER)
|
|
RW_TEXTURE2D_X(float2, _TransmittanceBufferRW);
|
|
#endif
|
|
|
|
#if defined (USE_INDIRECT)
|
|
StructuredBuffer<uint> _WaterTileBuffer;
|
|
RWStructuredBuffer<uint> _WaterTileBufferRW;
|
|
int _WaterNumTiles;
|
|
|
|
uint3 GetActualDispatchThread(uint2 groupThreadId, uint groupId)
|
|
{
|
|
uint tileIndex = _WaterTileBuffer[VARIANT * _WaterNumTiles * _XRViewCount + groupId];
|
|
uint2 tileCoord = uint2((tileIndex >> TILE_INDEX_SHIFT_X) & TILE_INDEX_MASK, (tileIndex >> TILE_INDEX_SHIFT_Y) & TILE_INDEX_MASK);
|
|
return uint3(tileCoord * 8 + groupThreadId, tileIndex >> TILE_INDEX_SHIFT_EYE);
|
|
}
|
|
#endif
|
|
|
|
RWBuffer<uint> _WaterDispatchIndirectBuffer;
|
|
[numthreads(NR_THREADS, 1, 1)]
|
|
void WaterClearIndirect(uint dispatchThreadId : SV_DispatchThreadID)
|
|
{
|
|
// We need NUM_WATER_VARIANTS + 1 Dispatch parameters, the last one being all the water tiles)
|
|
if (dispatchThreadId > NUM_WATER_VARIANTS)
|
|
return;
|
|
|
|
_WaterDispatchIndirectBuffer[dispatchThreadId * 3 + 0] = 0; // ThreadGroupCountX
|
|
_WaterDispatchIndirectBuffer[dispatchThreadId * 3 + 1] = 1; // ThreadGroupCountY
|
|
_WaterDispatchIndirectBuffer[dispatchThreadId * 3 + 2] = 1; // ThreadGroupCountZ
|
|
}
|
|
|
|
#if defined (USE_INDIRECT)
|
|
// Holds the per-tile light features
|
|
groupshared uint gs_tileFeatureFlags;
|
|
|
|
[numthreads(8, 8, 1)]
|
|
void WaterClassifyTiles(uint3 currentCoord : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex, uint2 groupId : SV_GroupID)
|
|
{
|
|
UNITY_XR_ASSIGN_VIEW_INDEX(currentCoord.z);
|
|
|
|
// Is this a water pixel?
|
|
uint stencilValue = GetStencilValue(LOAD_TEXTURE2D_X(_StencilTexture, currentCoord.xy));
|
|
|
|
// Read the depth value
|
|
float depthValue = LOAD_TEXTURE2D_X(_DepthTexture, currentCoord.xy).x;
|
|
|
|
// Compute the posInput
|
|
uint2 tileCoord = currentCoord.xy / GetTileSize();
|
|
PositionInputs posInput = GetPositionInput(currentCoord.xy, _ScreenSize.zw, depthValue, UNITY_MATRIX_I_VP, GetWorldToViewMatrix(), tileCoord);
|
|
|
|
// This is the minimal set of features we allow
|
|
uint featureFlags = LIGHTFEATUREFLAGS_SKY | LIGHTFEATUREFLAGS_DIRECTIONAL | LIGHTFEATUREFLAGS_SSREFLECTION | LIGHTFEATUREFLAGS_SSREFRACTION;
|
|
|
|
// For this pixel, get the number of lights (for each type)
|
|
uint lightCount, tmp;
|
|
GetCountAndStart(posInput, LIGHTCATEGORY_PUNCTUAL, tmp, lightCount);
|
|
featureFlags |= (lightCount != 0 ? LIGHTFEATUREFLAGS_PUNCTUAL : 0);
|
|
GetCountAndStart(posInput, LIGHTCATEGORY_AREA, tmp, lightCount);
|
|
featureFlags |= (lightCount != 0 ? LIGHTFEATUREFLAGS_AREA : 0);
|
|
GetCountAndStart(posInput, LIGHTCATEGORY_ENV, tmp, lightCount);
|
|
featureFlags |= (lightCount != 0 ? LIGHTFEATUREFLAGS_ENV : 0);
|
|
|
|
// if the pixel is not a water pixel, we reset the feature flags to 0
|
|
if ((stencilValue & STENCILUSAGE_WATER_SURFACE) == 0)
|
|
featureFlags = 0;
|
|
|
|
// Now that we defined the state of this specific pixel, we need to gather across the wave to know how to classify it
|
|
#if defined(PLATFORM_SUPPORTS_WAVE_INTRINSICS)
|
|
// Gather the feature flags through the wave
|
|
uint tileFeatureFlags = WaveActiveBitOr(featureFlags);
|
|
#else
|
|
// First lane initializes the LDS
|
|
if (groupIndex == 0)
|
|
gs_tileFeatureFlags = 0;
|
|
|
|
GroupMemoryBarrierWithGroupSync();
|
|
|
|
// TODO, do a parallel reduction here instead of a dumb interlock
|
|
uint previousValue = 0;
|
|
InterlockedOr(gs_tileFeatureFlags, featureFlags, previousValue);
|
|
GroupMemoryBarrierWithGroupSync();
|
|
uint tileFeatureFlags = gs_tileFeatureFlags;
|
|
#endif
|
|
|
|
// We now need to do two things:
|
|
// - Increase the number of active tiles of the variant in the indirect buffer
|
|
// - Store the coordinates of the tile into the array
|
|
if (groupIndex == 0 && tileFeatureFlags != 0)
|
|
{
|
|
// Evaluate the variant index
|
|
int variant = FeatureFlagsToTileVariant_Water(tileFeatureFlags);
|
|
|
|
// Evaluate the tile index
|
|
uint prevGroupCnt;
|
|
uint tileIndex = (unity_StereoEyeIndex << TILE_INDEX_SHIFT_EYE) | (groupId.y << TILE_INDEX_SHIFT_Y) | (groupId.x << TILE_INDEX_SHIFT_X);
|
|
|
|
// Increase the number of tiles in the indirect buffer
|
|
InterlockedAdd(_WaterDispatchIndirectBuffer[variant * 3 + 0], 1, prevGroupCnt);
|
|
_WaterTileBufferRW[variant * _WaterNumTiles * _XRViewCount + prevGroupCnt] = tileIndex;
|
|
|
|
// We also use an additional variant to track all the tiles that have water
|
|
InterlockedAdd(_WaterDispatchIndirectBuffer[NUM_WATER_VARIANTS * 3 + 0], 1, prevGroupCnt);
|
|
_WaterTileBufferRW[NUM_WATER_VARIANTS * _WaterNumTiles * _XRViewCount + prevGroupCnt] = tileIndex;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined (USE_INDIRECT)
|
|
[numthreads(8, 8, 1)]
|
|
void PrepareSSRIndirect(uint2 groupThreadId : SV_GroupThreadID, uint groupId : SV_GroupID)
|
|
{
|
|
// Evaluate the actual dispatch
|
|
uint3 dispatchThreadId = GetActualDispatchThread(groupThreadId, groupId);
|
|
UNITY_XR_ASSIGN_VIEW_INDEX(dispatchThreadId.z);
|
|
uint2 currentCoord = dispatchThreadId.xy;
|
|
|
|
// Is this a water pixel?
|
|
uint stencilValue = GetStencilValue(LOAD_TEXTURE2D_X(_StencilTexture, currentCoord));
|
|
if ((stencilValue & STENCILUSAGE_WATER_SURFACE) == 0)
|
|
return;
|
|
|
|
// Decode the normal and the smoothness
|
|
NormalData normalData;
|
|
DecodeWaterFromNormalBuffer(currentCoord, normalData);
|
|
|
|
// Grab the surface index of the current surface
|
|
uint surfaceIndex;
|
|
int frontFace;
|
|
DecompressWaterSSRData(currentCoord, surfaceIndex, frontFace);
|
|
|
|
// Grab the matching water profile
|
|
WaterSurfaceProfile profile = _WaterSurfaceProfiles[surfaceIndex];
|
|
|
|
// Adjust the normal based on where we are w/r to the surface
|
|
if (frontFace)
|
|
AdjustWaterNormalForSSR(profile, normalData.normalWS);
|
|
|
|
// Encode the normal data and output it
|
|
float4 outputNormalData;
|
|
EncodeIntoNormalBuffer(normalData, outputNormalData);
|
|
_NormalBufferRW[COORD_TEXTURE2D_X(currentCoord)] = outputNormalData;
|
|
}
|
|
#endif
|
|
|
|
#if defined (USE_INDIRECT)
|
|
[numthreads(8, 8, 1)]
|
|
void WATER_DEFERRED_LIGHTING(uint2 groupThreadId : SV_GroupThreadID, uint groupId : SV_GroupID)
|
|
{
|
|
// Evaluate the actual dispatch
|
|
uint3 dispatchThreadId = GetActualDispatchThread(groupThreadId, groupId);
|
|
uint featureFlags = kWaterFeatureVariantFlags[VARIANT];
|
|
#else
|
|
[numthreads(8, 8, 1)]
|
|
void WATER_DEFERRED_LIGHTING(uint3 dispatchThreadId : SV_DispatchThreadID)
|
|
{
|
|
uint featureFlags = UINT_MAX;
|
|
#endif
|
|
UNITY_XR_ASSIGN_VIEW_INDEX(dispatchThreadId.z);
|
|
|
|
// Compute the pixel position to process
|
|
uint2 currentCoord = dispatchThreadId.xy;
|
|
|
|
// Read the depth value
|
|
float depthValue = LOAD_TEXTURE2D_X(_DepthTexture, currentCoord).x;
|
|
|
|
// If this is a background pixel or an invalid ray, leave right away
|
|
if (depthValue == UNITY_RAW_FAR_CLIP_VALUE)
|
|
return;
|
|
|
|
// Is this a water pixel?
|
|
uint stencilValue = GetStencilValue(LOAD_TEXTURE2D_X(_StencilTexture, currentCoord));
|
|
if ((stencilValue & STENCILUSAGE_WATER_SURFACE) == 0)
|
|
return;
|
|
|
|
// Compute the posInput
|
|
uint2 clusterTile = currentCoord / GetTileSize();
|
|
PositionInputs posInput = GetPositionInput(currentCoord, _ScreenSize.zw, depthValue, UNITY_MATRIX_I_VP, GetWorldToViewMatrix(), clusterTile);
|
|
|
|
// Compute the view vector
|
|
float3 V = GetWorldSpaceNormalizeViewDir(posInput.positionWS);
|
|
|
|
// Read the bsdf data and builtin data from the gbuffer
|
|
BSDFData bsdfData;
|
|
ZERO_INITIALIZE(BSDFData, bsdfData);
|
|
|
|
BuiltinData builtinData;
|
|
ZERO_INITIALIZE(BuiltinData, builtinData);
|
|
|
|
// Decode the water data from the gbuffer
|
|
DecodeFromGBuffer(currentCoord, bsdfData, builtinData);
|
|
|
|
// Compute the prelight data
|
|
PreLightData preLightData = GetPreLightData(V, posInput, bsdfData);
|
|
|
|
// Modify the bake diffuse lighting here because we don't benefit from the pass done during the post init builtin data
|
|
builtinData.bakeDiffuseLighting *= preLightData.diffuseFGD * GetIndirectDiffuseMultiplier(builtinData.renderingLayers);
|
|
|
|
// Evaluate the light loop
|
|
LightLoopOutput lightLoopOutput;
|
|
LightLoop(V, posInput, preLightData, bsdfData, builtinData, featureFlags, lightLoopOutput);
|
|
|
|
// Combine both lighting terms and apply the exposure
|
|
float3 finalColor = (lightLoopOutput.diffuseLighting + lightLoopOutput.specularLighting) * GetCurrentExposureMultiplier();
|
|
|
|
// Output to the color buffer
|
|
_CameraColorTextureRW[COORD_TEXTURE2D_X(currentCoord)] = float4(finalColor, 1.0);
|
|
}
|
|
|
|
#if defined (USE_INDIRECT)
|
|
[numthreads(8, 8, 1)]
|
|
void WATER_FOG_INDIRECT(uint2 groupThreadId : SV_GroupThreadID, uint groupId : SV_GroupID)
|
|
{
|
|
// Evaluate the actual dispatch
|
|
uint3 dispatchThreadId = GetActualDispatchThread(groupThreadId, groupId);
|
|
UNITY_XR_ASSIGN_VIEW_INDEX(dispatchThreadId.z);
|
|
uint2 currentCoord = dispatchThreadId.xy;
|
|
|
|
// Is this a water pixel?
|
|
uint stencilValue = GetStencilValue(LOAD_TEXTURE2D_X(_StencilTexture, currentCoord));
|
|
if ((stencilValue & STENCILUSAGE_WATER_SURFACE) == 0)
|
|
return;
|
|
|
|
// Read the depth value
|
|
float depthValue = LOAD_TEXTURE2D_X(_DepthTexture, currentCoord).x;
|
|
|
|
// Compute the posInput
|
|
PositionInputs posInput = GetPositionInput(currentCoord, _ScreenSize.zw, depthValue, UNITY_MATRIX_I_VP, GetWorldToViewMatrix(), 0);
|
|
|
|
// Read the color value
|
|
float3 result = LOAD_TEXTURE2D_X(_CameraColorTexture, currentCoord).xyz;
|
|
|
|
// Atmospheric fog on front faces, absorption on back faces
|
|
float3 volColor = 0, volOpacity = 0;
|
|
|
|
// Compute the view vector
|
|
float3 V = GetWorldSpaceNormalizeViewDir(posInput.positionWS);
|
|
|
|
// Compute water or fog absorption
|
|
EvaluateAtmosphericScattering(posInput, V, volColor, volOpacity);
|
|
|
|
result.rgb = result * (1 - volOpacity) + volColor;
|
|
|
|
// Output to the color buffer
|
|
_CameraColorTextureRW[COORD_TEXTURE2D_X(currentCoord)] = float4(result, 1.0);
|
|
|
|
#if defined(OUTPUT_TRANSMITTANCE_BUFFER)
|
|
float2 transmittance = _TransmittanceBufferRW[COORD_TEXTURE2D_X(currentCoord)] * (1 - volOpacity.x);
|
|
_TransmittanceBufferRW[COORD_TEXTURE2D_X(currentCoord)] = transmittance;
|
|
#endif
|
|
}
|
|
#endif
|