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

BatchedMesh: Add geometry groups support and multi material handling #27930

Open
minitoine opened this issue Mar 16, 2024 · 1 comment
Open

Comments

@minitoine
Copy link

minitoine commented Mar 16, 2024

Description

I've tried to read all the discussions and PRs about the recent addition of BatchedMesh to Three.js.

There is still a WIP, or at least questions, about how geometry groups support could be added.
I might have a solution, that I am already using in my own version of BatchedMesh (was developing it before BatchedMesh was added).

If I understand correctly the current state of BatchedMesh:

  • We have support for multi_draw extension if the browser supports it
  • Objects matrices are stored in a texture and used directly in the shader (useful to transform objects)
  • A unique material can be used, and in addition

The main goal is to be able to change the opacity per object (or proxy) embedded in the BatchedMesh.

Solution

To support multiple geometry groups, what I've done is

  • I can give the mesh an array of materials
  • I can assign a material index to each proxy (i.e. virtual objets) and store them in an array. For example [0, 1, 1, 0, 0, 2, 1] for 7 proxies and 3 materials
  • I create/update geometry groups on-the-fly depending on the material index array. Groups are presented as successive and cumulative buffer ranges of the same material.
    • In the example just above, we have 5 groups: [0 for 1 proxy, 1 for 2 proxies, 0 for 2 proxies, 2 for 1 proxy, 1 for 1 proxy].
    • For each group we have a distinct gpu draw call
  • Our goal is then to reduce the number of groups
    • we can do this by optimizing the BatchedMesh geometry
      • that optimization can take into account the defragmentation implementation that will come to BatchedMesh (it is already planed as I understood) to remove empty spaces
      • that optimization can also reindex the index buffer so that we order the proxies regarding their material index
        • in the example above, we would have [0, 0, 0, 1, 1, 1, 2], 3 groups for 3 materials
  • Reorganizing the index buffer can be done quick enough to be done in realtime, or on demand. Can also be done (this is what I do) in a webworker with ArrayBuffer transfer, or even better, with SharedArrayBuffer.
  • Reorganizing the index buffer does not break the three-mesh-bvh library, as a indirect buffer option is now available to store the BVH into a separate index buffer.
  • Using Material texture is still compatible with an array of materials.
  • Materials without visibility can be sorted at the end of the index and we can use drawRange to hide the objet (this is an alternative to multi draw)

I already have such implementation in my project (without multi draw, I use non-visible materials instead) and I can change transparency per objet on-the-fly.

Alternatives

Currently, if I understand correctly what has been done, it is possible to use a transparent material for the BatchedMesh, and use RGBA values for vertexColors buffer to control per-object opacity. Problem is that opaque objects will be drawn with transparent objects, failing a correct drawing order, and will lead to gpu overdraw (DoubleSide drawing for opaque objects for example)

Additional context

I will be glad to contribute to improve BatchedMesh implementation and rely on it in my own project. Are you interested in this idea ? Feel free to comment and expose alternatives.

@gkjohnson
Copy link
Collaborator

gkjohnson commented Mar 18, 2024

I believe this is effectively a duplicate of #27203.

A unique material can be used, and in addition

Only a single material can be used across all geometry in the BatchedMesh. The demo from #27170 (comment) just demonstrates how a material can be modified to support different surface properties by packing them into a texture.

BatchedMesh is designed to minimize draw calls so I don't support changing the implementation to support an arbitrary number of materials which results separate draw calls, defeating the purpose of the class.

As I mention in #27203 it may be possible to shift the separate geometry tracking to the geometry object and share that among BatchedMesh instances so different materials can be used. But this hasn't been completely thought though. With the current BatchedMesh implementation in WebGLRenderer it should be possible to implement a custom version of the class with some of the behavior your reference without further changes to core. I think a clear API design and prototype should be demonstrated before more work is considered for this.

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

No branches or pull requests

3 participants