175 lines
5.1 KiB
HLSL
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 |