Skip to content

crazyramirez/AO-Lightmapper

Repository files navigation

AO Lightmapper

AO Lightmapper AO Lightmapper

Ultra-fast GPU-accelerated ambient occlusion lightmap baker that runs entirely in the browser. Loads GLB or FBX files, unwraps UV2 automatically via XAtlas, bakes AO via WebGL2 BVH ray tracing, and exports the result in multiple formats. Also available as a Chrome Extension that bakes directly inside BabylonJS Sandbox and Three.js Editor.


Requirements

  • Node.js 18+
  • A browser with WebGL2 support (Chrome / Edge / Firefox)

Setup

npm install
npm run dev

This starts two processes concurrently:

  • Vite dev server — the browser app
  • FBX converter server — local Express server on port 3001 that handles FBX → GLB conversion via fbx2gltf

FBX support requires the converter server to be running. GLB files work without it.


Desktop App (Electron)

You can run and package the application as a standalone desktop app using Electron. The app automatically starts the backend server in the background and loads the interface in a dedicated, high-performance window with full WebGL 2.0 and SharedArrayBuffer support.

Run in Desktop Mode (Development)

To test the application in a desktop window:

npm run desktop

Build / Package Standalone Executable

To compile the application into a standalone executable (.exe on Windows, .app/.dmg on macOS):

npm run pack

Important

Windows Privilege Requirement (Symbolic Links Error)

On Windows, the packaging process (npm run pack) downloads code-signing utilities which contain macOS symbolic links (.dylib). Extracting these links requires permissions to create symbolic links on Windows.

If you get a Cannot create symbolic link: El cliente no dispone de un privilegio requerido error, resolve it in one of these ways:

  1. Run as Administrator: Close your terminal, open PowerShell/CMD as Administrator, navigate to the project directory, and run npm run pack. Once the cache is extracted, you can compile as a regular user in the future.
  2. Enable Developer Mode (Recommended): Go to Windows Settings > Privacy & security > For developers and turn Developer Mode ON. This permits symbolic links to be created without elevation.

Chrome Extension (In Development ⏳)

The browser extension version allows you to run AO Lightmapper directly on 3D canvases inside BabylonJS Sandbox and Three.js Editor — no local server or file upload needed.

Note

Extension in Development: This extension is currently in active development and will be available soon on the Chrome Web Store.

Supported Sites

Site URL
BabylonJS Sandbox https://sandbox.babylonjs.com
Three.js Editor https://threejs.org/editor

👉 Watch the Demo Video (Direct Link)


Workflow

1. Load a model

Drag and drop a .glb or .fbx file onto the viewport, or click Open in the top-left of the sidebar to use the file picker.

Supported formats: GLB, FBX (FBX is automatically converted to GLB via the local server).

2. Configure settings

All settings are saved automatically to localStorage and persist between sessions. Click Reset to restore defaults.

Lightmap Settings

Setting Options Default Description
Texture Size 512 / 1024 / 2048 / 4096 1024 Resolution of the baked lightmap texture
Format PNG / JPG PNG Output image format. JPG produces smaller files; PNG is lossless
AO Samples 16 – 1024 128 Ray samples per texel. Higher = less noise, slower bake
AO Radius 0.01+ 1.0 Radius of AO rays as a fraction of model size. Higher = softer, wider occlusion

Post-Process

Denoiser — GPU bilateral filter applied after baking. Reduces noise while preserving edges using the G-Buffer world normals as a guide.

Parameter Range Default Description
Radius 1 – 8 px 4 px Filter kernel size. Larger = smoother result
Passes 1 – 3× Number of denoising passes

Seam Fix — UV dilation pass that fills empty texels at UV island borders, preventing visible seam lines on the 3D mesh.

Parameter Range Default Description
Strength 1 – 5× Number of dilation passes. Use 4–5 for meshes with large UV islands

3. Bake the lightmap

