-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Description
Extend crt_effect.effect — Physically Based Phosphor Afterglow
This PR extends crt_effect.effect
to implement a physically accurate CRT phosphor afterglow model. It replaces the // TODO
afterglow placeholder with a decaying-maximum luminance function matching real phosphor persistence.
Shader Update (insert at existing TODO in crt_effect.effect
)
// -----------------------------------------------------------------------------
// CRT phosphor afterglow: decaying-maximum persistence model
// -----------------------------------------------------------------------------
uniform float afterglow_duration_ms <
string name = "Afterglow Duration (ms)";
string description = "Duration of phosphor persistence in milliseconds";
float minimum = 0.0;
float maximum = 3000.0;
float step = 10.0;
> = 500.0;
uniform int afterglow_curve <
string name = "Afterglow Curve";
string description = "Decay curve shaping (Instant, Gradual, Rapid, Long Tail)";
> = 1;
uniform texture2d image;
uniform texture2d prev_frame;
uniform float elapsed_time;
sampler_state linear_clamp {
Filter = Linear;
AddressU = Clamp;
AddressV = Clamp;
};
// ApplyAfterglow — integrates phosphor persistence model
float3 ApplyAfterglow(float2 uv, float3 current_rgb)
{
float4 prev = prev_frame.Sample(linear_clamp, uv);
float duration_s = max(afterglow_duration_ms, 1.0) / 1000.0;
float3 tau = float3(0.6, 0.8, 0.3) * duration_s;
float curve_scale = 1.0;
switch (afterglow_curve) {
case 0: curve_scale = 4.0; break; // InstantFade
case 1: curve_scale = 1.0; break; // GradualFade
case 2: curve_scale = 2.0; break; // RapidFade
case 3: curve_scale = 0.5; break; // LongTail
}
tau *= curve_scale;
float3 decay = exp(-elapsed_time / max(tau, 0.001));
float3 persisted = max(current_rgb, prev.rgb * decay);
return persisted;
}
In your fragment shader main function, modify:
float4 color = image.Sample(linear_clamp, inp.uv);
to:
float3 rgb = image.Sample(linear_clamp, inp.uv).rgb;
rgb = ApplyAfterglow(inp.uv, rgb);
float4 color = float4(rgb, 1.0);
Re-enable Plugin Properties
obs_property_t *afterglow_duration_prop = obs_properties_add_int_slider(
effects_props, "afterglow_duration_ms",
obs_module_text("AfterglowDuration"), 0, 3000, 10);
obs_property_set_long_description(afterglow_duration_prop,
obs_module_text("AfterglowDuration.Description"));
obs_property_t *afterglow_curve_prop = obs_properties_add_list(
effects_props, "afterglow_curve", obs_module_text("AfterglowCurve"),
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT);
obs_property_list_add_int(afterglow_curve_prop, obs_module_text("AfterglowCurve.InstantFade"), 0);
obs_property_list_add_int(afterglow_curve_prop, obs_module_text("AfterglowCurve.GradualFade"), 1);
obs_property_list_add_int(afterglow_curve_prop, obs_module_text("AfterglowCurve.RapidFade"), 2);
obs_property_list_add_int(afterglow_curve_prop, obs_module_text("AfterglowCurve.LongTail"), 3);
obs_property_set_long_description(afterglow_curve_prop,
obs_module_text("AfterglowCurve.Description"));
Apply parameters during rendering:
float duration_ms = (float)obs_data_get_int(settings, "afterglow_duration_ms");
int curve = (int)obs_data_get_int(settings, "afterglow_curve");
gs_effect_set_float(gs_effect_get_param_by_name(effect, "afterglow_duration_ms"), duration_ms);
gs_effect_set_int(gs_effect_get_param_by_name(effect, "afterglow_curve"), curve);
LLM Integration Instruction
You are updating crt_effect.effect
to implement a physically based phosphor afterglow. Locate the // TODO
for afterglow. Insert the ApplyAfterglow() function and modify the main fragment shader to call it. Ensure uniforms: afterglow_duration_ms, afterglow_curve, image, prev_frame, elapsed_time exist. Do not alter unrelated code or passes. Add comment: // CRT phosphor afterglow: decaying-maximum persistence model
.
Summary
- Integrates true CRT phosphor persistence into existing CRT shader.
- Uses per-channel exponential decay and configurable duration/curve.
- Re-enables and maps existing OBS UI properties.
- Backwards-compatible and localized via existing text keys.
Copilot
Metadata
Metadata
Assignees
Labels
No labels