Additional shaders
This commit is contained in:
@@ -234,12 +234,11 @@ If your Windows runner stores the Blackmagic SDK outside the repo, configure `GP
|
|||||||
Audio
|
Audio
|
||||||
improve text rendering
|
improve text rendering
|
||||||
genlock
|
genlock
|
||||||
|
find a better UI libary
|
||||||
Logs
|
Logs
|
||||||
anamorphic desqueeze
|
anamorphic desqueeze
|
||||||
solid color layer
|
|
||||||
refactor, cleanup of source files
|
refactor, cleanup of source files
|
||||||
display URL (Maybe clicakable) for control in the windows app (Not on the output)
|
display URL (Maybe clicakable) for control in the windows app (Not on the output)
|
||||||
Sound shader as seperate .slang in shader package?
|
Sound shader as seperate .slang in shader package?
|
||||||
runtime date time UTC and offset from PCs internal clock
|
runtime date time UTC and offset from PCs internal clock
|
||||||
Add a value control to the color wheels
|
|
||||||

|

|
||||||
46
shaders/anamorphic-desqueeze/shader.json
Normal file
46
shaders/anamorphic-desqueeze/shader.json
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
"id": "anamorphic-desqueeze",
|
||||||
|
"name": "Anamorphic Desqueeze",
|
||||||
|
"description": "Desqueezes anamorphic footage by 1.3x, 1.33x, 1.5x, or 2x with fit or fill framing.",
|
||||||
|
"category": "Transform",
|
||||||
|
"entryPoint": "shadeVideo",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"id": "desqueezeFactor",
|
||||||
|
"label": "Desqueeze",
|
||||||
|
"type": "enum",
|
||||||
|
"default": "x1_33",
|
||||||
|
"options": [
|
||||||
|
{ "value": "x1_3", "label": "1.3x" },
|
||||||
|
{ "value": "x1_33", "label": "1.33x" },
|
||||||
|
{ "value": "x1_5", "label": "1.5x" },
|
||||||
|
{ "value": "x2_0", "label": "2x" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "framing",
|
||||||
|
"label": "Framing",
|
||||||
|
"type": "enum",
|
||||||
|
"default": "fit",
|
||||||
|
"options": [
|
||||||
|
{ "value": "fit", "label": "Fit" },
|
||||||
|
{ "value": "fill", "label": "Fill" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "pan",
|
||||||
|
"label": "Pan",
|
||||||
|
"type": "vec2",
|
||||||
|
"default": [0.0, 0.0],
|
||||||
|
"min": [-1.0, -1.0],
|
||||||
|
"max": [1.0, 1.0],
|
||||||
|
"step": [0.001, 0.001]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "outsideColor",
|
||||||
|
"label": "Outside Color",
|
||||||
|
"type": "color",
|
||||||
|
"default": [0.0, 0.0, 0.0, 1.0]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
32
shaders/anamorphic-desqueeze/shader.slang
Normal file
32
shaders/anamorphic-desqueeze/shader.slang
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
float selectedDesqueezeFactor()
|
||||||
|
{
|
||||||
|
if (desqueezeFactor == 0)
|
||||||
|
return 1.3;
|
||||||
|
if (desqueezeFactor == 1)
|
||||||
|
return 1.3333333;
|
||||||
|
if (desqueezeFactor == 2)
|
||||||
|
return 1.5;
|
||||||
|
return 2.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 shadeVideo(ShaderContext context)
|
||||||
|
{
|
||||||
|
float factor = selectedDesqueezeFactor();
|
||||||
|
float2 centered = context.uv - 0.5;
|
||||||
|
|
||||||
|
if (framing == 0)
|
||||||
|
{
|
||||||
|
centered.y *= factor;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
centered.x /= factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
float2 sourceUv = centered + 0.5 - pan;
|
||||||
|
bool inside = sourceUv.x >= 0.0 && sourceUv.x <= 1.0 && sourceUv.y >= 0.0 && sourceUv.y <= 1.0;
|
||||||
|
if (!inside)
|
||||||
|
return outsideColor;
|
||||||
|
|
||||||
|
return sampleVideo(sourceUv);
|
||||||
|
}
|
||||||
8
shaders/smpte-color-bars/shader.json
Normal file
8
shaders/smpte-color-bars/shader.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"id": "smpte-color-bars",
|
||||||
|
"name": "SMPTE Color Bars",
|
||||||
|
"description": "Generates a procedural SMPTE RP 219-style 16:9 color bar test pattern matching the common Wikimedia 1920x1080 reference layout.",
|
||||||
|
"category": "Calibration",
|
||||||
|
"entryPoint": "shadeVideo",
|
||||||
|
"parameters": []
|
||||||
|
}
|
||||||
90
shaders/smpte-color-bars/shader.slang
Normal file
90
shaders/smpte-color-bars/shader.slang
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
float3 hexColor(float r, float g, float b)
|
||||||
|
{
|
||||||
|
return float3(r, g, b) / 255.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 smpteTop(float x)
|
||||||
|
{
|
||||||
|
if (x < 240.0)
|
||||||
|
return hexColor(102.0, 102.0, 102.0);
|
||||||
|
if (x < 445.0)
|
||||||
|
return hexColor(191.0, 191.0, 191.0);
|
||||||
|
if (x < 651.0)
|
||||||
|
return hexColor(191.0, 191.0, 0.0);
|
||||||
|
if (x < 857.0)
|
||||||
|
return hexColor(0.0, 191.0, 191.0);
|
||||||
|
if (x < 1063.0)
|
||||||
|
return hexColor(0.0, 191.0, 0.0);
|
||||||
|
if (x < 1269.0)
|
||||||
|
return hexColor(191.0, 0.0, 191.0);
|
||||||
|
if (x < 1475.0)
|
||||||
|
return hexColor(191.0, 0.0, 0.0);
|
||||||
|
if (x < 1680.0)
|
||||||
|
return hexColor(0.0, 0.0, 191.0);
|
||||||
|
return hexColor(102.0, 102.0, 102.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 smpteMiddleA(float x)
|
||||||
|
{
|
||||||
|
if (x < 240.0)
|
||||||
|
return hexColor(0.0, 255.0, 255.0);
|
||||||
|
if (x < 445.0)
|
||||||
|
return hexColor(0.0, 63.0, 105.0);
|
||||||
|
if (x < 1680.0)
|
||||||
|
return hexColor(191.0, 191.0, 191.0);
|
||||||
|
return hexColor(0.0, 0.0, 255.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 smpteMiddleB(float x)
|
||||||
|
{
|
||||||
|
if (x < 240.0)
|
||||||
|
return hexColor(255.0, 255.0, 0.0);
|
||||||
|
if (x < 445.0)
|
||||||
|
return hexColor(65.0, 0.0, 119.0);
|
||||||
|
if (x < 1475.0)
|
||||||
|
{
|
||||||
|
float ramp = saturate((x - 445.0) / (1475.0 - 445.0));
|
||||||
|
return float3(ramp, ramp, ramp);
|
||||||
|
}
|
||||||
|
if (x < 1680.0)
|
||||||
|
return float3(1.0, 1.0, 1.0);
|
||||||
|
return hexColor(255.0, 0.0, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 smpteBottom(float x)
|
||||||
|
{
|
||||||
|
if (x < 240.0)
|
||||||
|
return hexColor(38.0, 38.0, 38.0);
|
||||||
|
if (x < 549.0)
|
||||||
|
return float3(0.0, 0.0, 0.0);
|
||||||
|
if (x < 960.0)
|
||||||
|
return float3(1.0, 1.0, 1.0);
|
||||||
|
if (x < 1268.0)
|
||||||
|
return float3(0.0, 0.0, 0.0);
|
||||||
|
if (x < 1337.0)
|
||||||
|
return hexColor(5.0, 5.0, 5.0);
|
||||||
|
if (x < 1405.0)
|
||||||
|
return float3(0.0, 0.0, 0.0);
|
||||||
|
if (x < 1474.0)
|
||||||
|
return hexColor(10.0, 10.0, 10.0);
|
||||||
|
if (x < 1680.0)
|
||||||
|
return float3(0.0, 0.0, 0.0);
|
||||||
|
return hexColor(38.0, 38.0, 38.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 shadeVideo(ShaderContext context)
|
||||||
|
{
|
||||||
|
float2 uv = saturate(context.uv);
|
||||||
|
float2 pixel = float2(uv.x, 1.0 - uv.y) * float2(1920.0, 1080.0);
|
||||||
|
|
||||||
|
if (pixel.y < 630.0)
|
||||||
|
return float4(smpteTop(pixel.x), 1.0);
|
||||||
|
|
||||||
|
if (pixel.y < 720.0)
|
||||||
|
return float4(smpteMiddleA(pixel.x), 1.0);
|
||||||
|
|
||||||
|
if (pixel.y < 810.0)
|
||||||
|
return float4(smpteMiddleB(pixel.x), 1.0);
|
||||||
|
|
||||||
|
return float4(smpteBottom(pixel.x), 1.0);
|
||||||
|
}
|
||||||
15
shaders/solid-color/shader.json
Normal file
15
shaders/solid-color/shader.json
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"id": "solid-color",
|
||||||
|
"name": "Solid Color",
|
||||||
|
"description": "Fills the frame with a single user-selected color.",
|
||||||
|
"category": "Color",
|
||||||
|
"entryPoint": "shadeVideo",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"id": "fillColor",
|
||||||
|
"label": "Fill",
|
||||||
|
"type": "color",
|
||||||
|
"default": [1.0, 1.0, 1.0, 1.0]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
4
shaders/solid-color/shader.slang
Normal file
4
shaders/solid-color/shader.slang
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
float4 shadeVideo(ShaderContext context)
|
||||||
|
{
|
||||||
|
return saturate(fillColor);
|
||||||
|
}
|
||||||
@@ -190,43 +190,70 @@ export function ParameterField({ layer, parameter, onParameterChange }) {
|
|||||||
while (values.length < 4) {
|
while (values.length < 4) {
|
||||||
values.push(values.length === 3 ? 1 : 0);
|
values.push(values.length === 3 ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
const hsva = colorValueToHsva(values);
|
||||||
|
const wheelHsva = { ...hsva, v: 100 };
|
||||||
|
const sendHsva = (nextHsva) => scheduleSendValue(hsvaToColorValue(nextHsva, values[3]));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="parameter">
|
<section className="parameter">
|
||||||
{header}
|
{header}
|
||||||
<div className="parameter__wheel-row">
|
<div className="parameter__wheel-row">
|
||||||
<div
|
<div className="parameter__color-stack">
|
||||||
className="parameter__wheel"
|
<div
|
||||||
onPointerDown={beginInteraction}
|
className="parameter__wheel"
|
||||||
onPointerUp={endInteraction}
|
onPointerDown={beginInteraction}
|
||||||
onPointerCancel={endInteraction}
|
onPointerUp={endInteraction}
|
||||||
onBlur={endInteraction}
|
onPointerCancel={endInteraction}
|
||||||
>
|
|
||||||
<Wheel
|
|
||||||
color={colorValueToHsva(values)}
|
|
||||||
width={132}
|
|
||||||
height={132}
|
|
||||||
onChange={(color) => scheduleSendValue(hsvaToColorValue(color.hsva, values[3]))}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<label className="parameter__alpha">
|
|
||||||
<span>Alpha</span>
|
|
||||||
<input
|
|
||||||
type="number"
|
|
||||||
min={parameter.min?.[3] ?? 0}
|
|
||||||
max={parameter.max?.[3] ?? 1}
|
|
||||||
step={parameter.step?.[3] ?? 0.01}
|
|
||||||
value={values[3]}
|
|
||||||
onFocus={beginInteraction}
|
|
||||||
onChange={(event) => {
|
|
||||||
const next = [...values];
|
|
||||||
next[3] = Number(event.target.value);
|
|
||||||
sendValue(next);
|
|
||||||
}}
|
|
||||||
onBlur={endInteraction}
|
onBlur={endInteraction}
|
||||||
/>
|
>
|
||||||
</label>
|
<Wheel
|
||||||
<div className="parameter__swatch" style={{ background: colorValueToHex(values) }} aria-hidden="true" />
|
color={wheelHsva}
|
||||||
|
width={196}
|
||||||
|
height={196}
|
||||||
|
onChange={(color) => sendHsva({ ...color.hsva, v: hsva.v })}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<label className="parameter__value-slider">
|
||||||
|
<input
|
||||||
|
type="range"
|
||||||
|
min={0}
|
||||||
|
max={100}
|
||||||
|
step={1}
|
||||||
|
value={Math.round(hsva.v)}
|
||||||
|
aria-label={`${parameter.label} value`}
|
||||||
|
onMouseDown={beginInteraction}
|
||||||
|
onPointerDown={beginInteraction}
|
||||||
|
onTouchStart={beginInteraction}
|
||||||
|
onChange={(event) => sendHsva({ ...hsva, v: Number(event.target.value) })}
|
||||||
|
onMouseUp={endInteraction}
|
||||||
|
onTouchEnd={endInteraction}
|
||||||
|
onPointerUp={endInteraction}
|
||||||
|
onKeyDown={beginInteraction}
|
||||||
|
onKeyUp={endInteraction}
|
||||||
|
onBlur={endInteraction}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div className="parameter__color-bottom">
|
||||||
|
<label className="parameter__alpha">
|
||||||
|
<span>Alpha</span>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
min={parameter.min?.[3] ?? 0}
|
||||||
|
max={parameter.max?.[3] ?? 1}
|
||||||
|
step={parameter.step?.[3] ?? 0.01}
|
||||||
|
value={values[3]}
|
||||||
|
onFocus={beginInteraction}
|
||||||
|
onChange={(event) => {
|
||||||
|
const next = [...values];
|
||||||
|
next[3] = Number(event.target.value);
|
||||||
|
sendValue(next);
|
||||||
|
}}
|
||||||
|
onBlur={endInteraction}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<div className="parameter__swatch" style={{ background: colorValueToHex(values) }} aria-hidden="true" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ParameterValueDisplay parameterType={parameter.type} value={appliedValue} pending={isPending} />
|
<ParameterValueDisplay parameterType={parameter.type} value={appliedValue} pending={isPending} />
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -858,14 +858,23 @@ pre {
|
|||||||
|
|
||||||
.parameter__wheel-row {
|
.parameter__wheel-row {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: auto minmax(5.25rem, 1fr);
|
grid-template-columns: minmax(0, 196px);
|
||||||
gap: 0.5rem;
|
gap: 0.625rem;
|
||||||
align-items: start;
|
align-items: start;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.parameter__color-stack {
|
||||||
|
display: grid;
|
||||||
|
gap: 0.625rem;
|
||||||
|
width: 196px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.parameter__wheel {
|
.parameter__wheel {
|
||||||
width: 132px;
|
width: 196px;
|
||||||
height: 132px;
|
height: 196px;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.parameter__wheel [class*="react-colorful"],
|
.parameter__wheel [class*="react-colorful"],
|
||||||
@@ -873,14 +882,87 @@ pre {
|
|||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.parameter__wheel svg,
|
||||||
|
.parameter__wheel canvas {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.parameter__color-bottom {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, 1fr) minmax(4.5rem, 0.85fr);
|
||||||
|
gap: 0.625rem;
|
||||||
|
align-items: end;
|
||||||
|
width: 196px;
|
||||||
|
}
|
||||||
|
|
||||||
.parameter__swatch {
|
.parameter__swatch {
|
||||||
grid-column: 2;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: 28px;
|
min-height: 38px;
|
||||||
border: 1px solid var(--app-border);
|
border: 1px solid var(--app-border);
|
||||||
border-radius: var(--app-radius-sm);
|
border-radius: var(--app-radius-sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.parameter__value-slider {
|
||||||
|
display: block;
|
||||||
|
width: 196px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.parameter__value-slider input[type="range"] {
|
||||||
|
--value-thumb-size: 18px;
|
||||||
|
display: block;
|
||||||
|
width: 196px;
|
||||||
|
height: 22px;
|
||||||
|
margin: 0;
|
||||||
|
accent-color: #f2f6fb;
|
||||||
|
background: linear-gradient(90deg, #000 0%, #fff 100%);
|
||||||
|
border-radius: 999px;
|
||||||
|
cursor: pointer;
|
||||||
|
appearance: none;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.parameter__value-slider input[type="range"]::-webkit-slider-runnable-track {
|
||||||
|
height: 0.75rem;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.28);
|
||||||
|
border-radius: 999px;
|
||||||
|
background: linear-gradient(90deg, #000 0%, #fff 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.parameter__value-slider input[type="range"]::-webkit-slider-thumb {
|
||||||
|
width: var(--value-thumb-size);
|
||||||
|
height: var(--value-thumb-size);
|
||||||
|
margin-top: calc((0.75rem - var(--value-thumb-size)) / 2);
|
||||||
|
border: 2px solid #f7fbff;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: #f7fbff;
|
||||||
|
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.65), 0 1px 4px rgba(0, 0, 0, 0.45);
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.parameter__value-slider input[type="range"]::-moz-range-track {
|
||||||
|
height: 0.75rem;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.28);
|
||||||
|
border-radius: 999px;
|
||||||
|
background: linear-gradient(90deg, #000 0%, #fff 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.parameter__value-slider input[type="range"]::-moz-range-thumb {
|
||||||
|
width: var(--value-thumb-size);
|
||||||
|
height: var(--value-thumb-size);
|
||||||
|
border: 2px solid #f7fbff;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: #f7fbff;
|
||||||
|
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.65), 0 1px 4px rgba(0, 0, 0, 0.45);
|
||||||
|
}
|
||||||
|
|
||||||
|
.parameter__value-slider strong {
|
||||||
|
text-align: right;
|
||||||
|
min-height: 1rem;
|
||||||
|
color: var(--app-text);
|
||||||
|
font-size: 0.74rem;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.parameter__alpha {
|
.parameter__alpha {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 0.25rem;
|
gap: 0.25rem;
|
||||||
@@ -975,6 +1057,13 @@ pre {
|
|||||||
grid-column: auto;
|
grid-column: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.parameter__color-stack,
|
||||||
|
.parameter__color-bottom,
|
||||||
|
.parameter__value-slider,
|
||||||
|
.parameter__value-slider input[type="range"] {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.kv-row {
|
.kv-row {
|
||||||
grid-template-columns: minmax(6.25rem, 0.6fr) minmax(0, 1fr);
|
grid-template-columns: minmax(6.25rem, 0.6fr) minmax(0, 1fr);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user