LUT interpolation
All checks were successful
CI / React UI Build (push) Successful in 11s
CI / Native Windows Build And Tests (push) Successful in 1m47s
CI / Windows Release Package (push) Successful in 2m31s

This commit is contained in:
2026-05-06 16:44:39 +10:00
parent 96e7e66b0d
commit f9ea2d6900
4 changed files with 36150 additions and 0 deletions

View File

@@ -0,0 +1,48 @@
{
"id": "lut-apply",
"name": "3D LUT Apply",
"description": "Applies the packaged 33-point .cube LUT to the incoming video using trilinear interpolation.",
"category": "Color",
"entryPoint": "shadeVideo",
"textures": [
{
"id": "lutTexture",
"path": "test-lut.cube"
}
],
"parameters": [
{
"id": "lutStrength",
"label": "LUT Strength",
"type": "float",
"default": 1.0,
"min": 0.0,
"max": 1.0,
"step": 0.01
},
{
"id": "preExposure",
"label": "Pre Exposure",
"type": "float",
"default": 0.0,
"min": -4.0,
"max": 4.0,
"step": 0.01
},
{
"id": "postContrast",
"label": "Post Contrast",
"type": "float",
"default": 1.0,
"min": 0.0,
"max": 2.0,
"step": 0.01
},
{
"id": "clampInput",
"label": "Clamp Input",
"type": "bool",
"default": true
}
]
}

View File

@@ -0,0 +1,54 @@
static const float LUT_SIZE = 33.0;
static const float LUT_LAST_INDEX = 32.0;
float3 sampleLutCell(float3 index)
{
float r = floor(index.r + 0.5);
float g = floor(index.g + 0.5);
float b = floor(index.b + 0.5);
float atlasWidth = LUT_SIZE * LUT_SIZE;
float2 lutUv;
lutUv.x = (r + b * LUT_SIZE + 0.5) / atlasWidth;
lutUv.y = (g + 0.5) / LUT_SIZE;
return lutTexture.Sample(lutUv).rgb;
}
float3 applyLut33(float3 color)
{
float3 lutCoord = saturate(color) * LUT_LAST_INDEX;
float3 baseIndex = floor(lutCoord);
float3 nextIndex = min(baseIndex + 1.0, LUT_LAST_INDEX);
float3 blend = lutCoord - baseIndex;
float3 c000 = sampleLutCell(float3(baseIndex.r, baseIndex.g, baseIndex.b));
float3 c100 = sampleLutCell(float3(nextIndex.r, baseIndex.g, baseIndex.b));
float3 c010 = sampleLutCell(float3(baseIndex.r, nextIndex.g, baseIndex.b));
float3 c110 = sampleLutCell(float3(nextIndex.r, nextIndex.g, baseIndex.b));
float3 c001 = sampleLutCell(float3(baseIndex.r, baseIndex.g, nextIndex.b));
float3 c101 = sampleLutCell(float3(nextIndex.r, baseIndex.g, nextIndex.b));
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);
}
float4 shadeVideo(ShaderContext context)
{
float4 source = context.sourceColor;
float3 inputColor = source.rgb * pow(2.0, preExposure);
if (clampInput)
inputColor = saturate(inputColor);
float3 lutColor = applyLut33(inputColor);
float3 graded = lerp(inputColor, lutColor, lutStrength);
graded = (graded - 0.5) * postContrast + 0.5;
return float4(saturate(graded), source.a);
}

File diff suppressed because it is too large Load Diff