#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