Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow Baking OccluderInstances from script #4316

Open
timshannon opened this issue Mar 31, 2022 · 6 comments · May be fixed by godotengine/godot#90590
Open

Allow Baking OccluderInstances from script #4316

timshannon opened this issue Mar 31, 2022 · 6 comments · May be fixed by godotengine/godot#90590

Comments

@timshannon
Copy link

Describe the project you are working on

A 3D FPS with procedurally generated levels.

Describe the problem or limitation you are having in your project

With procedurally generated geometry you have to manually add the occluder geometry to the ArrayOccluder3D by setting the Arrays value.

This works fine, but you miss out on the mesh simplification done during the Editor Bake. Also the simplification used isn't exposed anywhere you can access it in a script (that I can find, please correct me if I'm wrong here).

Describe the feature / enhancement and how it helps to overcome the problem or limitation

Expose the bake_scene(Node *p_from_node, String p_occluder_path = "") method to scripts.

From there you could call it on the fly, or via a scene import script.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

Expose the bake_scene(Node *p_from_node, String p_occluder_path = "") method to scripts.

If this enhancement will not be used often, can it be worked around with a few lines of script?

A 1 to 1 behavior can't be replicated from scripts because we don't have access to the simplification features in the SurfaceTool.

Is there a reason why this should be core and not an add-on in the asset library?

It could probably be done in an addon, but it'd be an addon that simply exposes an existing method to scripts.

@Calinou
Copy link
Member

Calinou commented Mar 31, 2022

cc @JFonS, who implemented occluder simplification on bake in godotengine/godot#57627.

Is meshoptimizer compiled in release export templates? If not, mesh simplification at run-time will not work in an exported project. This might be worth checking with SurfaceTool as well.
If this isn't done already, I think meshoptimiser should be available in exported projects – it probably doesn't impact binary size too much.

@timshannon
Copy link
Author

FWIW, It looks like SurfaceTool exposes a generate_lod method that I think possibly uses the same meshoptimizer library.

@Calinou
Copy link
Member

Calinou commented Apr 5, 2022

FWIW, It looks like SurfaceTool exposes a generate_lod method that I think possibly uses the same meshoptimizer library.

Indeed, it uses meshoptimizer behind the scenes.

@timshannon
Copy link
Author

If anyone is trying to do something similar, this is the solution I came up with that appears to be working fine for me:

private void AddLevelOccluderInstance()
    {
        var instance = new OccluderInstance3D();
        instance.Name = "OccluderInstance3D";
        _root.AddChild(instance);
        instance.Owner = _root;
        var occluder = new ArrayOccluder3D();
        var occSt = new SurfaceTool();

        RecurseTreeOfType<MeshInstance3D>(_root, (mesh) =>
        {
            if (!IsPartialStructureMesh(mesh))
                return;

            var st = new SurfaceTool();

            var m = mesh.Mesh;
            var blnFound = false;

            for (var i = 0; i < m.GetSurfaceCount(); i++)
            {
                var mat = m.SurfaceGetMaterial(i) as StandardMaterial3D;
                if (mat == null)
                    continue;
                if (mat.Transparency != StandardMaterial3D.TransparencyEnum.Disabled)
                    continue;

                st.AppendFrom(m, i, Transform3D.Identity);
                blnFound = true;
            }

            if (!blnFound)
                return;

            var arr = st.CommitToArrays();
            var simplified = st.GenerateLod(0.1f);
            arr[(int)ArrayMesh.ArrayType.Index] = simplified;
            var smesh = new ArrayMesh();
            smesh.AddSurfaceFromArrays(Mesh.PrimitiveType.Triangles, arr);

            for (var i = 0; i < smesh.GetSurfaceCount(); i++)
                occSt.AppendFrom(smesh, i, GetLocalRootTransform(mesh));
        });

        var arr = occSt.CommitToArrays();
        var vertices = (Vector3[])arr[(int)ArrayMesh.ArrayType.Vertex];
        var indices = (int[])arr[(int)ArrayMesh.ArrayType.Index];

        occluder.SetArrays(vertices, indices);
        instance.Occluder = occluder;
    }

@cybernaut4
Copy link

cybernaut4 commented Aug 12, 2023

Would be great to have this implemented in one built-in function like BakeOccluders()

Because it currently asks where to save it, a path parameter would suffice:

occluderInstance3D.BakeOccluders("res://Assets/LevelMaps/Level1.occ")

Tools that auto-generate geometry (like Qodot) would benefit from this: I would press the "Full Build" button so that it generates lots of custom-defined groups of geometry from a .map file (a level designing format) and automatically bake their occluders while at it.

The current state would have me add each OccluderInstance child and hit the Bake Occluders button on every single wrapping Node3D in every re-generation. In advanced map prototyping, I'd have to repeat this about 100 times if I wanted the occluders working after every change.

@TrueJole
Copy link

TrueJole commented Aug 27, 2024

Would be great to at least be able to bake via a @tool script so that I don't have to open the large world scene anytime I change geometry.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants