godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
91.14k stars 21.19k forks source link

Can't bake lightmaps on a MultiMeshInstance at all #48909

Open TheUltimateAbsol opened 3 years ago

TheUltimateAbsol commented 3 years ago

Godot version: 3.3.0

OS/device including version:

Tested on both GLES2 and GLES3, Windows 10, Intel integrated graphics

Issue description:

I can't bake a lightmap into a MultiMeshInstance. Nor can I use a MultiMeshInstance in a lightmap. Given that I can bake a GridMap, I was under the impression I could bake a MultiMeshInstance as well.

Steps to reproduce:

  1. Create a scene with a light source, BakedLightmap, and MultiMesh
  2. Ensure the MutliMesh is using an ArrayMesh with the UV2 unwrapped for BakedLightMaps by adding it to a regular mesh and clicking "Unwrap UV2 for Lightmap/AO"
  3. Set the used_in_baked_light and generate_lightmap options to true
  4. Bake the lightmap
  5. Multimesh is excluded entirely

Minimal reproduction project:

This issue is actually already covered in #45313, although the poster doesn't seem to aware at all (likely because the SSAO in the sample project made it look like the MultiMeshInstance casted a shadow)

Here's a simpler project: bakedlighmap_test.zip

image

This is an image of the scene after I bake the indirect light and then turn the directional light off. The lefthand side is a bunch of individual meshes (indirect light off the spheres is saved, as desired) The middle is a multimesh (nothing is saved) The left is a single sphere (for reference)

TheUltimateAbsol commented 3 years ago

Here's a workaround if all you want to do is have the multimesh in the baked lightmap but not contain a lightmap of its own

Create a Spatial in your scene with the following script:

tool
extends Spatial

export(bool) var running = false setget set_running

func get_all_multimeshes(node, list=[]):
    if node is MultiMeshInstance: 
        list.append(node)
    for child in node.get_children():
        get_all_multimeshes(child, list)
    return list

func set_running(value):
    running = value
    if running:
        var multi_meshes = get_all_multimeshes(get_tree().get_root())
        for multi_mesh in multi_meshes:
            for i in range(multi_mesh.multimesh.instance_count):
                var global_xform = multi_mesh.global_transform*multi_mesh.multimesh.get_instance_transform(i)
                var mesh = MeshInstance.new()
                mesh.mesh = multi_mesh.multimesh.mesh
                mesh.global_transform = global_xform
                add_child(mesh)
                mesh.set_owner(self)
                mesh.use_in_baked_light = true
                mesh.generate_lightmap = false
        running = false

In the editor, click the "running" checkbox and set it equal to "true". This will essentially create a copy of every multimesh in your scene and convert it to a regular mesh that will take part in lighting calculations. Then you can bake lightmaps as usual

The meshes are a temporary copy that will disappear after you reload your scene.

JFonS commented 3 years ago

@TheUltimateAbsol Baking of MultiMeshInstances is not supported right now, so the only way to getting what you need is indeed some script like the one you shared.

It would be nice to support baking for MultimeshInstance, so I will add it to my list of things to improve, but it's not very high priority, so I can't promise I will work on it soon. However, if anyone is interested in taking a stab at it, I'll be happy to help and give pointers to what needs to be changed.

stilobique commented 3 years ago

@TheUltimateAbsol Baking of MultiMeshInstances is not supported right now, so the only way to getting what you need is indeed some script like the one you shared.

It would be nice to support baking for MultimeshInstance, so I will add it to my list of things to improve, but it's not very high priority, so I can't promise I will work on it soon. However, if anyone is interested in taking a stab at it, I'll be happy to help and give pointers to what needs to be changed.

Oh, bad news to read that. Have you a dedicated roadmap with features planned anywhere ? Thanks to sharing your script @TheUltimateAbsol.

darthLeviN commented 2 years ago

Is it possible to export the meshes as a gltf and import the gltf and then unwrap uv and use that for baking?

I have done that with basic godot generated meshes and it worked since godot generated meshes don't have a UV 2.

I mean my solution is not gonna be great but it will do for the urgent need

vzuzik commented 1 year ago

Maybe it's be interesting. I'm implemented lightmap baking for multimesh instances for gles2 renderer (yet not implemented for gles3). Lot of work was done, but feature working pretty well in my opinion. How it works - default lightmap baker create lots of image for each instance. At the next step instead of saving that images on disk the baker pack that images into a single large lightmap image (max 4096x4096), assing uv rectangles for each instance and saving that image on disk as "lightmap for multimesh instance" Don't know how its fits for submitting into engine sources (implementation has some stricts. Most significant - just one lightmap 4096x4096 on MultiMeshInstance) Editor viewport: image Generated lightmap for multimesh instance (spheres - 62x992 pixels) : image