V1 text, needs improvements
Some checks failed
CI / Native Windows Build And Tests (pull_request) Failing after 18s
CI / React UI Build (pull_request) Has been cancelled
CI / Windows Release Package (pull_request) Has been cancelled

This commit is contained in:
2026-05-05 23:57:02 +10:00
parent 6ce09c0e9c
commit 7e4ab5cbd8
4 changed files with 50 additions and 11 deletions

View File

@@ -232,7 +232,7 @@ If your Windows runner stores the Blackmagic SDK outside the repo, configure `GP
## Still todo
Audio
Fonts
improve text rendering
genlock
Logs
anamorphic desqueeze
@@ -240,6 +240,6 @@ solid color layer
refactor, cleanup of source files
display URL (Maybe clicakable) for control in the windows app (Not on the output)
Sound shader as seperate .slang in shader package?
runtime date time
runtime date time UTC and offset from PCs internal clock
Add a value control to the color wheels
![alt text](image.png)

View File

@@ -205,6 +205,9 @@ std::vector<unsigned char> BuildLocalSdf(const std::vector<unsigned char>& alpha
const float distance = std::sqrt(static_cast<float>(bestDistanceSq));
const float signedDistance = (inside ? 1.0f : -1.0f) * distance;
float normalized = 0.5f + signedDistance / static_cast<float>(kTextSdfSpread * 2);
const unsigned char sourceAlpha = alpha[static_cast<std::size_t>(y) * width + x];
if (sourceAlpha > 0 && sourceAlpha < 255)
normalized = static_cast<float>(sourceAlpha) / 255.0f;
if (normalized < 0.0f)
normalized = 0.0f;
if (normalized > 1.0f)
@@ -220,6 +223,24 @@ std::vector<unsigned char> BuildLocalSdf(const std::vector<unsigned char>& alpha
return sdf;
}
std::vector<unsigned char> BuildTextCoverageTexture(const std::vector<unsigned char>& alpha, unsigned width, unsigned height)
{
std::vector<unsigned char> coverage(static_cast<std::size_t>(width) * height * 4, 0);
for (unsigned y = 0; y < height; ++y)
{
for (unsigned x = 0; x < width; ++x)
{
const unsigned char value = alpha[static_cast<std::size_t>(y) * width + x];
const std::size_t out = (static_cast<std::size_t>(y) * width + x) * 4;
coverage[out + 0] = value;
coverage[out + 1] = value;
coverage[out + 2] = value;
coverage[out + 3] = value;
}
}
return coverage;
}
std::vector<unsigned char> FlipTextTextureForShaderUv(const std::vector<unsigned char>& pixels, unsigned width, unsigned height)
{
std::vector<unsigned char> flipped(pixels.size(), 0);
@@ -414,7 +435,7 @@ bool RasterizeTextSdf(const std::string& text, const std::filesystem::path& font
alpha[static_cast<std::size_t>(y) * kTextTextureWidth + x] = static_cast<unsigned char>(luminance);
}
}
sdf = BuildLocalSdf(alpha, kTextTextureWidth, kTextTextureHeight);
sdf = BuildTextCoverageTexture(alpha, kTextTextureWidth, kTextTextureHeight);
sdf = BlurTextSdf(sdf, kTextTextureWidth, kTextTextureHeight, kTextSdfBlurPasses);
sdf = FlipTextTextureForShaderUv(sdf, kTextTextureWidth, kTextTextureHeight);
WriteTextMaskDebugDump(text, alpha, sdf, kTextTextureWidth, kTextTextureHeight);

View File

@@ -57,6 +57,15 @@
"min": 0.0,
"max": 0.5,
"step": 0.01
},
{
"id": "softness",
"label": "Softness",
"type": "float",
"default": 0.04,
"min": 0.0,
"max": 0.3,
"step": 0.01
}
]
}

View File

@@ -20,18 +20,27 @@ float4 shadeVideo(ShaderContext context)
bool insideTextRect = textUv.x >= 0.0 && textUv.x <= 1.0 && textUv.y >= 0.0 && textUv.y <= 1.0;
float mask = insideTextRect ? sampleTitleText(textUv) : 0.0;
float edge = 0.5;
float aa = max(fwidth(mask) * 1.5, 0.006);
float outlineAmount = min(outlineWidth * 0.25, 0.24);
float edge = 0.02;
float aa = max(fwidth(mask) * 1.5, 0.002);
float fill = smoothstep(edge - aa, edge + aa, mask);
float outlineField = smoothstep(edge - outlineAmount - aa, edge - outlineAmount + aa, mask);
float outline = saturate(outlineField - fill);
float textAlpha = max(fill * fillColor.a, outline * outlineColor.a);
float shadowRadius = min((outlineWidth + softness) * 0.025, 0.018);
float shadow = 0.0;
if (shadowRadius > 0.0001)
{
shadow = max(shadow, sampleTitleText(textUv + float2(shadowRadius, shadowRadius)));
shadow = max(shadow, sampleTitleText(textUv + float2(-shadowRadius, shadowRadius)));
shadow = max(shadow, sampleTitleText(textUv + float2(shadowRadius, -shadowRadius)));
shadow = max(shadow, sampleTitleText(textUv + float2(-shadowRadius, -shadowRadius)));
}
shadow = smoothstep(edge - aa, edge + aa, shadow) * (0.35 + softness);
float outlineAlpha = saturate(shadow * (1.0 - fill)) * outlineColor.a;
float fillAlpha = fill * fillColor.a;
float textAlpha = max(fillAlpha, outlineAlpha);
if (textAlpha <= 0.0001)
return context.sourceColor;
float4 base = context.sourceColor;
float4 outlineLayer = float4(outlineColor.rgb * outlineColor.a, outline * outlineColor.a);
float4 fillLayer = float4(fillColor.rgb * fillColor.a, fill * fillColor.a);
float4 outlineLayer = float4(outlineColor.rgb * outlineAlpha, outlineAlpha);
float4 fillLayer = float4(fillColor.rgb * fillAlpha, fillAlpha);
return saturate(compositeOver(compositeOver(base, outlineLayer), fillLayer));
}