opti : shaders rework test

This commit is contained in:
2026-07-07 19:49:54 +02:00
parent a5b7c571eb
commit 06da5b858a
31 changed files with 1813 additions and 361 deletions
@@ -1,6 +1,27 @@
#ifndef MASK_INCLUDED
#define MASK_INCLUDED
/*
MASK - MEDIUM COMPATIBLE VERSION
Goal:
Keep the original portal / projection behavior while avoiding unnecessary work
in cases where the mask is not supposed to affect the object.
Important compatibility point:
In the original shader, when all three masks are active, MaskID 0 is affected:
Alpha = (MaskID <= 1) ? 1 - mask : mask;
The previous Medium version incorrectly skipped MaskID 0 entirely.
That could break portal logic.
Changes from the original version:
- Preserves the original Alpha logic.
- Keeps rounded rectangle SDF to avoid changing portal shape.
- Adds safer early returns only when they do not change original behavior.
- Samples only active masks outside the "all three active" special case.
*/
float ProjectionMask(
float3 PositionWS,
float3 CamPositionWS,
@@ -8,51 +29,78 @@ float ProjectionMask(
float3 RectNormalWS,
float3 RectUpWS,
float2 RectSize,
float Oval)
float Oval
)
{
// Build the rectangle local frame
/*
Build the local projection 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
float3 R = normalize(cross(N, U));
// Ray from camera toward the fragment
float3 rayDir = normalize(PositionWS - CamPositionWS);
/*
Recompute U to guarantee an orthogonal frame.
*/
U = normalize(cross(R, N));
// Ray-plane intersection
// Plane equation: dot(P - RectPositionWS, N) = 0
/*
Ray from camera to fragment.
*/
float3 camToFrag = PositionWS - CamPositionWS;
float distToFrag = length(camToFrag);
if (distToFrag <= 1e-5)
return 0.0;
float3 rayDir = camToFrag / distToFrag;
/*
Ray-plane intersection.
*/
float denom = dot(rayDir, N);
// Ray is parallel to the plane or facing away — no hit
if (abs(denom) < 1e-6)
return 0;
return 0.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;
/*
Reject intersections behind the camera or behind the current fragment.
*/
if (t < 0.0 || t > distToFrag + 1e-4)
return 0.0;
// Compute the hit point on the plane
/*
Compute hit point on the projection plane.
*/
float3 hitPoint = CamPositionWS + rayDir * t;
// Project hit point into the rectangle local space
/*
Convert hit point to rectangle local coordinates.
*/
float3 localVec = hitPoint - RectPositionWS;
float localU = dot(localVec, R); // horizontal axis
float localV = dot(localVec, U); // vertical axis
float localU = dot(localVec, R);
float localV = dot(localVec, U);
float halfW = RectSize.x * 0.5;
float halfH = RectSize.y * 0.5;
// Corner radius: 0 = rectangle, min(halfW, halfH) = oval
if (halfW <= 1e-5 || halfH <= 1e-5)
return 0.0;
/*
Original rounded rectangle SDF preserved.
The previous Medium version replaced this with a hard rectangle / ellipse.
That was cheaper, but it could change the portal shape.
*/
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;
@@ -60,17 +108,20 @@ float ProjectionMask(
float SampleProjectionMask(float3 PositionWS, float4x4 M)
{
if (M[0].w == 0)
return 0;
/*
M[0].w is used as the active flag.
*/
if (M[0].w <= 0.5)
return 0.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
M[0].xyz, // Camera world position
M[1].xyz, // Rectangle world position
M[3].xyz, // Rectangle normal in world space
M[2].xyz, // Rectangle up vector in world space
float2(M[2].w, M[3].w), // Rectangle size
M[1].w // Rounded shape amount
);
}
@@ -84,40 +135,82 @@ void Mask_float
out float Alpha
)
{
Alpha = 1;
if (Mask0[0].w == 1 && Mask1[0].w == 1 && Mask2[0].w == 1)
float active0 = Mask0[0].w > 0.5 ? 1.0 : 0.0;
float active1 = Mask1[0].w > 0.5 ? 1.0 : 0.0;
float active2 = Mask2[0].w > 0.5 ? 1.0 : 0.0;
float activeCount = active0 + active1 + active2;
/*
No active mask case.
Preserves original behavior:
- MaskID 1 is hidden.
- Other IDs remain visible.
*/
if (activeCount <= 0.0)
{
float mask = SampleProjectionMask(PositionWS, Mask0);
Alpha = (MaskID == 1) ? 0.0 : 1.0;
return;
}
/*
Original special case:
when all three masks are active, MaskID 0 is also affected by the mask.
This is probably what your portal depends on.
*/
if (active0 > 0.5 && active1 > 0.5 && active2 > 0.5)
{
float mask = 0.0;
mask += SampleProjectionMask(PositionWS, Mask0);
mask += SampleProjectionMask(PositionWS, Mask1);
mask += SampleProjectionMask(PositionWS, Mask2);
mask = saturate(mask);
Alpha = (MaskID <= 1) ? 1 - mask : mask;
Alpha = (MaskID <= 1.0) ? (1.0 - mask) : mask;
return;
}
else if (MaskID == 0)
/*
Safe optimization:
In the original shader, when not all three masks are active,
MaskID 0 is always fully visible.
So only here it is safe to skip all projection work for MaskID 0.
*/
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;
}
Alpha = 1.0;
return;
}
/*
Partial active mask case.
Only sample masks that are active.
*/
float maskPartial = 0.0;
if (active0 > 0.5)
maskPartial += SampleProjectionMask(PositionWS, Mask0);
if (active1 > 0.5)
maskPartial += SampleProjectionMask(PositionWS, Mask1);
if (active2 > 0.5)
maskPartial += SampleProjectionMask(PositionWS, Mask2);
maskPartial = saturate(maskPartial);
/*
Original convention preserved:
- MaskID 1 is visible outside the mask.
- MaskID > 1 is visible inside the mask.
*/
Alpha = (MaskID == 1.0) ? (1.0 - maskPartial) : maskPartial;
}
#endif
#endif