raea/post_process

What's done to the frame after it's drawn: tone mapping, bloom, depth of field, motion blur, grading and outlines.

View as Markdown

These are Bevy's post-processing passes, placed beside the camera: <ToneMapping>, <Bloom>, <DepthOfField>, <MotionBlur>, <AntiAliasing>, lens distortion and fisheye, plus raea's <Grade> for colour grading, <Outline> and <Look>, which sets a whole finish at once. <FramePass> and <Compute> run your own shaders on the frame.

TSX
import { Camera3d } from "raea/camera";
import { Bloom, ToneMapping } from "raea/post_process";
import { Transform } from "raea/transform";

const Glow = () => (
  <>
    <Camera3d transform={Transform.fromXyz(-2, 2.5, 5).lookingAt([0, 0, 0])} />
    <ToneMapping mode="tony" />
    <Bloom intensity={1} threshold={0} />
  </>
);
TS
import { AntiAliasing, Bloom, Compute, DepthOfField } from "raea/post_process"

raea/post_process exports 12 components, 14 types. Bevy's counterpart: bevy_post_process, bevy_anti_alias. Source: sdk/raea/src/post_process.ts.

Components

AntiAliasing

How the 3D's edges are smoothed. Put it inside the Canvas3D, once; the first frame's holds for the piece.

Bevy: bevy_anti_alias::smaa::Smaa, bevy_anti_alias::fxaa::Fxaa.

Takes AntiAliasingProps's props.

Bloom

Glow around bright parts (emissive materials, strong highlights). Put it inside the Canvas3D.

Bevy: bevy_post_process::bloom::settings::Bloom.

Takes BloomProps's props.

Compute

A compute over the frame, in the 3D beside the camera; several run in the order written, before the cameras draw.

Rust: raea_sys_compute::Computes.

Takes ComputeProps's props.

DepthOfField

A lens's depth of field: what's nearer or farther than the camera's focus blurs. Put it inside the Canvas3D; pull focus by animating the camera's focus. Inside a Camera3d it is Bevy's component on the camera, its focal_distance the camera's focus.

Bevy: bevy_post_process::dof::DepthOfField.

Takes DepthOfFieldProps's props.

Fisheye

A fisheye lens on the camera: a pass over the 3D after tone mapping (the page over it stays straight). Every value animates per frame; a lens's vignette and colour fringes are 's. Put it inside the Canvas3D.

Takes FisheyeProps's props.

FramePass

A full-screen pass over the scene camera's frame, beside the camera; several run in the order written. With a frame they run on its cells, before the look's composite.

Rust: raea_sys_framepass::FramePasses.

Takes FramePassProps's props.

Grade

The camera's colour grade (lift, gamma, gain and saturation per range of light, before tone mapping), a lens vignette and colour fringes: one grade over every scene, so a film looks of a piece. Put it inside the Canvas3D.

Bevy: bevy_render::view::ColorGrading, bevy_post_process::effect_stack::chromatic_aberration::ChromaticAberration, bevy_post_process::effect_stack::vignette::Vignette.

Takes GradeProps's props.

LensDistortion

Barrel or pincushion distortion (Brown-Conrady k1, k2) on the camera, a pass after tone mapping as Fisheye's. Put it inside the Canvas3D.

Bevy: bevy_post_process::LensDistortion.

Takes LensDistortionProps's props.

Look

The whole frame drawn as a model's look draws its model: every part of the scene in the one grain, its bloom, fog and blur inside it. Put it inside the Canvas3D. mode="paint" or "cartoon" draws every standard material as paint (engine/render paint.rs):

Bevy: bevy_pbr::mesh_material::MeshMaterial3d<bevy_pbr::extended_material::ExtendedMaterial<bevy_pbr::pbr_material::StandardMaterial, raea_render::engine::paint::Paint>>.

Takes LookProps's props.

MotionBlur

Motion blur from each part's and the camera's motion over the frame before (Bevy's MotionBlur): with it, each frame is drawn after the one before it, so a frame's blur is the same in a render, a seek and play. A frame without it has none. Put it inside the Canvas3D.

Bevy: bevy_post_process::motion_blur::MotionBlur.

Takes MotionBlurProps's props.

Outline

Ink lines where the scene's depth steps or its surfaces turn, drawn before bloom and tone mapping; under a a cell wide (Return of the Obra Dinn's line). Put it inside the Canvas3D.

Takes OutlineProps's props.

ToneMapping

The camera's tone mapping and exposure. Put it inside the Canvas3D.

Bevy: bevy_render::view::Tonemapping, bevy_camera::camera::Exposure.

