Post-Effekt-Kette als Gerüst, Dither als erstes Glied
Bildweite Effekte gehören nicht in den Szenen-Shader. Cel-Ramp und Sobel-Outline sollen dazukommen, ohne einander (oder scene.wgsl) zu kennen — also eine Kette gleichrangiger Fullscreen-Pässe zwischen Szene und Blit, Ping-Pong über zwei interne Targets. Der Vertrag ist für alle gleich: Farbtextur rein (group 0/binding 0), Farbe raus. Die Vertex-Stufe teilen sich alle über fullscreen.wgsl, damit eine Effekt-Datei nur aus ihrem fs_main besteht. Ein neuer Effekt ist eine .wgsl plus eine Zeile in EFFECTS. Bei 640×480 kostet ein eigener Pass je Effekt praktisch nichts — deshalb kein Über-Shader. Erster Bewohner ist die RGB555-Quantisierung samt Bayer-Dither, aus scene.wgsl herausgelöst. Das UI zeichnet jetzt in einem eigenen Pass hinter der Kette, sonst würde der Dither auch den Text quantisieren, den er bisher nicht anfasst; damit braucht SpritePass kein Tiefen-Attachment mehr. Geschaltet wird über den exec-Trichter (`post`, `post <e> on|off`). Die Namen kennt nur das Frontend: es meldet seine Kette beim Start in engine::post an, wie render::audio seine Emitter aus engine::audio zieht. Der Kern bekommt dadurch keine GPU zu sehen. Das Bild soll unverändert bleiben — gleicher Bayer-Kernel, gleiche Koordinaten, gleiche Reihenfolge relativ zum UI. Verifiziert sind Tests, clippy und ein Start ohne Validation-Fehler; ein Pixelvergleich steht aus. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+6
-11
@@ -1,5 +1,8 @@
|
||||
//! Sprite-Pass: das 2D-Overlay (UI) als getintete Textur-Quads.
|
||||
//!
|
||||
//! Zeichnet in einem eigenen Pass *hinter* der Post-Kette: Bild-Effekte
|
||||
//! (Farbtiefe, Dither, später Outline) treffen so nur die Welt, nie den Text.
|
||||
//!
|
||||
//! Immediate-Mode: der Vertex-Buffer wird jeden Frame neu befüllt (kleine
|
||||
//! Datenmenge). Geometrie kommt von [`crate::render::ui`] als fertige
|
||||
//! [`SpriteVertex`]-Liste + [`SpriteBatch`]es (ein Batch je Textur). Die
|
||||
@@ -60,7 +63,6 @@ impl SpritePass {
|
||||
device: &wgpu::Device,
|
||||
queue: &wgpu::Queue,
|
||||
color_format: wgpu::TextureFormat,
|
||||
depth_format: wgpu::TextureFormat,
|
||||
internal: [f32; 2],
|
||||
textures: &[Image],
|
||||
) -> Self {
|
||||
@@ -89,16 +91,9 @@ impl SpritePass {
|
||||
})],
|
||||
}),
|
||||
primitive: wgpu::PrimitiveState::default(),
|
||||
// Der interne Pass hat ein Tiefen-Attachment → die Pipeline muss
|
||||
// ein kompatibles Format deklarieren. UI testet/schreibt aber
|
||||
// keine Tiefe (Always, kein Write) → liegt immer obenauf.
|
||||
depth_stencil: Some(wgpu::DepthStencilState {
|
||||
format: depth_format,
|
||||
depth_write_enabled: Some(false),
|
||||
depth_compare: Some(wgpu::CompareFunction::Always),
|
||||
stencil: wgpu::StencilState::default(),
|
||||
bias: wgpu::DepthBiasState::default(),
|
||||
}),
|
||||
// Eigener Pass hinter der Post-Kette, ohne Tiefen-Attachment:
|
||||
// das Overlay liegt per Reihenfolge obenauf.
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview_mask: None,
|
||||
cache: None,
|
||||
|
||||
Reference in New Issue
Block a user