2025-10-21 14:18:31 +09:00

109 lines
3.3 KiB
HLSL

// Stylized Water 3 by Staggart Creations (http://staggart.xyz)
// COPYRIGHT PROTECTED UNDER THE UNITY ASSET STORE EULA (https://unity.com/legal/as-terms)
// • Copying or referencing source code for the production of new asset store, or public, content is strictly prohibited!
// • Uploading this file to a public repository will subject it to an automated DMCA takedown request.
#include "Projection.hlsl"
uniform bool _WaterHeightPrePassAvailable;
#define VOID_THRESHOLD -1000 //Same value as in HeightPrePass class
uniform float3 _WaterHeightCoords;
//XY: Bounds min
//Z: Bounds size
uniform Texture2D _WaterHeightBuffer;
//RED: Geometry world height
//GREEN: Relative world height (displacement effects)
#ifndef UNITY_CORE_SAMPLERS_INCLUDED
SamplerState sampler_LinearClamp;
#endif
//Position, relative to rendering bounds (normalized 0-1)
float2 WorldToHeightUV(float3 positionWS)
{
return WorldToProjectionUV(positionWS, _WaterHeightCoords.xy, _WaterHeightCoords.z);
}
//May be used to validate if the sampled (summed) height is actually from a water surface
bool HasHitWaterSurface(float height)
{
return height > VOID_THRESHOLD;
}
float2 SampleHeightBuffer(float2 uv)
{
//if(_WaterHeightPrePassAvailable == false) return VOID_THRESHOLD;
float2 heightData = _WaterHeightBuffer.SampleLevel(sampler_LinearClamp, uv, 0).rg;
return heightData;
}
//Main function
float2 SampleWaterHeight(float3 positionWS)
{
return SampleHeightBuffer(WorldToHeightUV(positionWS));
}
//Alternative version
void SampleWaterHeights(float3 positionWS, out float geometryHeight, out float displacement)
{
float2 heights = SampleHeightBuffer(WorldToHeightUV(positionWS));
geometryHeight = heights.r;
displacement = heights.g;
}
//Derive a world-space normal from the height data
float3 CalculateWaterNormal(float3 positionWS, float strength)
{
if(_WaterHeightPrePassAvailable == false) return float3(0,1,0);
//Note: not using the buffer's texel size so that the sampled result remains consistent across different resolutions.
const float radius = 1.0 / _WaterHeightCoords.z;
float2 uv = WorldToHeightUV(positionWS);
const float2 xMinSample = SampleHeightBuffer(float2(uv.x - radius, uv.y)).rg;
const float xLeft = xMinSample.r + xMinSample.g;
const float2 xMaxSample = SampleHeightBuffer(float2(uv.x + radius, uv.y)).rg;
const float xRight = xMaxSample.r + xMaxSample.g;
const float2 yMaxSample = SampleHeightBuffer(float2(uv.x, uv.y + radius)).rg;
const float yUp = yMaxSample.r + yMaxSample.g;
const float2 yMinSample = SampleHeightBuffer(float2(uv.x, uv.y - radius)).rg;
const float yDown = yMinSample.r + yMinSample.g;
float xDelta = (xLeft - xRight) * strength;
float zDelta = (yDown - yUp) * strength;
float3 normal = float3(xDelta, 1.0, zDelta);
//return float3(0,xLeft,0);
return normalize(normal.xyz);
}
//Shader Graph
void SampleWaterHeight_float(float3 positionWS, out float geometryHeight, out float displacement)
{
#if defined(SHADERGRAPH_PREVIEW)
geometryHeight = positionWS.y;
displacement = 0.0;
#else
float2 heights = SampleWaterHeight(positionWS);
geometryHeight = heights.r;
displacement = heights.g;
#endif
}
//Shader Graph
void CalculateWaterNormal_float(float3 positionWS, float strength, out float3 normal)
{
#if defined(SHADERGRAPH_PREVIEW)
normal = float3(0,1,0);
#else
normal = CalculateWaterNormal(positionWS, strength);
#endif
}