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

[rmodels] Meshes doesn't reliably represent gltf/m3d/obj/vox data #4650

Closed
rmn20 opened this issue Dec 29, 2024 · 4 comments
Closed

[rmodels] Meshes doesn't reliably represent gltf/m3d/obj/vox data #4650

rmn20 opened this issue Dec 29, 2024 · 4 comments

Comments

@rmn20
Copy link
Contributor

rmn20 commented Dec 29, 2024

Issue description

Current raylib Mesh structure is limited to only one material, while most 3D model formats supported by raylib (all except vox and iqm) allow the use of multiple materials per Mesh.
This limitation disables the direct association between meshes in the model files and the raylib meshes, since meshes with multiple materials had to be split to multiple raylib meshes to be fully represented. Moreover, I tested models in different formats, and formats workaround this problem in different ways by joining or splitting meshes in a unique way, making working with meshes in raylib even more unreliable.

Testing of each model format

I created a simple model consisting of 3 meshes:

  1. Green cube (1 material)
  2. White cube (1 material)
  3. Multicolor cube (2 materials)

image

I exported/converted model into several file formats and tested how each would work in raylib:

  1. IQM
    While IQM stores only one material per mesh (see IQM specs) I still decided to check how it would work.
    Obviously meshes with multiple materials got separated into multiple meshes on model convertation stage, but this is expected behavior.
    For some reason Z and Y axes got swapped but I think this is intended? Can't say for sure with this rare format.
    Meshes got loaded in raylib in correct order, but it looks like raylib doesn't account for IQM materials and just create separate material for each IQM mesh.
  2. M3D
    M3D specs allow for models with multiple meshes with multiple materials, but for some reason both m3dconv and io_scene_m3d Blender plugin combine all meshes into one when converting Wavefront OBJ to M3D (I checked this using m3dconv builtin validation tool).
    Also it looks like m3d.h from M3D SDK doesn't allow to load meshes separately anyways, so I don't think raylib has to do anything with this.
  3. GLTF / GLB
    Meshes got loaded in correct order, but meshes with multiple materials got split into multiple raylib meshes, resulting in this mesh list:
    1. Green cube mesh
    2. White cube mesh
    3. White part of multicolor cube mesh
    4. Green part of multicolor cube mesh
  4. OBJ
    For some reason all materials specified in OBJ file is ignored and joined if MTL file is not present. I think that even tho material file is not present material names from OBJ file itself still can be useful for end user (maybe material name field can be added to raylib Material structure?).
    This one is really weird. While original mesh order is present in raylib, meshes got joined and separated into multiple raylib meshes in some weird way, resulting in this mesh list:
    1. First half of green cube mesh
    2. Second half of green cube mesh
    3. White cube combined with white part of multicolor cube mesh
    4. Green part of multicolor cube mesh
  5. VOX
    While MagicaVoxel file format doesn't have materials at all it still allows for multiple "models" in one file, so I decided to try it too and created a project with 3 cube models in MagicaVoxel.
    For some reason raylib loads only last model provided in VOX file.

Why this is important?

Establishing a direct association between meshes in the model file and raylib meshes is important because it will allow users to reliably and efficiently use and manage model meshes in raylib.

For example, the end user would be able to save the entire level model in a single file and use different meshes as different level zones, disabling or enabling rendering of specified meshes for optimization purposes.
Or, if we are talking about small props on the level, user could store multiple LODs in a single file as separate meshes and render only selected mesh.
Separate meshes also could be used to add variety to game without complicating the editing and loading of models. For example, you could switch accessories or weapons on enemy/npc/player models or on some background props. Meshes could also be used for key frame animation on models, such as in the original Quake, but this applies only to retro-styled games.

Of course, all this is possible in the current version of raylib, but it requires user to spend additional time researching each model format supported by raylib to find out which one is most stable in raylib, and to practically limit use of materials, since they can easily break mesh indexing.

How this can be fixed?

