916 lines
24 KiB
HLSL
916 lines
24 KiB
HLSL
#ifndef KWS_COMMON_HELPERS
|
|
#define KWS_COMMON_HELPERS
|
|
|
|
float2 SpriteUV(float Width, float Height, float time, float2 uv)
|
|
{
|
|
float2 size = float2(1.0f / Width, 1.0f / Height);
|
|
uint totalFrames = Width * Height;
|
|
|
|
uint index = time;
|
|
|
|
uint indexX = index % Width;
|
|
uint indexY = floor((index % totalFrames) / Width);
|
|
|
|
float2 offset = float2(size.x * indexX, -size.y * indexY);
|
|
float2 newUV = frac(uv) * size;
|
|
|
|
newUV.y = newUV.y + size.y * (Height - 1);
|
|
return newUV + offset;
|
|
}
|
|
|
|
float KWS_Noise13(float3 p3)
|
|
{
|
|
p3 = frac(p3 * .1031);
|
|
p3 += dot(p3, p3.zyx + 31.32);
|
|
return frac((p3.x + p3.y) * p3.z);
|
|
}
|
|
|
|
float InterleavedGradientNoise(float2 pixel, float frame)
|
|
{
|
|
frame = frame % 64; //todo check why its jittered?
|
|
//frame = (_Time.y * 0.1) % 3;
|
|
pixel += (frame * 5.588238f);
|
|
return frac(52.9829189f * frac(0.06711056f * pixel.x + 0.00583715f * pixel.y));
|
|
}
|
|
|
|
inline float3 KWS_BlendNormals(float3 n1, float3 n2)
|
|
{
|
|
return normalize(float3(n1.x + n2.x, n1.y * n2.y, n1.z + n2.z));
|
|
}
|
|
|
|
inline float3 KWS_BlendNormals(float3 n1, float3 n2, float3 n3)
|
|
{
|
|
return normalize(float3(n1.x + n2.x + n3.x, n1.y * n2.y * n3.y, n1.z + n2.z + n3.z));
|
|
}
|
|
|
|
|
|
inline half3 KWS_GetDerivativeNormal(float3 pos, float rojectionParamsX)
|
|
{
|
|
return normalize(cross(ddx(pos), ddy(pos) * rojectionParamsX));
|
|
}
|
|
|
|
inline half KWS_Pow2(half x)
|
|
{
|
|
return x * x;
|
|
}
|
|
|
|
inline half KWS_Pow3(half x)
|
|
{
|
|
return x * x * x;
|
|
}
|
|
|
|
inline float KWS_Pow5(float x)
|
|
{
|
|
float val = x * x;
|
|
return val * val * x;
|
|
}
|
|
|
|
inline float KWS_Pow10(float x)
|
|
{
|
|
float val = x * x * x;
|
|
return val * val * x;
|
|
}
|
|
|
|
inline float KWS_Pow20(float x)
|
|
{
|
|
float x2 = x * x; // x^2
|
|
float x4 = x2 * x2; // x^4
|
|
float x5 = x4 * x; // x^5
|
|
float x10 = x5 * x5; // x^10
|
|
return x10 * x10; // x^20
|
|
}
|
|
|
|
float KWS_MAX(float2 v)
|
|
{
|
|
return max(v.x, v.y);
|
|
}
|
|
|
|
float KWS_MAX(float3 v)
|
|
{
|
|
return max(max(v.x, v.y), v.z);
|
|
}
|
|
|
|
float KWS_MAX(float4 v)
|
|
{
|
|
return max(max(v.x, v.y), max(v.z, v.w));
|
|
}
|
|
|
|
float KWS_MIN(float2 v)
|
|
{
|
|
return min(v.x, v.y);
|
|
}
|
|
|
|
float KWS_MIN(float3 v)
|
|
{
|
|
return min(min(v.x, v.y), v.z);
|
|
}
|
|
|
|
float KWS_MIN(float4 v)
|
|
{
|
|
return min(min(v.x, v.y), min(v.z, v.w));
|
|
}
|
|
|
|
|
|
float2 GetRTHandleUV(float2 UV, float2 texelSize, float numberOfTexels, float2 scale)
|
|
{
|
|
float2 maxCoord = 1.0f - numberOfTexels * texelSize;
|
|
return min(UV, maxCoord) * scale;
|
|
}
|
|
|
|
float2 GetRTHandleUVBilinear(float2 UV, float4 texelSize, float numberOfTexels, float2 scale)
|
|
{
|
|
float2 maxCoord = 1.0f - numberOfTexels * texelSize.xy;
|
|
UV = min(UV, maxCoord);
|
|
return floor(UV * scale * texelSize.zw) * texelSize.xy;
|
|
}
|
|
|
|
|
|
// filtering
|
|
|
|
inline float4 Texture2DSampleAA(Texture2D tex, SamplerState state, float2 uv)
|
|
{
|
|
half4 color = tex.Sample(state, uv.xy);
|
|
|
|
float2 uv_dx = ddx(uv);
|
|
float2 uv_dy = ddy(uv);
|
|
|
|
color += tex.Sample(state, uv.xy + (0.25) * uv_dx + (0.75) * uv_dy);
|
|
color += tex.Sample(state, uv.xy + (-0.25) * uv_dx + (-0.75) * uv_dy);
|
|
color += tex.Sample(state, uv.xy + (-0.75) * uv_dx + (0.25) * uv_dy);
|
|
color += tex.Sample(state, uv.xy + (0.75) * uv_dx + (-0.25) * uv_dy);
|
|
|
|
color /= 5.0;
|
|
|
|
return color;
|
|
}
|
|
|
|
float4 cubic(float v)
|
|
{
|
|
float4 n = float4(1.0, 2.0, 3.0, 4.0) - v;
|
|
float4 s = n * n * n;
|
|
float x = s.x;
|
|
float y = s.y - 4.0 * s.x;
|
|
float z = s.z - 4.0 * s.y + 6.0 * s.x;
|
|
float w = 6.0 - x - y - z;
|
|
return float4(x, y, z, w) * (1.0 / 6.0);
|
|
}
|
|
|
|
|
|
inline float4 Texture2DArraySampleBicubic(Texture2DArray tex, SamplerState state, float2 uv, float4 texelSize, float idx)
|
|
{
|
|
uv = uv * texelSize.zw - 0.5;
|
|
float2 fxy = frac(uv);
|
|
uv -= fxy;
|
|
|
|
float4 xcubic = cubic(fxy.x);
|
|
float4 ycubic = cubic(fxy.y);
|
|
|
|
float4 c = uv.xxyy + float2(-0.5, +1.5).xyxy;
|
|
float4 s = float4(xcubic.xz + xcubic.yw, ycubic.xz + ycubic.yw);
|
|
float4 offset = c + float4(xcubic.yw, ycubic.yw) / s;
|
|
offset *= texelSize.xxyy;
|
|
|
|
half4 sample0 = tex.Sample(state, float3(offset.xz, idx));
|
|
half4 sample1 = tex.Sample(state, float3(offset.yz, idx));
|
|
half4 sample2 = tex.Sample(state, float3(offset.xw, idx));
|
|
half4 sample3 = tex.Sample(state, float3(offset.yw, idx));
|
|
|
|
float sx = s.x / (s.x + s.y);
|
|
float sy = s.z / (s.z + s.w);
|
|
|
|
return lerp(lerp(sample3, sample2, sx), lerp(sample1, sample0, sx), sy);
|
|
}
|
|
|
|
inline float4 Texture2DArraySampleLevelBicubic(Texture2DArray tex, SamplerState state, float2 uv, float4 texelSize, float idx, float level)
|
|
{
|
|
uv = uv * texelSize.zw - 0.5;
|
|
float2 fxy = frac(uv);
|
|
uv -= fxy;
|
|
|
|
float4 xcubic = cubic(fxy.x);
|
|
float4 ycubic = cubic(fxy.y);
|
|
|
|
float4 c = uv.xxyy + float2(-0.5, +1.5).xyxy;
|
|
float4 s = float4(xcubic.xz + xcubic.yw, ycubic.xz + ycubic.yw);
|
|
float4 offset = c + float4(xcubic.yw, ycubic.yw) / s;
|
|
offset *= texelSize.xxyy;
|
|
|
|
float4 sample0 = tex.SampleLevel(state, float3(offset.xz, idx), level);
|
|
float4 sample1 = tex.SampleLevel(state, float3(offset.yz, idx), level);
|
|
float4 sample2 = tex.SampleLevel(state, float3(offset.xw, idx), level);
|
|
float4 sample3 = tex.SampleLevel(state, float3(offset.yw, idx), level);
|
|
|
|
float sx = s.x / (s.x + s.y);
|
|
float sy = s.z / (s.z + s.w);
|
|
|
|
return lerp(lerp(sample3, sample2, sx), lerp(sample1, sample0, sx), sy);
|
|
}
|
|
|
|
inline float3 Texture2DArraySampleLevelBicubic(Texture2DArray<float3> tex, SamplerState state, float2 uv, float4 texelSize, float idx, float level)
|
|
{
|
|
uv = uv * texelSize.zw - 0.5;
|
|
float2 fxy = frac(uv);
|
|
uv -= fxy;
|
|
|
|
float4 xcubic = cubic(fxy.x);
|
|
float4 ycubic = cubic(fxy.y);
|
|
|
|
float4 c = uv.xxyy + float2(-0.5, +1.5).xyxy;
|
|
float4 s = float4(xcubic.xz + xcubic.yw, ycubic.xz + ycubic.yw);
|
|
float4 offset = c + float4(xcubic.yw, ycubic.yw) / s;
|
|
offset *= texelSize.xxyy;
|
|
|
|
float3 sample0 = tex.SampleLevel(state, float3(offset.xz, idx), level).xyz;
|
|
float3 sample1 = tex.SampleLevel(state, float3(offset.yz, idx), level).xyz;
|
|
float3 sample2 = tex.SampleLevel(state, float3(offset.xw, idx), level).xyz;
|
|
float3 sample3 = tex.SampleLevel(state, float3(offset.yw, idx), level).xyz;
|
|
|
|
float sx = s.x / (s.x + s.y);
|
|
float sy = s.z / (s.z + s.w);
|
|
|
|
return lerp(lerp(sample3, sample2, sx), lerp(sample1, sample0, sx), sy);
|
|
}
|
|
|
|
inline float4 Texture2DSampleLevelBicubic(Texture2D tex, SamplerState state, float2 uv, float4 texelSize, float level)
|
|
{
|
|
uv = uv * texelSize.zw - 0.5;
|
|
float2 fxy = frac(uv);
|
|
uv -= fxy;
|
|
|
|
float4 xcubic = cubic(fxy.x);
|
|
float4 ycubic = cubic(fxy.y);
|
|
|
|
float4 c = uv.xxyy + float2(-0.5, +1.5).xyxy;
|
|
float4 s = float4(xcubic.xz + xcubic.yw, ycubic.xz + ycubic.yw);
|
|
float4 offset = c + float4(xcubic.yw, ycubic.yw) / s;
|
|
offset *= texelSize.xxyy;
|
|
|
|
half4 sample0 = tex.SampleLevel(state, offset.xz, level);
|
|
half4 sample1 = tex.SampleLevel(state, offset.yz, level);
|
|
half4 sample2 = tex.SampleLevel(state, offset.xw, level);
|
|
half4 sample3 = tex.SampleLevel(state, offset.yw, level);
|
|
|
|
float sx = s.x / (s.x + s.y);
|
|
float sy = s.z / (s.z + s.w);
|
|
|
|
return lerp(lerp(sample3, sample2, sx), lerp(sample1, sample0, sx), sy);
|
|
}
|
|
|
|
inline float4 Texture2DSampleBicubic(Texture2D tex, SamplerState state, float2 uv, float4 texelSize)
|
|
{
|
|
uv = uv * texelSize.zw - 0.5;
|
|
float2 fxy = frac(uv);
|
|
uv -= fxy;
|
|
|
|
float4 xcubic = cubic(fxy.x);
|
|
float4 ycubic = cubic(fxy.y);
|
|
|
|
float4 c = uv.xxyy + float2(-0.5, +1.5).xyxy;
|
|
float4 s = float4(xcubic.xz + xcubic.yw, ycubic.xz + ycubic.yw);
|
|
float4 offset = c + float4(xcubic.yw, ycubic.yw) / s;
|
|
offset *= texelSize.xxyy;
|
|
|
|
half4 sample0 = tex.Sample(state, offset.xz);
|
|
half4 sample1 = tex.Sample(state, offset.yz);
|
|
half4 sample2 = tex.Sample(state, offset.xw);
|
|
half4 sample3 = tex.Sample(state, offset.yw);
|
|
|
|
float sx = s.x / (s.x + s.y);
|
|
float sy = s.z / (s.z + s.w);
|
|
|
|
return lerp(lerp(sample3, sample2, sx), lerp(sample1, sample0, sx), sy);
|
|
}
|
|
|
|
inline float4 Texture2DSampleBilinear(Texture2D tex, SamplerState state, float2 uv, float4 texelSize)
|
|
{
|
|
uv = uv * texelSize.zw + 0.5;
|
|
float2 iuv = floor(uv);
|
|
float2 fuv = frac(uv);
|
|
uv = iuv + fuv * fuv * (3.0 - 2.0 * fuv); // fuv*fuv*fuv*(fuv*(fuv*6.0-15.0)+10.0);;
|
|
uv = (uv - 0.5) * texelSize.xy;
|
|
return tex.Sample(state, uv);
|
|
}
|
|
|
|
inline float4 Texture2DSampleLevelBilinear(Texture2D tex, SamplerState state, float2 uv, float4 texelSize, float level)
|
|
{
|
|
uv = uv * texelSize.zw + 0.5;
|
|
float2 iuv = floor(uv);
|
|
float2 fuv = frac(uv);
|
|
uv = iuv + fuv * fuv * (3.0 - 2.0 * fuv); // fuv*fuv*fuv*(fuv*(fuv*6.0-15.0)+10.0);;
|
|
uv = (uv - 0.5) * texelSize.xy;
|
|
return tex.SampleLevel(state, uv, level);
|
|
}
|
|
|
|
float4 Texture2DSampleFlowmapJump(Texture2D tex, SamplerState state, float2 uv, float2 direction, float time)
|
|
{
|
|
float2 d = sin(uv * 3.1415);
|
|
time -= (d.x + d.y) * 0.25 + 0.5;
|
|
|
|
float progressA = frac(time) - 0.5;
|
|
float progressB = frac(time + 0.5) - 0.5;
|
|
|
|
float2 jump = float2(0.248, 0.201);
|
|
float2 offsetA = (time - progressA) * jump;
|
|
float2 offsetB = (time - progressB) * jump + 0.5;
|
|
|
|
float4 colorA = tex.Sample(state, uv - progressA * direction + offsetA);
|
|
float4 colorB = tex.Sample(state, uv - progressB * direction + offsetB);
|
|
|
|
|
|
float weight = saturate(abs(progressA * 2.0));
|
|
// weight = weight * weight * weight * (weight * (weight * 6.0 - 15.0) + 10.0);
|
|
|
|
float EmpiricallyPatternFixVal = 1.06;
|
|
float flowLerpFix = lerp(EmpiricallyPatternFixVal, 1, abs(weight * 2 - 1));
|
|
|
|
return lerp(colorA, colorB, weight) * flowLerpFix;
|
|
}
|
|
|
|
|
|
float4 Texture2DSampleFlowmap(Texture2D tex, SamplerState state, float2 uv, float2 direction, float time)
|
|
{
|
|
float progressA = frac(time) - 0.5;
|
|
float progressB = frac(time + 0.5) - 0.5;
|
|
|
|
float4 colorA = tex.Sample(state, uv - progressA * direction);
|
|
float4 colorB = tex.Sample(state, uv - progressB * direction);
|
|
|
|
float weight = saturate(abs(progressA * 2.0));
|
|
|
|
float flowLerpFix = lerp(1, 0.75, saturate(length(direction)) * abs(weight * 2 - 1));
|
|
|
|
return lerp(colorA, colorB, weight) * flowLerpFix;
|
|
|
|
//float flowSpeed = saturate(length(direction));
|
|
|
|
//half time1 = frac(time + 0.5);
|
|
//half time2 = frac(time);
|
|
|
|
//float2 uvOffset1 = -direction * time1;
|
|
//float2 uvOffset2 = -direction * time2;
|
|
//float flowLerp = abs((0.5 - time1) / 0.5);
|
|
//float flowLerpFix = lerp(1, 0.75, flowSpeed * abs(flowLerp * 2 - 1));
|
|
|
|
//float4 colorA = tex.Sample(state, uv + uvOffset1);
|
|
//float4 colorB = tex.Sample(state, uv + uvOffset2);
|
|
//return lerp(colorA, colorB, flowLerp) * flowLerpFix;
|
|
}
|
|
|
|
inline bool IsOutsideUvBorders(float2 uv)
|
|
{
|
|
uv = uv * 1.01 - 0.005;
|
|
return any(uv != saturate(uv));
|
|
}
|
|
|
|
inline bool IsOutsideUV(float2 uv)
|
|
{
|
|
return uv.x < 0.002 || uv.x > 0.998 || uv.y < 0.002 || uv.y > 0.998;
|
|
}
|
|
|
|
inline bool IsInsideUV(float2 uv)
|
|
{
|
|
return !IsOutsideUV(uv);
|
|
}
|
|
|
|
|
|
inline float4 SampleTextureArray2(Texture2D tex0, Texture2D tex1, uint id, float2 uv)
|
|
{
|
|
KWS_FORCECASE switch(id)
|
|
{
|
|
case 0: return tex0.SampleLevel(sampler_linear_clamp, uv, 0);
|
|
case 1: return tex1.SampleLevel(sampler_linear_clamp, uv, 0);
|
|
default: return 0;
|
|
}
|
|
}
|
|
|
|
inline float4 SampleTextureArray4(Texture2D tex0, Texture2D tex1, Texture2D tex2, Texture2D tex3, uint id, float2 uv)
|
|
{
|
|
KWS_FORCECASE switch(id)
|
|
{
|
|
case 0: return tex0.SampleLevel(sampler_linear_clamp, uv, 0);
|
|
case 1: return tex1.SampleLevel(sampler_linear_clamp, uv, 0);
|
|
case 2: return tex2.SampleLevel(sampler_linear_clamp, uv, 0);
|
|
case 3: return tex3.SampleLevel(sampler_linear_clamp, uv, 0);
|
|
default: return 0;
|
|
}
|
|
}
|
|
|
|
inline float4 SampleTextureArray8(Texture2D tex0, Texture2D tex1, Texture2D tex2, Texture2D tex3, Texture2D tex4, Texture2D tex5, Texture2D tex6, Texture2D tex7, uint id, float2 uv)
|
|
{
|
|
KWS_FORCECASE switch(id)
|
|
{
|
|
case 0: return tex0.SampleLevel(sampler_linear_clamp, uv, 0);
|
|
case 1: return tex1.SampleLevel(sampler_linear_clamp, uv, 0);
|
|
case 2: return tex2.SampleLevel(sampler_linear_clamp, uv, 0);
|
|
case 3: return tex3.SampleLevel(sampler_linear_clamp, uv, 0);
|
|
case 4: return tex4.SampleLevel(sampler_linear_clamp, uv, 0);
|
|
case 5: return tex5.SampleLevel(sampler_linear_clamp, uv, 0);
|
|
case 6: return tex6.SampleLevel(sampler_linear_clamp, uv, 0);
|
|
case 7: return tex7.SampleLevel(sampler_linear_clamp, uv, 0);
|
|
default: return 0;
|
|
}
|
|
}
|
|
|
|
inline float4 SampleTextureArray2_FirstBicubic(Texture2D tex0, Texture2D tex1, uint id, float2 uv, float4 tex0_texelSize)
|
|
{
|
|
KWS_FORCECASE switch(id)
|
|
{
|
|
case 0: return Texture2DSampleLevelBicubic(tex0, sampler_linear_clamp, uv, tex0_texelSize, 0);
|
|
case 1: return tex1.SampleLevel(sampler_linear_clamp, uv, 0);
|
|
default: return 0;
|
|
}
|
|
}
|
|
|
|
inline float4 SampleTextureArray4_FirstBicubic(Texture2D tex0, Texture2D tex1, Texture2D tex2, Texture2D tex3, uint id, float2 uv, float4 tex0_texelSize)
|
|
{
|
|
KWS_FORCECASE switch(id)
|
|
{
|
|
case 0: return Texture2DSampleLevelBicubic(tex0, sampler_linear_clamp, uv, tex0_texelSize, 0);
|
|
case 1: return tex1.SampleLevel(sampler_linear_clamp, uv, 0);
|
|
case 2: return tex2.SampleLevel(sampler_linear_clamp, uv, 0);
|
|
case 3: return tex3.SampleLevel(sampler_linear_clamp, uv, 0);
|
|
default: return 0;
|
|
}
|
|
}
|
|
|
|
inline float4 SampleTextureArray8_FirstBicubic(Texture2D tex0, Texture2D tex1, Texture2D tex2, Texture2D tex3, Texture2D tex4, Texture2D tex5, Texture2D tex6, Texture2D tex7, uint id, float2 uv, float4 tex0_texelSize)
|
|
{
|
|
KWS_FORCECASE switch(id)
|
|
{
|
|
case 0: return Texture2DSampleLevelBicubic(tex0, sampler_linear_clamp, uv, tex0_texelSize, 0);
|
|
case 1: return tex1.SampleLevel(sampler_linear_clamp, uv, 0);
|
|
case 2: return tex2.SampleLevel(sampler_linear_clamp, uv, 0);
|
|
case 3: return tex3.SampleLevel(sampler_linear_clamp, uv, 0);
|
|
case 4: return tex4.SampleLevel(sampler_linear_clamp, uv, 0);
|
|
case 5: return tex5.SampleLevel(sampler_linear_clamp, uv, 0);
|
|
case 6: return tex6.SampleLevel(sampler_linear_clamp, uv, 0);
|
|
case 7: return tex7.SampleLevel(sampler_linear_clamp, uv, 0);
|
|
default: return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//Noises
|
|
|
|
float2 SimpleNoise1_grad(int2 z)
|
|
{
|
|
int n = z.x + z.y * 11111;
|
|
n = (n << 13) ^ n;
|
|
n = (n * (n * n * 15731 + 789221) + 1376312589) >> 16;
|
|
return float2(cos(float(n)), sin(float(n)));
|
|
}
|
|
|
|
float SimpleNoise1(float2 p)
|
|
{
|
|
int2 i = int2(floor(p));
|
|
float2 f = frac(p);
|
|
|
|
float2 u = f * f * (3.0 - 2.0 * f);
|
|
|
|
return lerp(lerp(dot(SimpleNoise1_grad(i + int2(0, 0)), f - float2(0.0, 0.0)),
|
|
dot(SimpleNoise1_grad(i + int2(1, 0)), f - float2(1.0, 0.0)), u.x),
|
|
lerp(dot(SimpleNoise1_grad(i + int2(0, 1)), f - float2(0.0, 1.0)),
|
|
dot(SimpleNoise1_grad(i + int2(1, 1)), f - float2(1.0, 1.0)), u.x), u.y);
|
|
}
|
|
|
|
|
|
|
|
float3 random3(float3 c)
|
|
{
|
|
float j = 4096.0 * sin(dot(c, float3(17.0, 59.4, 15.0)));
|
|
float3 r;
|
|
r.z = frac(512.0 * j);
|
|
j *= 0.125;
|
|
r.x = frac(512.0 * j);
|
|
j *= 0.125;
|
|
r.y = frac(512.0 * j);
|
|
return r - 0.5;
|
|
}
|
|
|
|
|
|
// 3D simplex noise
|
|
float simplex3d(float3 p)
|
|
{
|
|
static const float F3 = 0.3333333;
|
|
static const float G3 = 0.1666667;
|
|
|
|
// Find current tetrahedron T and its four vertices
|
|
float3 s = floor(p + dot(p, F3));
|
|
float3 x = p - s + dot(s, G3);
|
|
|
|
// Calculate i1 and i2
|
|
float3 e = step(0, x - x.yzx);
|
|
float3 i1 = e * (1.0 - e.zxy);
|
|
float3 i2 = 1.0 - e.zxy * (1.0 - e);
|
|
|
|
// Calculate x1, x2, x3
|
|
float3 x1 = x - i1 + G3;
|
|
float3 x2 = x - i2 + 2.0 * G3;
|
|
float3 x3 = x - 1.0 + 3.0 * G3;
|
|
|
|
// Find four surflets and store them in d
|
|
float4 w;
|
|
float4 d;
|
|
|
|
// Calculate surflet weights
|
|
w.x = dot(x, x);
|
|
w.y = dot(x1, x1);
|
|
w.z = dot(x2, x2);
|
|
w.w = dot(x3, x3);
|
|
|
|
// w fades from 0.6 at the center of the surflet to 0.0 at the margin
|
|
w = max(0.6 - w, 0.0);
|
|
|
|
// Calculate surflet components
|
|
d.x = dot(random3(s), x);
|
|
d.y = dot(random3(s + i1), x1);
|
|
d.z = dot(random3(s + i2), x2);
|
|
d.w = dot(random3(s + 1.0), x3);
|
|
|
|
// Multiply d by w^4
|
|
w *= w;
|
|
w *= w;
|
|
d *= w;
|
|
|
|
// Return the sum of the four surflets
|
|
return clamp(dot(d, float4(52.0, 52.0, 52.0, 52.0)), -1, 1) * 0.5 + 0.5;
|
|
}
|
|
|
|
inline float KWS_FormulaRoughDescent01(float x)
|
|
{
|
|
return saturate(x * 1.0575 - sin(pow(x, 100) * 0.01) * 100);
|
|
}
|
|
|
|
////////////////////////////// SDF helpers /////////////////////////////////////////////
|
|
|
|
|
|
float KWS_SDF_Box(float3 pos, float3 size)
|
|
{
|
|
float3 d = abs(pos) - size;
|
|
return length(max(d, 0)) + KWS_MAX(min(d, 0));
|
|
}
|
|
|
|
float KWS_SDF_Box(float3 pos, float3x3 rotationMatrix, float3 size)
|
|
{
|
|
float3 rotatedPos = mul(rotationMatrix, pos).xyz;
|
|
float3 d = abs(rotatedPos) - size;
|
|
return length(max(d, 0)) + KWS_MAX(min(d, 0));
|
|
}
|
|
|
|
float KWS_SDF_Sphere(float3 p, float r)
|
|
{
|
|
return length(p) - r;
|
|
}
|
|
|
|
//inline float2 KWS_SDF_IntersectionBox(float3 pos, float3 rayDir, float3x3 rotationMatrix, float3 size)
|
|
//{
|
|
// float3 rotatedRayDir = mul(rotationMatrix, rayDir).xyz;
|
|
// float3 rotatedPos = mul(rotationMatrix, pos).xyz;
|
|
|
|
// float3 m = 1.0 / rotatedRayDir;
|
|
// float3 n = m * rotatedPos;
|
|
// float3 k = abs(m) * size;
|
|
|
|
// float3 t1 = -n - k;
|
|
// float3 t2 = -n + k;
|
|
|
|
// return float2(max(max(t1.x, t1.y), t1.z),
|
|
// min(min(t2.x, t2.y), t2.z));
|
|
//}
|
|
|
|
inline float2 KWS_SDF_IntersectionBox(float3 startPos, float3 rayDir, float2x2 rotationMatrix, float3 boxCenter, float3 boxSize)
|
|
{
|
|
startPos -= boxCenter;
|
|
float3 rotatedRayDir = rayDir;
|
|
float3 rotatedPos = startPos;
|
|
|
|
rotatedRayDir.xz = mul(rayDir.xz, rotationMatrix);
|
|
rotatedPos.xz = mul(startPos.xz, rotationMatrix);
|
|
|
|
float3 m = 1.0 / rotatedRayDir;
|
|
float3 n = m * rotatedPos;
|
|
float3 k = abs(m) * boxSize;
|
|
|
|
float3 t1 = -n - k;
|
|
float3 t2 = -n + k;
|
|
|
|
return float2(max(max(t1.x, t1.y), t1.z),
|
|
min(min(t2.x, t2.y), t2.z));
|
|
}
|
|
|
|
|
|
inline float3 KWS_SDF_IntersectionBoxWithSDF(float3 pos, float3 rayDir, float3x3 rotationMatrix, float3 size)
|
|
{
|
|
float3 rotatedRayDir = mul(rotationMatrix, rayDir).xyz;
|
|
float3 rotatedPos = mul(rotationMatrix, pos).xyz;
|
|
|
|
float3 m = 1.0 / rotatedRayDir;
|
|
float3 n = m * rotatedPos;
|
|
float3 k = abs(m) * size;
|
|
|
|
float3 t1 = -n - k;
|
|
float3 t2 = -n + k;
|
|
|
|
float sdf = KWS_SDF_Box(rotatedPos, size);
|
|
|
|
return float3(max(max(t1.x, t1.y), t1.z),
|
|
min(min(t2.x, t2.y), t2.z),
|
|
sdf);
|
|
}
|
|
|
|
//float KWS_SDF_BoxFade(float3 worldPos, float3 boxCenter, float3x3 boxRotation, float3 boxHalfSize, float fadePercent) // 0.0 - ~0.5)
|
|
|
|
//{
|
|
// float3 localPos = mul(boxRotation, worldPos);
|
|
|
|
// float3 distToEdge = boxHalfSize - abs(localPos);
|
|
// float dist = min(min(distToEdge.x, distToEdge.y), distToEdge.z);
|
|
// float fade = smoothstep(0.0, boxHalfSize.x * fadePercent, dist);
|
|
// return length(distToEdge) / boxHalfSize;
|
|
//}
|
|
|
|
float2 KWS_SDF_Intersection(float2 a, float2 b, out int r)
|
|
{
|
|
if (a.x < b.x)
|
|
{
|
|
if (a.y < b.x) return float2(100000, -100000);
|
|
if (a.y < b.y)
|
|
{
|
|
r = 1; return float2(b.x, a.y);
|
|
}
|
|
{
|
|
r = 1; return b;
|
|
}
|
|
}
|
|
else if (a.x < b.y)
|
|
{
|
|
if (a.y < b.y)
|
|
{
|
|
r = 0; return a;
|
|
}
|
|
{
|
|
r = 0; return float2(a.x, b.y);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return float2(100000, -100000);
|
|
}
|
|
}
|
|
|
|
float KWS_SDF_SphereDensity(float3 ro, float3 rd, float3 sc, float sr, float dbuffer)
|
|
{
|
|
// normalize the problem to the canonical sphere
|
|
float ndbuffer = dbuffer / sr;
|
|
float3 rc = (ro - sc)/sr;
|
|
|
|
// find intersection with sphere
|
|
float b = dot(rd,rc);
|
|
float c = dot(rc,rc) - 1.0;
|
|
float h = b*b - c;
|
|
|
|
// not intersecting
|
|
if( h<0.0 ) return 0.0;
|
|
|
|
h = sqrt( h );
|
|
|
|
//return h*h*h;
|
|
|
|
float t1 = -b - h;
|
|
float t2 = -b + h;
|
|
|
|
// not visible (behind camera or behind ndbuffer)
|
|
if( t2<0.0 || t1>ndbuffer ) return 0.0;
|
|
|
|
// clip integration segment from camera to ndbuffer
|
|
t1 = max( t1, 0.0 );
|
|
//t2 = min( t2, ndbuffer );
|
|
|
|
// analytical integration of an inverse squared density
|
|
float i1 = -(c*t1 + b*t1*t1 + t1*t1*t1/3.0);
|
|
float i2 = -(c*t2 + b*t2*t2 + t2*t2*t2/3.0);
|
|
return (i2-i1)*(3.0/4.0);
|
|
}
|
|
|
|
|
|
float KWS_SDF_SphereDensity(float3 ro, float3 rd, float3 sc, float sr, float dbuffer, out float tEntry)
|
|
{
|
|
float ndbuffer = dbuffer / sr;
|
|
float3 rc = (ro - sc) / sr;
|
|
|
|
float b = dot(rd, rc);
|
|
float c = dot(rc, rc) - 1.0;
|
|
float h = b * b - c;
|
|
|
|
if (h < 0.0)
|
|
{
|
|
tEntry = 0.0;
|
|
return 0.0;
|
|
}
|
|
|
|
h = sqrt(h);
|
|
float t1 = -b - h;
|
|
float t2 = -b + h;
|
|
|
|
if (t2 < 0.0 || t1 > ndbuffer)
|
|
{
|
|
tEntry = 0.0;
|
|
return 0.0;
|
|
}
|
|
|
|
t1 = max(t1, 0.0);
|
|
//t2 = min(t2, ndbuffer);
|
|
|
|
float i1 = -(c * t1 + b * t1 * t1 + t1 * t1 * t1 / 3.0);
|
|
float i2 = -(c * t2 + b * t2 * t2 + t2 * t2 * t2 / 3.0);
|
|
float integral = (i2 - i1) * (3.0 / 4.0);
|
|
|
|
tEntry = t1 * sr;
|
|
|
|
return integral / (t2 - t1);
|
|
}
|
|
|
|
inline float KWS_SDF_OrientedEllipsoidXZ_Density(float3 ro, float3 rd, float3 center, float3 scale, float2x2 rotationXZ, float dbuffer, out float tEntry)
|
|
{
|
|
float3 rc = ro - center;
|
|
|
|
float2 rcXZ = mul(rc.xz, rotationXZ) / scale.xz;
|
|
float2 rdXZ = mul(rd.xz, rotationXZ) / scale.xz;
|
|
|
|
float rcY = rc.y / scale.y;
|
|
float rdY = rd.y / scale.y;
|
|
|
|
float3 rc_local = float3(rcXZ.x, rcY, rcXZ.y);
|
|
float3 rd_local = float3(rdXZ.x, rdY, rdXZ.y);
|
|
|
|
rd_local = normalize(rd_local);
|
|
float lenCorrection = 1.0;
|
|
float ndbuffer = dbuffer;
|
|
|
|
float b = dot(rd_local, rc_local);
|
|
float c = dot(rc_local, rc_local) - 1.0;
|
|
float h = b * b - c;
|
|
|
|
if (h < 0.0)
|
|
{
|
|
tEntry = 0.0;
|
|
return 0.0;
|
|
}
|
|
|
|
h = sqrt(h);
|
|
float t1 = -b - h;
|
|
float t2 = -b + h;
|
|
|
|
if (t2 < 0.0 || t1 > ndbuffer)
|
|
{
|
|
tEntry = 0.0;
|
|
return 0.0;
|
|
}
|
|
|
|
t1 = max(t1, 0.0);
|
|
|
|
float i1 = -(c * t1 + b * t1 * t1 + t1 * t1 * t1 / 3.0);
|
|
float i2 = -(c * t2 + b * t2 * t2 + t2 * t2 * t2 / 3.0);
|
|
float integral = (i2 - i1) * (3.0 / 4.0);
|
|
|
|
tEntry = t1 / lenCorrection;
|
|
return integral / (t2 - t1);
|
|
}
|
|
|
|
float KWS_SDF_BoxDensity(float3 ro, float3 rd, float3 boxCenter, float3 boxHalfSize, float dbuffer)
|
|
{
|
|
// transform ray into box local space
|
|
float3 localRo = ro - boxCenter;
|
|
|
|
float3 tMin = (-boxHalfSize - localRo) / rd;
|
|
float3 tMax = (+boxHalfSize - localRo) / rd;
|
|
|
|
float3 t1 = min(tMin, tMax);
|
|
float3 t2 = max(tMin, tMax);
|
|
|
|
float tNear = max(max(t1.x, t1.y), t1.z);
|
|
float tFar = min(min(t2.x, t2.y), t2.z);
|
|
|
|
if (tFar < 0.0 || tNear > tFar) return 0.0;
|
|
|
|
// clip integration to depth buffer
|
|
tNear = max(tNear, 0.0);
|
|
//tFar = min(tFar, dbuffer);
|
|
|
|
if (tNear >= tFar) return 0.0;
|
|
|
|
float3 p1 = ro + rd * tNear;
|
|
float3 p2 = ro + rd * tFar;
|
|
|
|
float3 mid = (p1 + p2) * 0.5;
|
|
float3 localMid = abs(mid - boxCenter) / boxHalfSize;
|
|
|
|
// density falloff from center to edges (simple radial box falloff)
|
|
float falloff = 1.0 - saturate(max(max(localMid.x, localMid.y), localMid.z));
|
|
|
|
float visibleLength = length(p2 - p1);
|
|
float maxLength = length(boxHalfSize) * 2.0;
|
|
|
|
return falloff * (visibleLength / maxLength);
|
|
}
|
|
|
|
float KWS_SDF_BoxDensity(float3 ro, float3 rd, float3 boxCenter, float3 boxHalfSize, float dbuffer, float2x2 rotationMatrixXZ, int falloffType, float falloffSharpness)
|
|
{
|
|
// Apply XZ rotation to ray origin and direction
|
|
float2 roXZ = mul((ro.xz - boxCenter.xz), rotationMatrixXZ);
|
|
float2 rdXZ = mul(rd.xz, rotationMatrixXZ);
|
|
float3 localRo = float3(roXZ.x, ro.y - boxCenter.y, roXZ.y);
|
|
float3 localRd = float3(rdXZ.x, rd.y, rdXZ.y);
|
|
|
|
float3 tMin = (-boxHalfSize - localRo) / localRd;
|
|
float3 tMax = (+boxHalfSize - localRo) / localRd;
|
|
|
|
float3 t1 = min(tMin, tMax);
|
|
float3 t2 = max(tMin, tMax);
|
|
|
|
float tNear = max(max(t1.x, t1.y), t1.z);
|
|
float tFar = min(min(t2.x, t2.y), t2.z);
|
|
|
|
if (tFar < 0.0 || tNear > tFar) return 0.0;
|
|
|
|
// clip to scene depth
|
|
tNear = max(tNear, 0.0);
|
|
//tFar = min(tFar, dbuffer);
|
|
|
|
if (tNear >= tFar) return 0.0;
|
|
|
|
float3 p1 = ro + rd * tNear;
|
|
float3 p2 = ro + rd * tFar;
|
|
float3 mid = (p1 + p2) * 0.5;
|
|
|
|
// Compute local space distance to box center (with rotation applied)
|
|
float2 midXZ = mul((mid.xz - boxCenter.xz), rotationMatrixXZ);
|
|
float3 localMid = float3(midXZ.x, mid.y - boxCenter.y, midXZ.y);
|
|
float3 normPos = abs(localMid / boxHalfSize); // ∈ [0..1]
|
|
|
|
float d = max(max(normPos.x, normPos.y), normPos.z); // radial-like
|
|
|
|
float falloff = 0.0;
|
|
|
|
// Choose falloff function
|
|
if (falloffType == 0) falloff = 1.0 - d; // linear
|
|
else if (falloffType == 1) falloff = exp(-d * d * falloffSharpness); // exponential
|
|
else if (falloffType == 2) falloff = pow(1.0 - d, falloffSharpness); // power
|
|
else if (falloffType == 3) falloff = smoothstep(1.0, 0.0, d); // smooth
|
|
|
|
falloff = saturate(falloff);
|
|
|
|
float visibleLength = length(p2 - p1);
|
|
float maxLength = length(boxHalfSize) * 2.0;
|
|
|
|
return falloff * (visibleLength / maxLength);
|
|
}
|
|
|
|
|
|
|
|
// end filtering
|
|
|
|
|
|
|
|
|
|
/// packing
|
|
|
|
float Pack_R16G16_UNorm(float2 rg)
|
|
{
|
|
rg = 65534.0 * saturate(rg);
|
|
uint packedValue = uint(round(rg.x)) + 65535u * uint(round(rg.y));
|
|
return asfloat(packedValue);
|
|
}
|
|
|
|
float2 Unpack_R16G16_UNorm(float packedValue)
|
|
{
|
|
uint val = asuint(packedValue);
|
|
float2 x = float2(val % 65535u, val / 65535u);
|
|
return x / 65534.0;
|
|
}
|
|
|
|
|
|
uint Pack_R11G11B10f(float3 rgb)
|
|
{
|
|
uint r = (f32tof16(rgb.x) << 17) & 0xFFE00000;
|
|
uint g = (f32tof16(rgb.y) << 6) & 0x001FFC00;
|
|
uint b = (f32tof16(rgb.z) >> 5) & 0x000003FF;
|
|
return r | g | b;
|
|
}
|
|
|
|
float3 Unpack_R11G11B10f(uint rgb)
|
|
{
|
|
float r = f16tof32((rgb >> 17) & 0x7FF0);
|
|
float g = f16tof32((rgb >> 6) & 0x7FF0);
|
|
float b = f16tof32((rgb << 5) & 0x7FE0);
|
|
return float3(r, g, b);
|
|
}
|
|
|
|
|
|
/// end packing
|
|
|
|
|
|
|
|
#endif |