All examplesshaderpost-processing
§ examples · shader

Post-Processing

Bloom, SSAO, FXAA, ACES/Reinhard tonemap — composable post stack.

slugpost-processing
source87 lines
statuslive
tsexamples-src/post-processing.ts
1/**
2 * Post-Processing — the render engine ships a configurable post chain
3 * (bloom · HDR tonemap · SSAO · FXAA). The library exports the typed
4 * `PostProcessConfig` shape and the shader modules under
5 * `mapgpu/render` for custom wiring.
6 *
7 * Here we swap between three atmosphere + lighting presets via
8 * `setGlobeEffects` — the cheapest way to change the feel of a scene
9 * without touching the post pipeline directly.
10 */
11 
12import { MapView } from "mapgpu";
13import { RasterTileLayer } from "mapgpu/layers";
14import { RenderEngine } from "mapgpu/render";
15 
16import type { RunResultObject } from "@/components/examples/ExampleCanvas";
17 
18type Preset = "neutral" | "warm" | "night";
19 
20export async function run(container: HTMLElement): Promise<RunResultObject> {
21 const view = new MapView({
22 container,
23 renderEngine: new RenderEngine(),
24 mode: "3d",
25 center: [30, 30],
26 zoom: 2.4,
27 backgroundColor: "transparent",
28 globeEffects: {
29 atmosphere: {
30 enabled: true,
31 colorInner: [0.55, 0.78, 1.0, 0.9],
32 colorOuter: [0.4, 0.6, 1.0, 0.3],
33 strength: 1.3,
34 falloff: 3,
35 },
36 },
37 });
38 
39 view.map.add(
40 new RasterTileLayer({
41 id: "esri-imagery",
42 urlTemplate:
43 "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",
44 maxZoom: 19,
45 attribution: "© Esri",
46 }),
47 );
48 
49 await view.when();
50 
51 const apply = (preset: Preset) => {
52 if (preset === "neutral") {
53 view.setGlobeEffects({
54 atmosphere: { enabled: true, colorInner: [0.55, 0.78, 1.0, 0.9], colorOuter: [0.4, 0.6, 1.0, 0.3], strength: 1.3, falloff: 3 },
55 lighting: { ambient: 0.5, diffuse: 0.85 },
56 });
57 } else if (preset === "warm") {
58 view.setGlobeEffects({
59 atmosphere: { enabled: true, colorInner: [1.0, 0.55, 0.25, 0.95], colorOuter: [1.0, 0.35, 0.15, 0.3], strength: 2.0, falloff: 2.6 },
60 lighting: { ambient: 0.6, diffuse: 1.0 },
61 });
62 } else {
63 view.setGlobeEffects({
64 atmosphere: { enabled: true, colorInner: [0.15, 0.3, 0.6, 0.85], colorOuter: [0.05, 0.1, 0.3, 0.4], strength: 1.4, falloff: 3.4 },
65 lighting: { ambient: 0.25, diffuse: 0.65 },
66 });
67 }
68 };
69 
70 return {
71 dispose: () => view.destroy(),
72 controls: [
73 {
74 kind: "segmented",
75 id: "preset",
76 initial: "neutral",
77 options: [
78 { value: "neutral", label: "Neutral" },
79 { value: "warm", label: "Warm" },
80 { value: "night", label: "Night" },
81 ],
82 onChange: (value) => apply(value as Preset),
83 },
84 ],
85 };
86}