Click Generate Lightmap. The pipeline runs in four steps:

  1. UV Unwrap — XAtlas generates a non-overlapping UV2 atlas. Existing UV1 (texture coordinates) is preserved. The model is reloaded into the viewport with UV2 applied.
  2. GBuffer Pass — The mesh is rendered in UV2 space to produce world position and world normal per lightmap texel.
  3. AO Bake — A WebGL2 fragment shader casts cosine-weighted hemisphere rays against a BVH built from the merged scene geometry. Runs N passes with different random seeds and accumulates results. Progress is displayed live.
  4. Post-Process — Denoising (bilateral filter) and dilation (seam fill) are applied if enabled.

A progress overlay with percentage is shown during baking. The lightmap preview panel appears in the bottom-right corner of the viewport when done.

4. Inspect and toggle the lightmap

After baking, the lightmap is applied to all mesh materials in the viewport. The AO Lightmap preview panel (bottom-right) provides:

  • ON / OFF toggle — instantly enable or disable the lightmap in the viewport without rebaking. Useful for A/B comparison with the original material.
  • Export button — downloads the full-resolution lightmap image in the configured format.

5. Export

Two export formats are available:

Export GLB + ZIP (Separate)

Downloads a ZIP containing:

  • modelname.glb — the unwrapped model with UV2
  • modelname_lightmap.png (or .jpg) — the lightmap as a separate image file

Use this when you need the lightmap as an external texture, for example to assign it to the ambient/occlusion slot in another tool.

Export GLB (Embedded)

Downloads a single .glb file with the lightmap embedded as the occlusion texture (occlusionTexture) on all materials, assigned to the UV2 channel (TEXCOORD_1). The file is self-contained and ready to use in any glTF-compatible renderer.

The lightmap is vertically flipped during embedding to match the glTF texture coordinate convention.


Batch Processing

Batch mode bakes multiple files sequentially using the current sidebar settings.

Setup

  1. Click Open → select the Batch tab.
  2. Drag and drop files or click the drop zone to add GLB/FBX files to the queue.
  3. Duplicate files (same name + size) are ignored automatically.

Export mode

Choose how the batch results are exported before running:

Mode Output Description
Separate batch_lightmaps.zip Each model exports as name.glb + name_lightmap.png — lightmap as a separate file
Embedded batch_lightmapped_embedded.zip Each model exports as name_lightmapped.glb — lightmap embedded in the GLB as the occlusion/ambient texture on UV2

Running

Click Bake All. Each file is processed in order:

  1. FBX → GLB conversion (if needed)
  2. UV2 unwrap via XAtlas
  3. Load into viewport
  4. AO bake
  5. Pack into ZIP

Status icons update per file: pending → baking → done → error.

After completion the last successfully baked model is loaded into the viewport. Failed files are shown in the queue; details are in the browser console.


Material Inspector

Click any mesh in the viewport to open the Material Inspector. A blue highlight indicates the selected mesh.

The inspector shows the material type badge (PBR or STD) and exposes:

PBR Materials

Field Description
Albedo Base color
Metallic Metallic factor (0–1)
Roughness Roughness factor (0–1)
Emissive Emissive color

Standard Materials

Field Description
Diffuse Diffuse color
Specular Specular color
Emissive Emissive color

Texture Channels

Both PBR and Standard materials expose their texture slots. Each slot supports:

  • Click thumbnail — opens a full-resolution lightbox preview
  • ↑ (Upload) — load a new image file from disk
  • ⊞ (UV Fit) — reset UV tiling and offset to 1:1 (removes tiling/panning)
  • × (Clear) — remove the texture from the channel

The last row in every texture list is AO Map, which shows the baked lightmap assigned to that mesh. Clicking × removes the lightmap from that specific mesh only. If no meshes retain a lightmap, the preview panel hides and export is disabled.

All material edits support Ctrl+Z undo (up to 64 steps).


View Settings

Located in the View Settings section of the sidebar:

