more shaders and updates/changes
This commit is contained in:
121
shaders/video-plane-3d/shader.json
Normal file
121
shaders/video-plane-3d/shader.json
Normal file
@@ -0,0 +1,121 @@
|
||||
{
|
||||
"id": "video-plane-3d",
|
||||
"name": "Video Plane 3D",
|
||||
"description": "Places the video on a perspective 2D plane in 3D space with camera FOV, XYZ position, and pan/tilt/roll controls.",
|
||||
"category": "Projection",
|
||||
"entryPoint": "shadeVideo",
|
||||
"parameters": [
|
||||
{
|
||||
"id": "fovDegrees",
|
||||
"label": "FOV",
|
||||
"type": "float",
|
||||
"default": 45,
|
||||
"min": 5,
|
||||
"max": 150,
|
||||
"step": 0.1,
|
||||
"description": "Virtual camera vertical field of view in degrees."
|
||||
},
|
||||
{
|
||||
"id": "positionX",
|
||||
"label": "X",
|
||||
"type": "float",
|
||||
"default": 0,
|
||||
"min": -4,
|
||||
"max": 4,
|
||||
"step": 0.01,
|
||||
"description": "Horizontal plane position in world units."
|
||||
},
|
||||
{
|
||||
"id": "positionY",
|
||||
"label": "Y",
|
||||
"type": "float",
|
||||
"default": 0,
|
||||
"min": -4,
|
||||
"max": 4,
|
||||
"step": 0.01,
|
||||
"description": "Vertical plane position in world units."
|
||||
},
|
||||
{
|
||||
"id": "positionZ",
|
||||
"label": "Z",
|
||||
"type": "float",
|
||||
"default": 2.2,
|
||||
"min": 0.1,
|
||||
"max": 10,
|
||||
"step": 0.01,
|
||||
"description": "Depth of the plane in front of the virtual camera."
|
||||
},
|
||||
{
|
||||
"id": "panDegrees",
|
||||
"label": "Pan",
|
||||
"type": "float",
|
||||
"default": 0,
|
||||
"min": -180,
|
||||
"max": 180,
|
||||
"step": 0.1,
|
||||
"description": "Rotates the plane left/right around its vertical axis."
|
||||
},
|
||||
{
|
||||
"id": "tiltDegrees",
|
||||
"label": "Tilt",
|
||||
"type": "float",
|
||||
"default": 0,
|
||||
"min": -120,
|
||||
"max": 120,
|
||||
"step": 0.1,
|
||||
"description": "Rotates the plane up/down around its horizontal axis."
|
||||
},
|
||||
{
|
||||
"id": "rollDegrees",
|
||||
"label": "Roll",
|
||||
"type": "float",
|
||||
"default": 0,
|
||||
"min": -180,
|
||||
"max": 180,
|
||||
"step": 0.1,
|
||||
"description": "Rotates the plane around its face normal."
|
||||
},
|
||||
{
|
||||
"id": "planeScale",
|
||||
"label": "Plane Scale",
|
||||
"type": "float",
|
||||
"default": 1.4,
|
||||
"min": 0.05,
|
||||
"max": 6,
|
||||
"step": 0.01,
|
||||
"description": "Height of the video plane in world units; width follows the source aspect ratio."
|
||||
},
|
||||
{
|
||||
"id": "edgeFeather",
|
||||
"label": "Edge Feather",
|
||||
"type": "float",
|
||||
"default": 1.5,
|
||||
"min": 0,
|
||||
"max": 24,
|
||||
"step": 0.1,
|
||||
"description": "Softens the plane edge in source pixels."
|
||||
},
|
||||
{
|
||||
"id": "backgroundMix",
|
||||
"label": "Background Mix",
|
||||
"type": "float",
|
||||
"default": 0,
|
||||
"min": 0,
|
||||
"max": 1,
|
||||
"step": 0.01,
|
||||
"description": "Mixes the original video behind the projected plane."
|
||||
},
|
||||
{
|
||||
"id": "outsideColor",
|
||||
"label": "Outside Color",
|
||||
"type": "color",
|
||||
"default": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1
|
||||
],
|
||||
"description": "Color used where the camera ray misses the plane."
|
||||
}
|
||||
]
|
||||
}
|
||||
84
shaders/video-plane-3d/shader.slang
Normal file
84
shaders/video-plane-3d/shader.slang
Normal file
@@ -0,0 +1,84 @@
|
||||
static const float PI = 3.14159265358979323846;
|
||||
|
||||
float radiansFromDegrees(float degrees)
|
||||
{
|
||||
return degrees * (PI / 180.0);
|
||||
}
|
||||
|
||||
float3 rotateX(float3 p, float angle)
|
||||
{
|
||||
float s = sin(angle);
|
||||
float c = cos(angle);
|
||||
return float3(p.x, c * p.y - s * p.z, s * p.y + c * p.z);
|
||||
}
|
||||
|
||||
float3 rotateY(float3 p, float angle)
|
||||
{
|
||||
float s = sin(angle);
|
||||
float c = cos(angle);
|
||||
return float3(c * p.x + s * p.z, p.y, -s * p.x + c * p.z);
|
||||
}
|
||||
|
||||
float3 rotateZ(float3 p, float angle)
|
||||
{
|
||||
float s = sin(angle);
|
||||
float c = cos(angle);
|
||||
return float3(c * p.x - s * p.y, s * p.x + c * p.y, p.z);
|
||||
}
|
||||
|
||||
float3 rotateWorldToPlane(float3 value)
|
||||
{
|
||||
float pan = radiansFromDegrees(panDegrees);
|
||||
float tilt = radiansFromDegrees(tiltDegrees);
|
||||
float roll = radiansFromDegrees(rollDegrees);
|
||||
return rotateZ(rotateX(rotateY(value, -pan), -tilt), -roll);
|
||||
}
|
||||
|
||||
float planeEdgeMask(float2 uv, float2 inputResolution)
|
||||
{
|
||||
float2 feather = max(edgeFeather, 0.0) / max(inputResolution, float2(1.0, 1.0));
|
||||
feather = max(feather, float2(0.00001, 0.00001));
|
||||
|
||||
float left = smoothstep(0.0, feather.x, uv.x);
|
||||
float right = 1.0 - smoothstep(1.0 - feather.x, 1.0, uv.x);
|
||||
float top = smoothstep(0.0, feather.y, uv.y);
|
||||
float bottom = 1.0 - smoothstep(1.0 - feather.y, 1.0, uv.y);
|
||||
return saturate(left * right * top * bottom);
|
||||
}
|
||||
|
||||
float4 shadeVideo(ShaderContext context)
|
||||
{
|
||||
float2 outputResolution = max(context.outputResolution, float2(1.0, 1.0));
|
||||
float outputAspect = outputResolution.x / outputResolution.y;
|
||||
float sourceAspect = context.inputResolution.x / max(context.inputResolution.y, 1.0);
|
||||
float tanHalfFov = tan(radiansFromDegrees(clamp(fovDegrees, 5.0, 150.0)) * 0.5);
|
||||
|
||||
float2 screen = float2(context.uv.x * 2.0 - 1.0, 1.0 - context.uv.y * 2.0);
|
||||
float3 rayOrigin = float3(0.0, 0.0, 0.0);
|
||||
float3 rayDirection = normalize(float3(screen.x * outputAspect * tanHalfFov, screen.y * tanHalfFov, 1.0));
|
||||
|
||||
float3 planePosition = float3(positionX, positionY, max(positionZ, 0.001));
|
||||
float3 localOrigin = rotateWorldToPlane(rayOrigin - planePosition);
|
||||
float3 localDirection = rotateWorldToPlane(rayDirection);
|
||||
|
||||
float backgroundAmount = saturate(backgroundMix);
|
||||
float4 background = float4(lerp(outsideColor.rgb, context.sourceColor.rgb, backgroundAmount), 1.0);
|
||||
if (abs(localDirection.z) < 0.00001)
|
||||
return background;
|
||||
|
||||
float hitDistance = -localOrigin.z / localDirection.z;
|
||||
if (hitDistance <= 0.0)
|
||||
return background;
|
||||
|
||||
float3 localHit = localOrigin + localDirection * hitDistance;
|
||||
float halfHeight = max(planeScale, 0.001) * 0.5;
|
||||
float halfWidth = halfHeight * sourceAspect;
|
||||
float2 planeUv = float2(
|
||||
localHit.x / max(halfWidth * 2.0, 0.0001) + 0.5,
|
||||
0.5 - localHit.y / max(halfHeight * 2.0, 0.0001)
|
||||
);
|
||||
|
||||
float mask = planeEdgeMask(planeUv, max(context.inputResolution, float2(1.0, 1.0)));
|
||||
float4 planeColor = sampleVideo(clamp(planeUv, 0.0, 1.0));
|
||||
return saturate(lerp(background, planeColor, mask));
|
||||
}
|
||||
Reference in New Issue
Block a user