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 ## Still todo
Audio Audio
Fonts improve text rendering
genlock genlock
Logs Logs
anamorphic desqueeze anamorphic desqueeze
@@ -240,6 +240,6 @@ 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 runtime date time UTC and offset from PCs internal clock
Add a value control to the color wheels Add a value control to the color wheels
![alt text](image.png) ![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 distance = std::sqrt(static_cast<float>(bestDistanceSq));
const float signedDistance = (inside ? 1.0f : -1.0f) * distance; const float signedDistance = (inside ? 1.0f : -1.0f) * distance;
float normalized = 0.5f + signedDistance / static_cast<float>(kTextSdfSpread * 2); 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) if (normalized < 0.0f)
normalized = 0.0f; normalized = 0.0f;
if (normalized > 1.0f) if (normalized > 1.0f)
@@ -220,6 +223,24 @@ std::vector<unsigned char> BuildLocalSdf(const std::vector<unsigned char>& alpha
return sdf; 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> FlipTextTextureForShaderUv(const std::vector<unsigned char>& pixels, unsigned width, unsigned height)
{ {
std::vector<unsigned char> flipped(pixels.size(), 0); 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); 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 = BlurTextSdf(sdf, kTextTextureWidth, kTextTextureHeight, kTextSdfBlurPasses);
sdf = FlipTextTextureForShaderUv(sdf, kTextTextureWidth, kTextTextureHeight); sdf = FlipTextTextureForShaderUv(sdf, kTextTextureWidth, kTextTextureHeight);
WriteTextMaskDebugDump(text, alpha, sdf, kTextTextureWidth, kTextTextureHeight); WriteTextMaskDebugDump(text, alpha, sdf, kTextTextureWidth, kTextTextureHeight);

View File

@@ -57,6 +57,15 @@
"min": 0.0, "min": 0.0,
"max": 0.5, "max": 0.5,
"step": 0.01 "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; 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 mask = insideTextRect ? sampleTitleText(textUv) : 0.0;
float edge = 0.5; float edge = 0.02;
float aa = max(fwidth(mask) * 1.5, 0.006); float aa = max(fwidth(mask) * 1.5, 0.002);
float outlineAmount = min(outlineWidth * 0.25, 0.24);
float fill = smoothstep(edge - aa, edge + aa, mask); float fill = smoothstep(edge - aa, edge + aa, mask);
float outlineField = smoothstep(edge - outlineAmount - aa, edge - outlineAmount + aa, mask); float shadowRadius = min((outlineWidth + softness) * 0.025, 0.018);
float outline = saturate(outlineField - fill); float shadow = 0.0;
float textAlpha = max(fill * fillColor.a, outline * outlineColor.a); 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) if (textAlpha <= 0.0001)
return context.sourceColor; return context.sourceColor;
float4 base = context.sourceColor; float4 base = context.sourceColor;
float4 outlineLayer = float4(outlineColor.rgb * outlineColor.a, outline * outlineColor.a); float4 outlineLayer = float4(outlineColor.rgb * outlineAlpha, outlineAlpha);
float4 fillLayer = float4(fillColor.rgb * fillColor.a, fill * fillColor.a); float4 fillLayer = float4(fillColor.rgb * fillAlpha, fillAlpha);
return saturate(compositeOver(compositeOver(base, outlineLayer), fillLayer)); return saturate(compositeOver(compositeOver(base, outlineLayer), fillLayer));
} }