Rendering Pipeline
Viso’s rendering pipeline has two main stages: a geometry pass that renders molecular structures to HDR render targets, and a post-processing stack that applies screen-space effects.
Overview
Geometry Pass (8 molecular renderers)
↓ Color (Rgba16Float) + Normals (Rgba16Float) + Depth (Depth32Float)
↓
Post-Processing Stack:
1. SSAO: depth + normals → ambient occlusion texture
2. Bloom: color → threshold → blur → half-res bloom texture
3. Composite: color + SSAO + depth + normals + bloom → tone-mapped result
4. FXAA: anti-aliased final output → swapchain
Geometry Pass
Render Targets
All molecular renderers write to two HDR render targets plus a depth buffer:
| Target | Format | Contents |
|---|---|---|
| Color | Rgba16Float | Scene color with alpha blending |
| Normal | Rgba16Float | View-space normals / metadata (no blending) |
| Depth | Depth32Float | Depth buffer (Less compare, writes enabled) |
Rgba16Float enables HDR lighting and bloom without banding
artifacts.
Molecular Renderers
The Renderers struct holds eight renderers, drawn in the geometry
pass:
1. BackboneRenderer
Renders protein backbones as a single mesh with two index ranges — tube indices (drawn first for coil segments and fully in tube mode) and ribbon indices (drawn for helices and sheets in ribbon mode).
- Geometry: cubic Hermite splines with rotation-minimizing frames.
- Per-SS appearance: helix / sheet / coil width, thickness, and
roundness from
GeometryOptions(driven bycartoon_stylepreset unlessCustom). - Detail:
segments_per_residue×cross_section_verts(defaults 32 × 16, scalable per LOD tier). - Vertex data: position, normal, color, residue idx, center pos.
2. SidechainRenderer
Renders sidechain atoms as ray-marched capsule impostors.
- Technique: storage buffer of capsule instances rendered as ray-marched impostors.
- Capsule radius: 0.3 Å.
- Color: from the active sidechain color mode (Backbone or Hydrophobicity).
- Frustum culling: instances outside the view frustum are skipped on upload.
3. BondRenderer
Renders structural bonds (H-bonds, disulfides) as configurable capsules.
- Style:
Solid,Dashed, orStippledper bond type (BondOptions). - Source:
Auto(geometry-detected),Manual(caller-provided), orBoth.
4. BandRenderer
Renders constraint bands (e.g. for Rosetta minimization).
- Visual: capsule impostors with variable radius (0.1–0.4 Å,
scaled by
strength). - Colors by type: default (purple), backbone (yellow-orange), disulfide (yellow-green), H-bond (cyan), disabled (gray).
- Anchor spheres: small spheres at band endpoints.
5. PullRenderer
Renders the active drag constraint.
- Cylinder: capsule from atom to mouse target (purple).
- Arrow: cone impostor at the target end pointing toward the drag direction.
6. BallAndStickRenderer
Renders ligands, ions, waters, and (in BallAndStick drawing mode) proteins.
- Atoms: ray-cast sphere impostors with vdW-scaled radii.
- Bonds: capsule impostors (cylinders with hemispherical caps).
- Lipid modes:
Coarse(P-only spheres + thin tail bonds) orBallAndStick(full detail).
7. NucleicAcidRenderer
Renders DNA/RNA backbones and base rings.
- Stems: capsule instances tracing the phosphate backbone.
- Rings: polygon instances for the nucleobase rings.
- Color: per-base (default) or uniform.
8. IsosurfaceRenderer
Renders electron-density-derived molecular surfaces (Gaussian, SES,
or cavity) generated by the background surface_regen worker.
- Backface depth pre-pass is rendered separately so the composite pass can apply correct depth-aware blending for translucent surfaces.
Shared Bind Groups
All renderers receive common bind groups via DrawBindGroups:
#![allow(unused)]
fn main() {
pub(crate) struct DrawBindGroups<'a> {
pub camera: &'a wgpu::BindGroup, // Projection / view matrices
pub lighting: &'a wgpu::BindGroup, // Light directions, intensities
pub selection: &'a wgpu::BindGroup, // Selection bit-array
pub color: Option<&'a wgpu::BindGroup>, // Per-residue color override
}
}
Post-Processing Stack
1. SSAO (Screen-Space Ambient Occlusion)
Computes local ambient occlusion from the depth and normal buffers.
- Kernel: hemisphere samples in view-space.
- Noise: 4×4 rotation noise texture to reduce banding.
- Parameters:
ao_radius(0.5),ao_bias(0.025),ao_power(2.0). - Output: single-channel AO texture.
- Blur pass: separable blur to smooth noise patterns.
2. Bloom
Extracts and blurs bright areas of the image.
- Threshold: extracts pixels above
bloom_threshold(1.0) to a half-resolution texture. - Blur: separable Gaussian blur (horizontal then vertical, ping-pong textures).
- Mip chain: progressive downsampling.
- Upsample: additive accumulation back to half-resolution.
- Output: half-resolution bloom texture.
- Default
bloom_intensity:0.0(disabled).
3. Composite
Combines all post-processing inputs into the final image.
Inputs:
- Scene color texture
- SSAO texture
- Depth texture
- Normal G-buffer
- Bloom texture
- Composite params uniform
Effects applied:
- SSAO as a darkening multiplier on base color.
- Depth-based fog (configurable
fog_startandfog_density). - Depth-based outlines (edge detection on depth discontinuities).
- Normal-based outlines (edge detection on normal discontinuities).
- Bloom additive blend.
- HDR tone mapping with
exposure. - Gamma correction.
4. FXAA
Fast Approximate Anti-Aliasing as the final pass.
- Smooths jagged edges on mesh-based geometry that supersampling alone doesn’t fully resolve.
- Reads from the composite output, writes to the swapchain surface
(or to the caller-owned texture view in
render_to_texture).
ShaderComposer
Viso uses naga_oil for shader composition, enabling modular WGSL
with imports:
#import viso::camera
#import viso::lighting
@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
let light = calculate_lighting(in.normal, in.position);
// …
}
Shaders live under src/shaders/:
shaders/modules/— shared modules (camera.wgsl,lighting.wgsl,pbr.wgsl,ray.wgsl,volume.wgsl,selection.wgsl,highlight.wgsl,shade.wgsl,depth.wgsl,constants.wgsl,fullscreen.wgsl,impostor_types.wgsl).shaders/raster/mesh/— mesh rasterization (backbone, NA).shaders/raster/impostor/— impostor shaders (sphere, capsule, cone, polygon).shaders/screen/— full-screen passes (composite.wgsl,fxaa.wgsl,ssao.wgsl,ssao_blur.wgsl,bloom_*.wgsl).shaders/utility/— picking shaders (picking_mesh.wgsl,picking_capsule.wgsl,picking_sphere.wgsl).
The composer produces naga::Module IR directly (skipping WGSL
re-parse at runtime for performance).
Render-Scale Supersampling
The rendering resolution can differ from the display resolution via
engine.set_surface_scale(scale). All internal textures (color,
depth, normal, SSAO, bloom) are sized to the render resolution. FXAA
downsamples to the display resolution as the final step.