Takes ToneMappingProps's props.

Types

AntiAliasingProps

FieldTypeWhat it is
mode (required)"msaa" | "smaa" | "fxaa" | "none""msaa" (4x multisampling, the default), "smaa" (morphological, high preset: the default with AmbientOcclusion, which can't multisample), "fxaa" (cheapest, softest) or "none". Each draws a frame from that frame alone, so a render equals its play (temporal anti-aliasing isn't offered: it needs the frames before)

BloomProps

FieldTypeWhat it is
intensitynumber1 is a natural glow, 2 strong; 0 none
thresholdnumberonly what's brighter than this glows (0 = everything a little; 1 = only emissive parts and highlights)
skipstring[]composition passes (a part's pass) left out of it: they neither glow nor take the glow
passesRecord<string, number>each named pass's share of it, 0 (as skip) to 1 (all of it, as "scene" has)

ComputeProps

A compute shader (raea-sys-compute). Its source has one @compute entry point and reads time() (seconds), u_NAME() for each uniform, each buffer as NAME: array<f32> (read and written) and each image as NAME: texture_storage_2d<rgba8unorm, write>.

FieldTypeWhat it is
filestringa shader file compiled as written, staticFile("shaders/x.wesl"), in place of wesl: its @group(0) storage textures and uniforms its own, as a Bevy example's render-graph node binds them
entrystring | nulla file's entry point this frame (null or left out: nothing dispatched), as a node picks its pipeline
bindRecord<string, string>a file's storage textures this frame, each an image's key ({ input: "a", output: "b" }), as a node picks its bind group (a ping-pong swaps them frame by frame)
weslstringthe source in WESL (a superset of WGSL)
wgslstringthe same in plain WGSL
workgroups (required)number[]how many workgroups a frame dispatches: [x], [x, y] or [x, y, z]
uniformsRecord<string, number | number[] | string | Record<string, number | number[] | string |…up to 16, as a surface shader's; a file's struct field may be { start: NAME } or { end: NAME }: the range of the mesh buffer NAME binds in its slab, in its array's elements (compute_mesh's range.start * 8)
buffersRecord<string, { size: number } | number[] | StorageValue | MeshSlab>up to 4, the compute's own, kept from frame to frame: { size } (that many f32s, zeroed) or its first contents. A file's: each var<storage> it declares, its first contents in its type's layout or a mesh's slab
imagesRecord<string, string | { src: string; sampler?: SamplerSpec }>up to 4 "render:NAME" (or "render:NAME:WxH") images it writes, which any shader's texture reads by that name (a file's may be { src, sampler }: the sampler it is drawn with)
defsShaderDefsshader defs, as a surface shader's

DepthOfFieldProps

FieldTypeWhat it is
aperturenumberthe lens's f-number: lower blurs more (1.4 dreamy, 2.8 cinematic, 8 nearly sharp); 2.8 by default
mode"bokeh" | "gaussian""bokeh" (round, as a real lens; the default) or "gaussian" (soft, cheaper)
maxBlurnumberthe largest blur, in pixels of the frame (64 by default)
focal_distancenumberBevy's fields, as Bevy's DepthOfField component on a Camera3d (inside it), Bevy's defaults: the distance in focus (10; the camera's focus), the f-number (1), the largest blur in pixels (64), "Bokeh" or "Gaussian"
aperture_f_stopsnumberthe f-number (1): lower is a shallower focus
max_circle_of_confusion_diameternumberthe largest blur, in px (64)

FisheyeProps

FieldTypeWhat it is
strengthnumber0..1 (1 by default): 0 is the camera's own picture, pixel for pixel; ramp it in and out on beats
mode"equidistant" | "stereographic""equidistant" (the default) or "stereographic" (gentler at the edges)
fovnumberthe vertical field of view, in degrees, the camera widens to at strength 1 (its own by default): 100-150 for a real fisheye; the picture is still remapped corner to corner, so nothing goes black
zoomnumberabove 1 crops in, below 1 shows past the picture's edge (see edges)
edges"clamp" | "black"what shows where the lens looks past the picture: its edge pixels ("clamp", the default) or "black"
animateAnimate3ddeclared animation of its numbers (strength, fov, k1, k2, zoom)

FramePassProps

