Files
Ipseity-Demo/Assets/_Content/Shaders/EnkiBillal/Include/Mask.hlsl
T
2026-05-29 15:24:31 +02:00

121 lines
3.2 KiB
HLSL

#ifndef MASK_INCLUDED
#define MASK_INCLUDED
float ProjectionMask(
float3 PositionWS,
float3 CamPositionWS,
float3 RectPositionWS,
float3 RectNormalWS,
float3 RectUpWS,
float2 RectSize,
float Oval)
{
// Build the rectangle local frame
float3 N = normalize(RectNormalWS);
float3 U = normalize(RectUpWS);
float3 R = normalize(cross(N, U)); // Right axis
U = normalize(cross(R, N)); // Recompute Up orthogonally in case RectUpWS is not perfectly perpendicular to RectNormalWS
// Ray from camera toward the fragment
float3 rayDir = normalize(PositionWS - CamPositionWS);
// Ray-plane intersection
// Plane equation: dot(P - RectPositionWS, N) = 0
float denom = dot(rayDir, N);
// Ray is parallel to the plane or facing away — no hit
if (abs(denom) < 1e-6)
return 0;
float t = dot(RectPositionWS - CamPositionWS, N) / denom;
// Intersection must be in front of the camera (t > 0)
// and not beyond the fragment (t <= distance from camera to fragment)
float tFrag = dot(PositionWS - CamPositionWS, rayDir);
if (t < 0.0 || t > tFrag + 1e-4)
return 0;
// Compute the hit point on the plane
float3 hitPoint = CamPositionWS + rayDir * t;
// Project hit point into the rectangle local space
float3 localVec = hitPoint - RectPositionWS;
float localU = dot(localVec, R); // horizontal axis
float localV = dot(localVec, U); // vertical axis
float halfW = RectSize.x * 0.5;
float halfH = RectSize.y * 0.5;
// Corner radius: 0 = rectangle, min(halfW, halfH) = oval
float radius = saturate(Oval) * min(halfW, halfH);
// Rounded rectangle SDF
float2 uv = float2(localU, localV);
float2 ext = float2(halfW, halfH);
float2 q = abs(uv) - ext + radius;
float sdf = length(max(q, 0.0)) - radius;
return sdf <= 0.0 ? 1.0 : 0.0;
}
float SampleProjectionMask(float3 PositionWS, float4x4 M)
{
if (M[0].w == 0)
return 0;
return ProjectionMask(
PositionWS,
M[0].xyz, // CamPositionWS
M[1].xyz, // RectPositionWS
M[3].xyz, // RectNormalWS
M[2].xyz, // RectUpWS
float2(M[2].w, M[3].w), // RectSize
M[1].w // Shape
);
}
void Mask_float
(
float3 PositionWS,
float MaskID,
float4x4 Mask0,
float4x4 Mask1,
float4x4 Mask2,
out float Alpha
)
{
Alpha = 1;
if (Mask2[0].w == 1)
{
float mask = SampleProjectionMask(PositionWS, Mask2);
Alpha = (MaskID <= 1) ? 1 - mask : mask;
}
else if (MaskID == 0)
{
Alpha = 1;
}
else
{
float Active = Mask0[0].w + Mask1[0].w; // + Mask2[0].w;
if (Active > 0)
{
float mask = saturate(
SampleProjectionMask(PositionWS, Mask0) +
SampleProjectionMask(PositionWS, Mask1) // +
//SampleProjectionMask(PositionWS, Mask2)
);
Alpha = (MaskID == 1) ? 1 - mask : mask;
}
else
{
Alpha = (MaskID == 1) ? 0 : 1;
}
}
}
#endif