KopMap/Assets/WaterWorks/Shaders/Water_Volume.hlsl
2025-04-03 02:30:16 +08:00

175 lines
5.1 KiB
HLSL

#ifndef Water_Volume
#define Water_Volume
CBUFFER_START(UnityPerMaterial)
Texture2D _MainTex;
sampler sampler_MainTex;
float4 Albedo;
float density;
float3 pos;
float3 bounds;
CBUFFER_END
float2 random2D(float2 UV, float offset)
{
float2x2 m = float2x2(15.27f, 47.63f, 99.41f, 89.98f);
UV = frac(sin(mul(UV, m)));
return float2(sin(UV.y * +offset) * 0.5f + 0.5f, cos(UV.x * offset) * 0.5f + 0.5f);
}
float random3D(float3 uv)
{
float Coord = (uv.x + uv.y + uv.z);
float2 _uv = float2(Coord, Coord);
float2 noise = (frac(sin(dot(_uv, float2(12.9898, 78.233) * 2.0)) * 43758.5453));
return (abs(noise.x + noise.y) - 1);
}
float2 Cellular(float2 UV, float AngleOffset)
{
float2 g = floor(UV);
float2 f = frac(UV);
float2 res = float2(8, 8);
[unroll]
for (int y = -1; y <= 1; y++)
{
[unroll]
for (int x = -1; x <= 1; x++)
{
float2 lattice = float2(x, y);
float2 offset = random2D(lattice + g, AngleOffset);
float dist = distance(lattice + offset, f);
if (dist < res.x)
{
res.y = length(offset);
res.x = dist;
}
}
}
return res;
}
float2 rayBoxDst(float3 boundsMin, float3 boundsMax, float3 rayOrigin, float3 invRaydir)
{
float3 t0 = (boundsMin - rayOrigin) * invRaydir;
float3 t1 = (boundsMax - rayOrigin) * invRaydir;
float3 tmin = min(t0, t1);
float3 tmax = max(t0, t1);
float dstA = max(max(tmin.x, tmin.y), tmin.z);
float dstB = min(tmax.x, min(tmax.y, tmax.z));
float dstToBox = max(0, dstA);
float dstInsideBox = max(0, dstB - dstToBox);
return float2(dstToBox, dstInsideBox);
}
float3 GetRay(float2 screenPos)
{
float3 viewVector = mul(unity_CameraInvProjection, float4(screenPos * 2 - 1, 0, -1));
float3 viewDir = mul(unity_CameraToWorld, float4(viewVector, 0));
float viewLength = length(viewDir);
float3 ray = viewDir / viewLength;
return ray;
}
float SceneDepth(float2 UV)
{
return LinearEyeDepth(SHADERGRAPH_SAMPLE_SCENE_DEPTH(UV), _ZBufferParams);
}
SurfaceDescription SurfaceDescriptionFunction(SurfaceDescriptionInputs IN)
{
SurfaceDescription surface = (SurfaceDescription)0;
pos.xz += _WorldSpaceCameraPos.xz;
float3 posBL = pos - bounds / 2;
float3 posTR = pos + bounds / 2;
float3 viewVector = mul(unity_CameraInvProjection, float4(IN.ScreenPosition.xy * 2 - 1, 0, -1));
float3 viewDir = mul(unity_CameraToWorld, float4(viewVector, 0));
float viewLength = length(viewDir);
float3 ray = GetRay(IN.ScreenPosition.xy);
float2 boxDist = rayBoxDst(posBL, posTR, _WorldSpaceCameraPos, 1 / ray);
float distToBox = boxDist.x;
float distInBox = boxDist.y;
float3 entryPoint = _WorldSpaceCameraPos + ray * distToBox;
float3 rayPos = entryPoint + ray * viewLength;
float depth = SceneDepth(IN.ScreenPosition.xy) * viewLength;
if (distInBox == 0 || distToBox > depth)
{
surface.BaseColor = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, IN.ScreenPosition.xy / IN.ScreenPosition.w);
return surface;
}
float cumulativeDensity = 0;
float cumulativeDensityNoNoise = 0;
float lighting = 0;
float distTravelled = 0;
float stepSize = 0.5;
int i = 0;
UNITY_LOOP
for (i = 0; i < 250 && distTravelled + distToBox < depth && distTravelled < distInBox; i++)
{
float shadowAtten = 1;
float shadowAttenL = 1;
float shadowAttenR = 1;
float pointDensity;
float distMultiplier = 1;
float yPos = rayPos.y - pos.y;
yPos += bounds.y / 2;
yPos /= bounds.y;
float surfaceDist = pow(yPos, 200);
//surfaceDist = 0;
yPos = 1 - yPos;
yPos = pow(yPos, 50);
float noiseValue = Cellular(rayPos.xz * 0.2, (_Time * 50));
pointDensity = clamp((density * (1 - noiseValue)) + (yPos + surfaceDist), 0, 1);
cumulativeDensity += pointDensity * stepSize;
cumulativeDensityNoNoise += 0.2 * stepSize;
lighting += 0.05 * (1 - noiseValue);
if (1 - exp(-cumulativeDensity) > 1)
{
break;
}
float jitter = 0.9;
float randOffset = (random3D(rayPos) * (2 * (1 - jitter))) + (jitter);
distTravelled += stepSize * randOffset;
rayPos += ray * stepSize * randOffset;
if (distTravelled > 70)
{
stepSize += 10 * distMultiplier;
distMultiplier += 5;
}
}
float totalDensity = exp(-cumulativeDensity);
float totalDensityNoNoise = 1 - exp(-cumulativeDensityNoNoise);
float totalLighting = pow(exp(-lighting), 0.5);
float2 refraction = sin(totalDensity) * 0.1;
float3 background = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, (IN.ScreenPosition.xy / IN.ScreenPosition.w) + refraction);
surface.BaseColor = lerp(background * ((totalLighting * 1) + 0.1), Albedo * (totalLighting + 0.8), (((1 - totalDensity) * (1 - density)) + density) * totalDensityNoNoise);
return surface;
}
#endif