A shader over the whole frame. Its source defines fn shade(in: FullscreenVertexOutput) -> vec4 (or its own

FieldTypeWhat it is
filestringa shader file compiled as written, staticFile("shaders/x.wesl"), in place of wesl: its @group(0) bindings its own, as custom_post_processing's pipeline binds them: each texture_2d the frame (the one frame names) or an image of textures, each sampler Bevy's default (nearest) or samplers' one, each var its value in uniforms (which may change frame by frame)
framestringa file's texture that reads the frame as drawn so far
entrystringa file's fragment entry point ("fragment" by default)
samplersRecord<string, SamplerSpec>a file's samplers by name
weslstringthe source in WESL (a superset of WGSL)
wgslstringthe same in plain WGSL
uniformsRecord<string, number | number[] | string | StorageValue>up to 16, as a surface shader's (a file's: each var, a struct's { field: value })
texturesRecord<string, string | Record<string, unknown>>up to 4, as a surface shader's, each read with its own sampler
defsShaderDefsshader defs, as a surface shader's
at"before-tonemap" | "after-tonemap""after-tonemap" (display colours; the default) or "before-tonemap" (the HDR frame, after bloom)
prepassboolean | { depth?: boolean; normal?: boolean }the camera's depth and normal prepasses, for depth(uv) and normal(uv) (turns its multisampling off)

GradeProps

FieldTypeWhat it is
temperaturenumberwarmer (+) or cooler (-): a shift of the CIE x chromaticity, about -0.3 to 0.3
tintnumbermagenta (+) or green (-)
saturationnumberthe whole frame's saturation after tone mapping (1 keeps it)
shadowsGradeSectionthe grade on the shadows: saturation, contrast, gamma, gain, lift
midtonesGradeSectionthe grade on the midtones
highlightsGradeSectionthe grade on the highlights
vignettenumber | { intensity?: number; radius?: number; smoothness?: number; color?: string }the corners darkened: 0 none, 1 black; or {intensity, radius (0.75), smoothness (5), color}
aberrationnumbera lens's colour fringes at edges, as a fraction of the frame (0.005 subtle, 0.02 strong)
skipstring[]composition passes (a part's pass) the grade leaves as drawn: no fringes or vignette on them, and on an untonemapped camera (a paint Look's) no colour grading either
passesRecord<string, number>each named pass's share of the grade, 0 (as skip) to 1

GradeSection

FieldTypeWhat it is
saturationnumber1 keeps the colour; 0 grey; above 1 richer
contrastnumber1 keeps it; above 1 harder
gammanumber1 keeps it; above 1 darker mids
gainnumbera multiplier: 1 keeps it
liftnumberadded: 0 keeps it, positive lifts the blacks

LensCommon

FieldTypeWhat it is
edges"clamp" | "black"what shows where the lens looks past the picture: its edge pixels ("clamp", the default) or "black"
animateAnimate3ddeclared animation of its numbers (strength, fov, k1, k2, zoom)

LensDistortionProps

FieldTypeWhat it is
k1numberBrown-Conrady: r' = r (1 + k1 r^2 + k2 r^4), r a share of the half-diagonal. Above 0 barrel, below 0 pincushion
k2numberthe r^4 term of the distortion
zoomnumberby default just enough for a barrel's corners to stay inside the picture (1 for pincushion)
edges"clamp" | "black"what shows where the lens looks past the picture: its edge pixels ("clamp", the default) or "black"
animateAnimate3ddeclared animation of its numbers (strength, fov, k1, k2, zoom)

LookProps

MotionBlurProps

FieldTypeWhat it is
shutterAnglenumberthe fraction of a frame the shutter is open (0.5 by default, a 180-degree shutter); above 1 smears further
samplesnumbersamples each way per pixel (4 by default)
animateAnimate3ddeclared animation of its numbers

OutlineProps

FieldTypeWhat it is
colorstringthe line's colour, a hex colour (black by default)
depthnumbera silhouette: how far behind the nearer surface (a fraction of its distance) a neighbour must be (0.04)
normalnumbera crease: how far the surface must turn between neighbours, 1 - cos of the angle (0.3, about 45 degrees; 0 for none)
widthnumberthe line's width in pixels (1 by default; a cartoon's line is about 6)
farnumberhow far from the camera lines reach, in metres: they fade out over its last third, so a far field meeting the sky draws no line along the horizon (no limit by default)
skipstring[]composition passes (a part's pass) drawn with no line: none on their pixels and no crease against them (a scene object's silhouette in front of one still draws, on the object)

ToneMappingProps

FieldTypeWhat it is
mode"tony" | "aces" | "agx" | "neutral" | "reinhard" | "none"how bright light maps to the screen: "tony" (Bevy's default), "aces" (filmic, contrasty), "agx", "neutral", "reinhard", "none"
exposurenumberstops brighter (+) or darker (-) than the default exposure