Obviously, the model loading needs to be improved.
There are several ways how raylib meshes could represent model meshes better.
The straightforward way is to add multiple materials support to the Mesh structure itself, by replacing almost all fields with arrays of these fields... Or you could move the data from the Mesh structure to a new structure named Submesh and just store the array of submeshes in the Mesh structure. Obviously, one way or another, this is a breaking change.
Another way is to store an additional array of integers in the Model structure with indexes of Meshes in original model file. This shouldn't cause breaking changes, but I don't think this method is really convenient.

Environment

I checked both 5.5 and 5.6-dev (commit f355d6f) raylib versions.

Platform backend: DESKTOP (GLFW)
GL: OpenGL device information:
> Vendor:   NVIDIA Corporation
> Renderer: NVIDIA GeForce GTX 1660 Ti/PCIe/SSE2
> Version:  3.3.0 NVIDIA 566.03
> GLSL:     3.30 NVIDIA via Cg compiler
GL: VAO extension detected, VAO functions loaded successfully
GL: NPOT textures extension detected, full NPOT textures supported
GL: DXT compressed textures supported
GL: ETC2/EAC compressed textures supported

Code and model examples

This archive contains the aforementioned model in several file format and a simple raylib application that loads model file and allows to switch between different meshes.

@raysan5 raysan5 changed the title [rmodels] Raylib meshes doesn't reliably represent gltf/m3d/obj/vox meshes [rmodels] Meshes doesn't reliably represent gltf/m3d/obj/vox data Dec 29, 2024
@raysan5
Copy link
Owner

raysan5 commented Dec 29, 2024

@rmn20 raylib is focused on simplicity and current approach follows that line. Supporting multiple materials "per mesh" actually means supporting differents materials per groups of triangles, that, in practice, it's the same as splitting to multiple meshes. Afaik, it's not possible to support multiple Materials by the same Mesh, and even if it was possible it would require multiple render passes and a more advance rendering pipeline.

Establishing a direct association between meshes in the model file and raylib meshes is important because it will allow users to reliably and efficiently use and manage model meshes in raylib.

I do not agree with this statement. A model file-format is an intermediate format and it must be always adapted to the native engine supported format, in this case, raylib, despite its potential limitations.

The straightforward way is to add multiple materials support to the Mesh structure itself, by replacing almost all fields with arrays of these fields.

I'm afraid this is out of scope for raylib, and sincerely I can't see the use-case for multiple Materials per Mesh, could you provide some example?

@rmn20
Copy link
Contributor Author

rmn20 commented Dec 29, 2024

@raysan5

Supporting multiple materials "per mesh" actually means supporting different materials per groups of triangles, that, in practice, it's the same as splitting to multiple meshes.

Yep, it is, no advanced rendering is required. It's just about more convenient data structure that would group submeshes with different materials into one mesh structure for simplified usage and direct mapping between raylib meshes and meshes in model file.

I'm afraid this is out of scope for raylib, and sincerely I can't see the use-case for multiple Materials per Mesh, could you provide some example?

Some of the more obvious examples:

  1. Multiple materials can be useful for level meshes. Texture atlases aren't always convenient because they doesn't allow for texture tiling, so you'll had to use a lot of materials for more complex levels with different textures. I already mentioned how meshes could be used for splitting levels into zones for optimization purposes.
  2. Same thing applies to props with LODs or NPCs with accessories, multiple materials can be required if several textures or shaders are used per object.

@rmn20
Copy link
Contributor Author

rmn20 commented Dec 29, 2024

Just a quick note: LODs can use different amount of materials than the base mesh

@JeffM2501
Copy link
Contributor

JeffM2501 commented Dec 31, 2024

This all sounds way out of scope for what the model structure is designed to do.
There are many use cases of mesh outside of model.
A mesh is a draw call, thus it has one material.
It sounds more like what you want is groups of meshes for manipulation, and that's understandable, but that's not what a model does. That would be a specific use case that you'd handle yourself.

Raylib is not an engine.

@raysan5 raysan5 closed this as completed Dec 31, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants