bevyengine / bevy

A refreshingly simple data-driven game engine built in Rust
https://bevyengine.org
Apache License 2.0
35.85k stars 3.54k forks source link

Add a Bevy-native tool to generate (and bake) global illumination for light maps #12233

Open alice-i-cecile opened 7 months ago

alice-i-cecile commented 7 months ago

What problem does this solve or what need does it fill?

Light maps (cube maps, irradiance volumes, reflection probes) are a class of assets used to "fake" pretty but expensive global illumination. Bevy has support for these now, but as #10057 says, we have no way to generate them ourselves:

An easy way to generate reflection probe cubemaps is to bake them in Blender and use the export-blender-gi tool that's part of the bevy-baked-gi project. This tool takes a .blend file containing baked cubemaps as input and exports cubemap images, pre-filtered with an embedded fork of the glTF IBL Sampler, alongside a corresponding .scn.ron file that the scene spawner can use to recreate the reflection probes.

What solution would you like?

  1. Add features for global illumination to Bevy, even if they're slow.
  2. Add a tool to generate the lightmaps and export them as assets.
  3. Teach users how to use this workflow.

This is tagged with A-Editor, as while it is possible to do this using a non-GUI solution, it makes more sense as a component of a larger scene editor.

What alternative(s) have you considered?

Existing third-party light baking tools exist, and can be used with Bevy.

These are generally harder to customize / integrate, and cannot be used to dynamically generate lightmaps as part of procedurally generated environments.

Additional context

Pre-existing work:

pcwalton commented 7 months ago

In order of difficulty, what would need to be done is:

  1. Write a reflection probe baker. This is pretty simple: just load a scene, render all 6 sides of a cubemap, run the results through the glTF IBL Sampler, and save the results to .ktx2.

  2. Write an irradiance volume baker. This is a bit more involved than (1), but still not too hard. The easiest approach would be to, for every voxel location, render a cubemap in which each side is, say, 32x32, and then average all the colors of every side together to reduce the cubemap to 1x1. This would work, but would be slow (however, it wouldn't be that slow: it would still probably only take a few seconds).

  3. Write a lightmap baker. This is a lot more involved. You'll want to start with some sort of GI solution, for example bevy_solari or strolle. For each lightmapped object, initialize a blank light map texture. Then path trace every pixel on that texture, and save the results as an image. As a followup, you'll probably want to integrate xatlas to generate the UVs and a denoiser like OpenImageDenoise.

JMS55 commented 7 months ago

I made a PR to replace gltf-ibl-sampler, but it didn't work well on all environment maps and I've shelved it for now due to lack of motivation https://github.com/bevyengine/bevy/pull/9414.

viridia commented 7 months ago

I've contemplated posting my environment maps to Discord and asking if anyone would be willing to convert them :)

viridia commented 7 months ago

BTW, three.js has a PMREMGenerator written in JavaScript which does something similar to what we want:

https://github.com/mrdoob/three.js/blob/master/src/extras/PMREMGenerator.js