diff --git a/README.md b/README.md index 33c247b..5cf2bd3 100644 --- a/README.md +++ b/README.md @@ -256,3 +256,5 @@ If neither variable is set, the workflow falls back to the repo-local defaults u - better shader search UI - LUT applicator - More comprehensive greenscreen shader +- 16bit float render target, linear compositing? +- add 10bit output path decklink diff --git a/shaders/lut-apply/shader.json b/shaders/lut-apply/shader.json index 7bf339a..4b6cc43 100644 --- a/shaders/lut-apply/shader.json +++ b/shaders/lut-apply/shader.json @@ -1,7 +1,7 @@ { "id": "lut-apply", "name": "3D LUT Apply", - "description": "Applies the packaged 33-point .cube LUT to the incoming video using trilinear interpolation.", + "description": "Applies the packaged 33-point .cube LUT to the incoming video using tetrahedral interpolation and optional output dithering.", "category": "Color", "entryPoint": "shadeVideo", "textures": [ @@ -38,6 +38,15 @@ "max": 2.0, "step": 0.01 }, + { + "id": "ditherAmount", + "label": "Output Dither", + "type": "float", + "default": 0.5, + "min": 0.0, + "max": 1.0, + "step": 0.01 + }, { "id": "clampInput", "label": "Clamp Input", diff --git a/shaders/lut-apply/shader.slang b/shaders/lut-apply/shader.slang index 1f58e10..4f6a627 100644 --- a/shaders/lut-apply/shader.slang +++ b/shaders/lut-apply/shader.slang @@ -30,13 +30,35 @@ float3 applyLut33(float3 color) float3 c011 = sampleLutCell(float3(baseIndex.r, nextIndex.g, nextIndex.b)); float3 c111 = sampleLutCell(float3(nextIndex.r, nextIndex.g, nextIndex.b)); - float3 c00 = lerp(c000, c100, blend.r); - float3 c10 = lerp(c010, c110, blend.r); - float3 c01 = lerp(c001, c101, blend.r); - float3 c11 = lerp(c011, c111, blend.r); - float3 c0 = lerp(c00, c10, blend.g); - float3 c1 = lerp(c01, c11, blend.g); - return lerp(c0, c1, blend.b); + if (blend.r > blend.g) + { + if (blend.g > blend.b) + return c000 + blend.r * (c100 - c000) + blend.g * (c110 - c100) + blend.b * (c111 - c110); + if (blend.r > blend.b) + return c000 + blend.r * (c100 - c000) + blend.b * (c101 - c100) + blend.g * (c111 - c101); + return c000 + blend.b * (c001 - c000) + blend.r * (c101 - c001) + blend.g * (c111 - c101); + } + + if (blend.b > blend.g) + return c000 + blend.b * (c001 - c000) + blend.g * (c011 - c001) + blend.r * (c111 - c011); + if (blend.b > blend.r) + return c000 + blend.g * (c010 - c000) + blend.b * (c011 - c010) + blend.r * (c111 - c011); + return c000 + blend.g * (c010 - c000) + blend.r * (c110 - c010) + blend.b * (c111 - c110); +} + +float hash12(float2 value) +{ + float3 p = frac(float3(value.xyx) * 0.1031); + p += dot(p, p.yzx + 33.33); + return frac((p.x + p.y) * p.z); +} + +float3 outputDither(float2 pixel) +{ + float r = hash12(pixel + float2(17.0, 31.0)) - hash12(pixel + float2(83.0, 47.0)); + float g = hash12(pixel + float2(29.0, 71.0)) - hash12(pixel + float2(53.0, 19.0)); + float b = hash12(pixel + float2(61.0, 11.0)) - hash12(pixel + float2(7.0, 97.0)); + return float3(r, g, b) / 255.0; } float4 shadeVideo(ShaderContext context) @@ -49,6 +71,7 @@ float4 shadeVideo(ShaderContext context) float3 lutColor = applyLut33(inputColor); float3 graded = lerp(inputColor, lutColor, lutStrength); graded = (graded - 0.5) * postContrast + 0.5; + graded += outputDither(context.uv * context.outputResolution) * ditherAmount; return float4(saturate(graded), source.a); }