Baking static light into textures is one of the most impactful optimizations a game developer can make — and Godot 4's LightmapGI system makes the process accessible without sacrificing quality. This guide walks through the complete workflow: scene setup, texel density tuning, baking parameters, and squeezing the best results from low-end and mobile targets.
Setting up your scene for LightmapGI
Before you bake a single photon, your scene geometry needs to be ready. LightmapGI requires every mesh that will receive baked light to have a dedicated UV2 channel — a non-overlapping unwrap that the baker writes shadow and GI data into.
![]()
In Blender, generate a lightmap UV before exporting to GLB:
# Blender Python — auto-generate lightmap UVs for selected meshes
import bpy
for obj in bpy.context.selected_objects:
if obj.type == 'MESH':
bpy.context.view_layer.objects.active = obj
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.uv.lightmap_pack(
PREF_CONTEXT='ALL_FACES',
PREF_PACK_IN_ONE=True,
PREF_NEW_UVLAYER=True,
PREF_MARGIN_DIV=0.1
)
bpy.ops.object.mode_set(mode='OBJECT')
Alternatively, enable Lightmap Unwrap on import inside Godot's import settings (Scene tab → Lightmap → generate_lightmap_uvs: true). This works for simple meshes but gives less control over seam placement and texel distribution on complex geometry.
Scene setup checklist before baking:
- All static geometry set to Static mode (top of the Inspector)
GeometryInstance3D.gi_modeset toSTATIC(notDYNAMICorDISABLED)MeshInstance3Dnodes haveUV2present — check in the Mesh resource inspector- Lights contributing to bake have
LightmapGIDatamode enabled (default forDirectionalLight3DandOmniLight3D) - Sky contribution: set your
WorldEnvironmentsky before baking — it contributes indirect light
LightmapGI node placement
Add a single LightmapGI node to the root of your scene (not nested under any geometry). Key properties:
| Property | Recommended starting value | Notes |
|---|---|---|
Quality | Medium | High for final bake, Low for iteration |
Bounces | 2–3 | 1 bounce for indoor-only scenes |
Texel Scale | 1.0 | Increase for higher resolution |
Max Texture Size | 4096 | 8192 only if texture budget allows |
Environment Mode | Scene | Uses your WorldEnvironment sky |
Interior | false | Enable for fully enclosed spaces |
Baking lightmaps with LightmapGI
With the scene prepared, bake from Scene → Bake Lightmaps (or the LightmapGI node's "Bake" button). Godot writes a .lmbake file containing packed light data textures into your project.
![]()
Texel density is the most important quality lever. Higher Texel Scale means more lightmap pixels per world unit — sharper shadow edges but larger texture memory.
# Rule of thumb for texel scale by asset type
Small props (< 0.5m): Texel Scale 0.5–1.0
Room-scale geometry: Texel Scale 1.0–2.0
Exterior terrain: Texel Scale 0.25–0.5
Character (rare): Texel Scale 2.0–4.0
Probes: LightmapGI automatically scatters Lightmap Probes for dynamic objects. Add LightmapProbe nodes manually near areas with strong light variation (doorways, windows, under arches). Dynamic MeshInstance3D nodes (gi_mode = DYNAMIC) sample these probes at runtime with zero performance cost versus fully dynamic GI.
Common baking pitfalls
- Dark patches under small gaps: increase
Bouncesto 3 and enableEnvironment Mode: Scene - Seam artifacts at UV islands: increase margin in UV2 unwrap; add padding in Blender's lightmap pack
- Blotchy indirect light: raise
Qualityto High or increase probe density with manualLightmapProbenodes - Build time too long: reduce
Max Texture Sizeto 2048 during iteration; only bake at 4096+ for final build
Optimizing baked light for mobile and low-end targets
On mobile (Android/iOS) and low-spec desktop, lightmap texture memory is your main constraint. A 4096×4096 lightmap at RGBA8 costs 64 MB uncompressed — multiply that by slice count and you're over budget fast.
Compression settings: in Project Settings → Rendering → Lightmapping, enable Compress Lightmaps (on by default). Godot uses ETC2 on mobile (OpenGL ES 3.0+) and BC6H on desktop Vulkan. Both cut lightmap memory by ~6×.
Atlas packing: Godot automatically packs multiple meshes into shared lightmap atlases. You can check the final atlas layout with the lmbake file — import it as a texture to inspect packing efficiency. If atlas utilization is below ~70%, reduce Max Texture Size and let the packer use more, smaller textures.
Per-mesh lightmap scale: override lightmap resolution per mesh with GeometryInstance3D.lightmap_scale. Set small or distant props to 0.5× or even 0.25× to free up atlas space for hero geometry.
# GDScript — reduce lightmap scale for distant props at runtime
func set_lod_lightmap_scale(mesh: MeshInstance3D, distance: float) -> void:
if distance > 30.0:
mesh.lightmap_scale = GeometryInstance3D.LIGHTMAP_SCALE_2X # 0.5x
elif distance > 15.0:
mesh.lightmap_scale = GeometryInstance3D.LIGHTMAP_SCALE_1X # default
Mobile bake targets checklist:
- Total lightmap atlas memory < 128 MB (sum all atlases × 2 bytes/px for ETC2)
Interior: truefor enclosed scenes — skips expensive sky samplingBounces: 1on low-end targets — single bounce captures 85% of indirect lightQuality: Low+ upscale with denoiser for fast iteration on mobile hardware
Lightmap baking in Godot 4: quick reference
Assets from BitSoul's marketplace ship with correct UV2 data already embedded in the GLB, so you can drop them into a scene, add a LightmapGI node, and bake immediately without touching Blender. Scenes built entirely from BitSoul assets can typically achieve a complete lightmap bake in under 5 minutes on modern hardware.
For full scene integration guidance and ready-to-bake environment kits, browse the BitSoul marketplace — all 747 models are GLB format with engine-ready UV2 channels.
This post is part of the Ultimate Guide to Free 3D Game Assets — BitSoul's complete reference for formats, texturing, rigging, optimization, and engine integration.
Need drop-in assets for this workflow? Grab the 70-model Food Bundle on the BitSoul marketplace and drop them straight into your project.