fix: Fog masking
This commit is contained in:
@@ -220,80 +220,6 @@ float WorldDistort(float3 PositionWS, float3 NormalWS, float Angle, float Tripla
|
||||
return stripes;
|
||||
}
|
||||
|
||||
|
||||
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 EnkiBillal_float
|
||||
(
|
||||
float4 Color,
|
||||
@@ -308,12 +234,7 @@ void EnkiBillal_float
|
||||
float StripesWidth,
|
||||
float StripesSmooth,
|
||||
int Step,
|
||||
float MaskID,
|
||||
float4x4 Mask0,
|
||||
float4x4 Mask1,
|
||||
float4x4 Mask2,
|
||||
out float3 Output,
|
||||
out float Alpha
|
||||
out float3 Output
|
||||
)
|
||||
{
|
||||
float3 scaledPositionOS = PositionOS * ObjectScale;
|
||||
@@ -384,38 +305,6 @@ void EnkiBillal_float
|
||||
|
||||
//Output = PerlinColor3D(PositionWS, 5);
|
||||
//Output = smoothstep(.97, .93, ao);
|
||||
|
||||
// Mask
|
||||
|
||||
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
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
#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
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2f64e213049952b44ac4bed6f62cafda
|
||||
ShaderIncludeImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user