Toggle Description
Show UV Seams Renders UV2 seam edges as neon pink lines in the viewport
Wireframe Toggles wireframe overlay on all meshes
Show Normals Renders per-vertex normal vectors as blue lines
Repair Mesh Normals Analyzes mesh winding order per connected component and flips any inward-facing components. Recomputes smooth normals. Useful for FBX files with broken normals.

Technical Pipeline

UV Unwrapping (unwrapper.js)

Uses XAtlas (via WASM) to generate a non-overlapping UV2 atlas:

  • Existing UV1 (TEXCOORD_0), positions, and normals are preserved and re-indexed to match the new vertex layout
  • TANGENT attributes are removed (incompatible with atlas reindexing)
  • Any existing TEXCOORD_1 is overwritten

AO Baker (baker.js)

Pure WebGL2, no server required. Pipeline per bake:

  1. BVH construction — CPU builds a bounding volume hierarchy from the merged scene geometry. Packed into RGBA32F textures and uploaded to the GPU.
  2. GBuffer pass — Renders the mesh in UV2 space. Outputs world-space position and normal per lightmap texel into floating-point render targets.
  3. AO accumulation — M passes (M = samples / 4), each with a different random seed. Per-texel cosine-weighted hemisphere sampling, ray cast against the BVH using Möller-Trumbore intersection. Ray max distance scales automatically to 15% of model bounding-box diagonal × AO Radius. Self-intersection bias is clamped between 0.1 mm and 2 cm.
  4. Denoising — G-buffer guided bilateral filter. Ping-pongs between two FBOs.
  5. Dilation — Outward-fill passes to pad UV island borders.
  6. Readbackgl.readPixels with Y-axis flip to produce a standard-orientation canvas.

FBX Conversion (server.cjs)

Local Express server on port 3001. Receives raw FBX bytes, writes to a temp file, runs fbx2gltf, and returns the GLB. Also detects and removes the RootNode transform artifact produced by some FBX exporters (propagates scale/rotation to children before removing the root node).

Export (exporter.js)

  • Separate ZIP — packs the unwrapped GLB + lightmap image using JSZip with DEFLATE compression.
  • Embedded GLB — uses @gltf-transform to insert the lightmap PNG as occlusionTexture on all materials with texCoord: 1 (UV2). The image is vertically flipped before embedding to match glTF conventions.

Keyboard Shortcuts

Shortcut Action
Ctrl+Z Undo last material edit
Escape Close material inspector / file modal / texture lightbox

Viewport Controls

Input Action
Left drag Orbit camera
Right drag / Middle drag Pan
Scroll wheel Zoom
Click mesh Open Material Inspector
Click empty space Deselect mesh

Libraries

Runtime

Library Version Role
@babylonjs/core ^9.10.1 3D engine — scene, camera, lights, mesh picking, PBR/Standard materials, texture management
@babylonjs/loaders ^9.10.1 glTF/GLB import via SceneLoader
@babylonjs/serializers ^9.10.1 GLB serialization support
@gltf-transform/core ^4.0.0 Read/write GLB binary, traverse and mutate glTF documents
@gltf-transform/extensions ^4.0.0 glTF extension support (KHR_materials_*, EXT_meshopt_compression, etc.)
@gltf-transform/functions ^4.0.0 glTF transform utilities
jszip ^3.10.1 ZIP archive creation for batch and single exports
fbx2gltf ^0.9.7-p1 Native FBX → GLB conversion (runs server-side via Node)
express ^5.2.1 Local HTTP server that exposes the FBX conversion endpoint
cors ^2.8.6 CORS headers for the local converter server
concurrently ^10.0.0 Run Vite dev server and Node converter server in parallel with npm run dev

Dev

Library Version Role
vite ^5.0.0 Dev server and production bundler
playwright ^1.60.0 End-to-end testing

WASM (bundled)

Library Role
XAtlas UV atlas generation — packs all mesh primitives into a non-overlapping UV2 lightmap atlas. Runs as a WASM module in the browser.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors