godotengine / godot-docs

Godot Engine official documentation
https://docs.godotengine.org
Other
3.94k stars 3.22k forks source link

MultiMeshInstance2D useage needs to be documented #5967

Open golddotasksquestions opened 2 years ago

golddotasksquestions commented 2 years ago

Your Godot version: 3.4, 3.5, 4.0 Alpha

Issue description: There is not really any documentation on how to use the MuliMeshInstance2D node. Currently the MultiMeshInstance2D docs pages says "just like 3D", but this is actually not at all the case.

The closest thing to an explanation can be found in the Optimizing Multimesh tutorial page, but this only features an example for MultiMeshInstance, so the 3D variant. This example does not work for MultiMeshInstance2D and trying to translate this is not an easy job for someone who has not worked in 3D extensively yet.

Many people learn Godot 2D before 3D, so it's wrong to expect people to bring extensive 3D knowledge for a 2D feature.

I had this issue for years and I'm not the only one. Reddit example. This is an issue, because MultiMeshInstance2D are a powerful tool, but since virtually undocumented the are underutilized by the community and then people blame the engine for not being capable of delivering good performance.

URL to the documentation page (if already existing): https://docs.godotengine.org/en/stable/classes/class_multimeshinstance2d.html https://docs.godotengine.org/en/3.5/classes/class_multimeshinstance2d.html https://docs.godotengine.org/en/latest/classes/class_multimeshinstance2d.html

YuriSizov commented 2 years ago

To use it you basically need to create a shape by hand from triangles and ArrayMesh. Then do everything else in code, just like in 3D. For example, here's how I did it with a texture displayed on a rectangle (the texture itself set in the scene):

    multimesh_node.multimesh.instance_count = 0
    multimesh_node.multimesh.custom_data_format = MultiMesh.CUSTOM_DATA_FLOAT
    multimesh_node.multimesh.color_format = MultiMesh.COLOR_FLOAT
    multimesh_node.multimesh.instance_count = _actual_instance_count

    var arrays = []
    arrays.resize(ArrayMesh.ARRAY_MAX)

    var vertices = PoolVector2Array()

    vertices.push_back(Vector2(-BALLOT_SIZE, -BALLOT_SIZE))
    vertices.push_back(Vector2(BALLOT_SIZE, -BALLOT_SIZE))
    vertices.push_back(Vector2(-BALLOT_SIZE, BALLOT_SIZE))

    vertices.push_back(Vector2(BALLOT_SIZE, -BALLOT_SIZE))
    vertices.push_back(Vector2(BALLOT_SIZE, BALLOT_SIZE))
    vertices.push_back(Vector2(-BALLOT_SIZE, BALLOT_SIZE))

    arrays[ArrayMesh.ARRAY_VERTEX] = vertices

    var uvs = PoolVector2Array()

    uvs.push_back(Vector2(0.0, 0.0))
    uvs.push_back(Vector2(1.0, 0.0))
    uvs.push_back(Vector2(0.0, 1.0))

    uvs.push_back(Vector2(1.0, 0.0))
    uvs.push_back(Vector2(1.0, 1.0))
    uvs.push_back(Vector2(0.0, 1.0))

    arrays[ArrayMesh.ARRAY_TEX_UV] = uvs

    var mesh = ArrayMesh.new()
    mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays)
    multimesh_node.multimesh.mesh = mesh

It's not very intuitive, to say the least, but it's workable. You can also create a mesh from any sprite in the editor's toolbar and copy that data to your multimesh.

golddotasksquestions commented 2 years ago

@YuriSizov Thanks for the example code! You can use MultiMeshInstance2D with a lot more than just ArrayMesh. Using it with ArrayMesh is definitely not the most basic usecase. Like I have explained in my comment in the above linked Reddit post, a simple example using the built-in QuadMesh is fine and a good starting point.

Docs should aim for the most basic easiest use first imho.

YuriSizov commented 2 years ago

You can use MultiMeshInstance2D with a lot more than just ArrayMesh.

You probably can, but that's the only example that I've found online when looking for this same information. You still need to create things in code, I think. I believe I tried creating a quad mesh from the inspector before searching for the answer, and it didn't work for me, or at least it didn't properly display in the editor.

golddotasksquestions commented 2 years ago

You still need to create things in code, I think

You don't actually. See my comment in the Reddit post I linked.

or at least it didn't properly display in the editor.

Very likely it just did not look to you like it worked because the default QuadMesh size is 1x1. If you add the icon.png for example you need to also set the QuadMesh size to 64x64

YuriSizov commented 2 years ago

I've seen your post, and yes, you obviously need to give it a size. But I'm pretty sure it still didn't draw or didn't take the texture in my case.

Either way, yes, this needs to be documented. And possibly the editor needs to be adjusted too to make sure everything works in the 2D context.

clayjohn commented 2 years ago

You can use MultiMeshInstance2D with a lot more than just ArrayMesh. Using it with ArrayMesh is definitely not the most basic usecase. Like I have explained in my comment in the above linked Reddit post, a simple example using the built-in QuadMesh is fine and a good starting point.

Your right this needs to be documented better. QuadMesh is actually problematic when used with MultiMeshInstance2D (and MeshInstance2D) as internally it is still treated as a 3D node for the purposes of calculating an AABB/bounding rect. This leads to issues with the mesh getting improperly culled when it should be visible.

The current best approach is either to use a 2D mesh constructed in code (you can construct it once in code and then use the ResourceSaver to save it) Or to use the Sprite->Mesh converter. I.e. set your texture onto a Sprite, convert the Sprite into a MeshInstance2D using the button in the Toolbar and then use the resulting Mesh in your MultiMesh.

golddotasksquestions commented 2 years ago

This leads to issues with the mesh getting improperly culled when it should be visible.

So far I did not notice this issue in my tests, but thanks for mentioning it. Documenting this as well would definitely be a good idea.