Files
UnrealEngine/Engine/Plugins/Experimental/Water/Shaders/Private/WaterDataFunctions.ush
2025-05-18 13:04:45 +08:00

215 lines
6.2 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#if VM_SIMULATION==0
#define PER_WAVE_DATA_SIZE 2
#define PER_WATERZONE_DATA_SIZE 2
#define PER_WATERBODY_DATA_SIZE 2
#define PER_WATERZONEVIEW_DATA_SIZE 1
/** Struct containing the decoded water body data */
struct FWaterBodyData
{
// Index of the water zone which owns this body. Points to the position of the water zone in the zone sub-buffer.
int WaterZoneIndex;
// Index into the wave data sub-buffer.
int WaveDataIndex;
// Number of waves to be read from the wave data buffer
int NumWaves;
// Target Wave Mask Depth
float TargetWaveMaskDepth;
float3 FixedVelocity;
float FixedZHeight;
float FixedWaterDepth;
};
/** Struct containing the decoded per-water zone data. */
struct FWaterZoneData
{
float2 Location;
float2 Extent;
float2 HeightExtent;
float GroundZMin;
};
struct FWaveParams
{
float2 Direction;
float Wavelength;
float Amplitude;
float Steepness;
};
struct FWaterZoneViewData
{
float2 Location;
};
int GetWaterZoneDataOffset()
{
return (int)View.WaterData[0].x;
}
int GetWaveDataOffset()
{
return (int)View.WaterData[0].y;
}
int GetWaterZoneViewDataOffset()
{
return (int)View.WaterData[0].z;
}
int GetNumWaterViewData()
{
return (int)View.WaterData[0].w;
}
bool IsWaterLocalTessellationEnabled(int InWaterZoneIndex)
{
const int WaterZoneDataBufferOffset = GetWaterZoneDataOffset();
const int WaterZoneOffset = WaterZoneDataBufferOffset + (InWaterZoneIndex * PER_WATERZONE_DATA_SIZE);
return View.WaterData[WaterZoneOffset + 1].y > 0;
}
int GetWaterInfoTextureViewIndex(int InWaterZoneIndex)
{
int Index = IsWaterLocalTessellationEnabled(InWaterZoneIndex) ? View.WaterInfoTextureViewIndex : 0;
return Index;
}
/** Function to decode the raw data from the water indirection buffer */
FWaterBodyData DecodeWaterBodyData(float4 InDataToDecode0, float4 InDataToDecode1)
{
FWaterBodyData OutWaterBodyData = (FWaterBodyData)0;
OutWaterBodyData.WaterZoneIndex = InDataToDecode0.x;
OutWaterBodyData.WaveDataIndex = InDataToDecode0.y;
OutWaterBodyData.NumWaves = InDataToDecode0.z;
OutWaterBodyData.TargetWaveMaskDepth = InDataToDecode0.w;
OutWaterBodyData.FixedVelocity = float3(f16tof32(asuint(InDataToDecode1.x)), f16tof32(asuint(InDataToDecode1.x) >> 16u), InDataToDecode1.y);
OutWaterBodyData.FixedZHeight = InDataToDecode1.z;
OutWaterBodyData.FixedWaterDepth = InDataToDecode1.w;
return OutWaterBodyData;
}
FWaterBodyData GetWaterBodyData(int InWaterBodyIndex)
{
const int WaterBodyOffset = InWaterBodyIndex * PER_WATERBODY_DATA_SIZE;
const float4 Data0 = View.WaterIndirection[WaterBodyOffset];
const float4 Data1 = View.WaterIndirection[WaterBodyOffset + 1];
return DecodeWaterBodyData(Data0, Data1);
}
/** Function to decode the data for an individual gerstner wave from the water data buffer */
FWaveParams DecodeWaveParams(float4 InDataToDecode0, float4 InDataToDecode1)
{
FWaveParams OutWaveParams = (FWaveParams)0;
OutWaveParams.Direction = InDataToDecode0.xy;
OutWaveParams.Wavelength = InDataToDecode0.z;
OutWaveParams.Amplitude = InDataToDecode0.w;
OutWaveParams.Steepness = InDataToDecode1.x;
return OutWaveParams;
}
FWaveParams GetWaveDataNew(int InWaveIndex, FWaterBodyData InWaterBodyData)
{
const int WaveDataOffset = GetWaveDataOffset();
const int AbsoluteWaveDataIndex = WaveDataOffset + (InWaterBodyData.WaveDataIndex + InWaveIndex) * PER_WAVE_DATA_SIZE;
const float4 Data0 = View.WaterData[AbsoluteWaveDataIndex];
const float4 Data1 = View.WaterData[AbsoluteWaveDataIndex + 1];
return DecodeWaveParams(Data0, Data1);
}
FWaterZoneData DecodeWaterZoneData(float2 Location, float4 Data0, float4 Data1)
{
FWaterZoneData OutWaterZoneData = (FWaterZoneData)0;
OutWaterZoneData.Location = Location;
OutWaterZoneData.Extent = Data0.xy;
OutWaterZoneData.HeightExtent = Data0.zw;
OutWaterZoneData.GroundZMin = Data1.x;
return OutWaterZoneData;
}
FWaterZoneViewData GetWaterZoneViewData(int InWaterZoneIndex)
{
const int NumViews = GetNumWaterViewData();
const int ViewIndex = GetWaterInfoTextureViewIndex(InWaterZoneIndex);
const int WaterZoneViewDataBufferOffset = GetWaterZoneViewDataOffset();
const int WaterZoneViewOffset = WaterZoneViewDataBufferOffset + (InWaterZoneIndex * NumViews + ViewIndex) * PER_WATERZONEVIEW_DATA_SIZE;
FWaterZoneViewData WaterZoneViewData = (FWaterZoneViewData)0;
WaterZoneViewData.Location = View.WaterData[WaterZoneViewOffset].xy;
return WaterZoneViewData;
}
FWaterZoneData GetWaterZoneData(int InWaterZoneIndex)
{
const int WaterZoneDataBufferOffset = GetWaterZoneDataOffset();
const int WaterZoneOffset = WaterZoneDataBufferOffset + (InWaterZoneIndex * PER_WATERZONE_DATA_SIZE);
FWaterZoneViewData WaterZoneViewData = GetWaterZoneViewData(InWaterZoneIndex);
const float2 ZoneViewLocation = WaterZoneViewData.Location;
const float4 Data0 = View.WaterData[WaterZoneOffset];
const float4 Data1 = View.WaterData[WaterZoneOffset + 1];
return DecodeWaterZoneData(ZoneViewLocation, Data0, Data1);
}
FWaterZoneData GetWaterZoneDataForWaterBody(int InWaterBodyIndex)
{
const int WaterZoneIndex = GetWaterBodyData(InWaterBodyIndex).WaterZoneIndex;
return GetWaterZoneData(WaterZoneIndex);
}
float DecodeWaterInfoGroundHeight(float4 WaterInfoSample, int WaterZoneIndex)
{
const float GroundZNormalized = WaterInfoSample.w;
const FWaterZoneData WaterZoneData = GetWaterZoneData(WaterZoneIndex);
const float GroundZScale = WaterZoneData.HeightExtent.y - WaterZoneData.GroundZMin;
return GroundZNormalized * GroundZScale + WaterZoneData.GroundZMin;
}
float DecodeWaterInfoZHeight(float4 WaterInfoSample, int WaterZoneIndex)
{
const float WaterZNormalized = WaterInfoSample.z;
const FWaterZoneData WaterZoneData = GetWaterZoneData(WaterZoneIndex);
const float WaterZScale = WaterZoneData.HeightExtent.y - WaterZoneData.HeightExtent.x;
float WaterZ = WaterZNormalized * WaterZScale + WaterZoneData.HeightExtent.x;
// If below 0, we need to push the height below the height of the terrain
if (WaterZNormalized <= 0.0)
{
WaterZ = DecodeWaterInfoGroundHeight(WaterInfoSample, WaterZoneIndex) - 256.0;
}
return WaterZ;
}
float2 DecodeWaterInfoVelocity(float4 WaterInfoSample, float MaxVelocity)
{
const float2 NormalizedFlow = WaterInfoSample.xy;
return (NormalizedFlow - 0.5) * 2.0 * MaxVelocity;
}
#endif