Updated shader and fixed PNG output
All checks were successful
CI / React UI Build (push) Successful in 10s
CI / Native Windows Build And Tests (push) Successful in 2m15s
CI / Windows Release Package (push) Successful in 2m10s

This commit is contained in:
2026-05-08 15:52:58 +10:00
parent 05d0bcbedd
commit 0831e18c2d
4 changed files with 69 additions and 22 deletions

View File

@@ -1,7 +1,7 @@
{
"id": "fisheye-equirectangular-mirror",
"name": "Fisheye Equirectangular Mirror",
"description": "Unwraps a single fisheye lens into a 360x180 equirectangular map by mirroring the rear hemisphere into the same fisheye source.",
"description": "Unwraps a single width-filled 16:9 fisheye lens into a 360x180 equirectangular map by mirroring the rear hemisphere into the same fisheye source.",
"category": "Projection",
"entryPoint": "shadeVideo",
"parameters": [
@@ -9,7 +9,7 @@
"id": "lensFovDegrees",
"label": "Lens FOV",
"type": "float",
"default": 180.0,
"default": 190.0,
"min": 1.0,
"max": 220.0,
"step": 0.1
@@ -27,7 +27,7 @@
"id": "radius",
"label": "Fisheye Radius",
"type": "vec2",
"default": [0.5, 0.5],
"default": [0.5, 0.8889],
"min": [0.001, 0.001],
"max": [2.0, 2.0],
"step": [0.001, 0.001]
@@ -59,15 +59,6 @@
"max": 180.0,
"step": 0.1
},
{
"id": "seamAngleDegrees",
"label": "Seam Angle",
"type": "float",
"default": 0.0,
"min": -180.0,
"max": 180.0,
"step": 0.1
},
{
"id": "fisheyeModel",
"label": "Fisheye Model",
@@ -80,6 +71,24 @@
{ "value": "orthographic", "label": "Orthographic" }
]
},
{
"id": "edgeFill",
"label": "Edge Fill",
"type": "float",
"default": 0.06,
"min": 0.0,
"max": 0.3,
"step": 0.001
},
{
"id": "edgeBlur",
"label": "Edge Blur",
"type": "float",
"default": 0.018,
"min": 0.0,
"max": 0.12,
"step": 0.001
},
{
"id": "outsideColor",
"label": "Outside Color",

View File

@@ -49,7 +49,7 @@ float normalizedFisheyeRadius(float theta, float halfFov)
float3 equirectangularRay(float2 uv)
{
float longitude = (uv.x - 0.5) * TWO_PI + radiansFromDegrees(seamAngleDegrees);
float longitude = (uv.x - 0.5) * TWO_PI;
float latitude = (0.5 - uv.y) * PI;
float latitudeCos = cos(latitude);
@@ -60,6 +60,39 @@ float3 equirectangularRay(float2 uv)
));
}
float sourceUvOutsideDistance(float2 uv)
{
float2 lower = max(-uv, float2(0.0, 0.0));
float2 upper = max(uv - 1.0, float2(0.0, 0.0));
return max(max(lower.x, lower.y), max(upper.x, upper.y));
}
float4 sampleEdgeFilledVideo(float2 sourceUv, ShaderContext context)
{
float outsideDistance = sourceUvOutsideDistance(sourceUv);
if (outsideDistance <= 0.0)
return sampleVideo(sourceUv);
float fillDistance = max(edgeFill, 0.0);
if (outsideDistance > fillDistance)
return outsideColor;
float2 clampedUv = saturate(sourceUv);
float2 inward = clampedUv - sourceUv;
float inwardLength = max(length(inward), 0.000001);
inward /= inwardLength;
float blurDistance = max(edgeBlur, 0.0);
float4 color = sampleVideo(clampedUv) * 0.32;
color += sampleVideo(saturate(clampedUv + inward * blurDistance * 0.35)) * 0.26;
color += sampleVideo(saturate(clampedUv + inward * blurDistance * 0.75)) * 0.20;
color += sampleVideo(saturate(clampedUv + inward * blurDistance * 1.20)) * 0.14;
color += sampleVideo(saturate(clampedUv + inward * blurDistance * 1.75)) * 0.08;
float edgeFade = smoothstep(fillDistance * 0.78, fillDistance, outsideDistance);
return lerp(color, outsideColor, edgeFade);
}
float4 shadeVideo(ShaderContext context)
{
float3 ray = equirectangularRay(context.uv);
@@ -86,8 +119,9 @@ float4 shadeVideo(ShaderContext context)
center.y - sin(phi) * fisheyeRadius * radius.y
);
if (sourceUv.x < 0.0 || sourceUv.x > 1.0 || sourceUv.y < 0.0 || sourceUv.y > 1.0)
float2 guard = 0.5 / max(context.inputResolution, float2(1.0, 1.0));
if (edgeFill <= 0.0 && (sourceUv.x < -guard.x || sourceUv.x > 1.0 + guard.x || sourceUv.y < -guard.y || sourceUv.y > 1.0 + guard.y))
return outsideColor;
return sampleVideo(sourceUv);
return sampleEdgeFilledVideo(sourceUv, context);
}