FractalFir / tmf

Tight Model format is an experimental lossy 3D model format focused on reducing file size as much as posible without decreasing visual quality of the viewed model or read speeds.
MIT License
100 stars 6 forks source link

[FEATURE] Support arbitrary vertex attributes #7

Open nicopap opened 1 year ago

nicopap commented 1 year ago

TMF looks super cool!

But I'd not only want to store normal, positions and uvs data. Formats like glTF also store other attributes per vertex, such as: color, tangent, secondary uvs, skeletal animation bone weights.

Game engines do use more than normal position and uvs, and it seems reasonable to expect from a mesh serialization format that it supports additional attributes.

Implementation

I'm conscious this is not a trivial task, because each attribute can have an arbitrary representation. And it probably makes it hard to apply some useful heuristics. So I'm not adventuring to propose an implementation. But the most basic API I'd like is a method on TMFMesh that does:

fn set_attribute<T: VertexAttribute>(&mut self, attribute_id: usize, buffer: &[T]) {}
fn get_attribute<T: VertexAttribte>(&self, attribute_id: usize) -> Option<&[T]> {}

(this is an extremely primitive API that can fairly trivially be improved, not a template for a final API)

A method on VertexAttribute could provide to TMFMesh informations so that it can apply good compression heuristics, and specifically allow erasing the type (so that it could be internally stored as a Box<[u8]> and cast when accessed)

What is this for?

I'm maintaining the bevy_fbx crate and bevy is landing a new asset loader with a post-processing step. The FBX format suuuuucks and is wasteful when it comes to game assets (it even leaks private information), using an intermediary representation *that is fast to write and read from is a necessity tbh.

My fbx loader currently only supports normal positions and uvs, so I already can use TMF! However, storing tangents in the backed meshes would be super useful, it would allow not having to compute tangents at runtime, which can be fairly expensive.

FractalFir commented 1 year ago

Supporting arbitrary vertex attributes would not be hard, but those attributes would receive little to no size reduction due to the compression algorithm requiring a lot of insight into data stored. Since knowing what is stored accounts for most of the savings (normals being unit vectors, uvs being in the range 0.0-1.0), a lot of savings comes from code which differs for each attribute. So custom vertex attributes would be mostly compression-less. The compression-less variant could be added in a couple of work hours.

A much better approach would be to have dedicated format segments for those attributes. Knowing their properties could allow for them to be compressed. Would you mind opening issues for each kind of data your use case requires?

FractalFir commented 1 year ago

d9a5be3b1fcc06bbe8dd896b7f6832eefa2ef592 adds some groundwork for supporting custom mesh data. API will be a bit more involved than the one proposed (many kinds of CustomData), but all custom data will be compressed.

Planned supported data kinds:

  1. CustomIndex
  2. CustomFloat
  3. CustomVetor2
  4. CustomVector3
  5. CustomVector4
  6. CustomColor(Vector4 with components of between 0.0 and 1.0)
  7. CustomUnit2(Vector2 of length 1)
  8. CustomUnit3(Vector3 of length 1)

This data may reuse some of the compression architecture and would be compressed to comparable levels as other mesh data. Each custom segment should have a unique name of between 1 and 255 characters.

nicopap commented 1 year ago

Awesome. This is way beyond any expectation. It's definitively not a deal breaker to not have access to extra attributes, but it's very handy. I'll open a feature request for tangents.

FractalFir commented 1 year ago

d38894d87f54041302fa24c14e893e7052309506 adds support for saving/reading custom indices with a name of up to 255 characters. All the groundwork for saving other data types is there, only thing left to implement is the glue code to decode the data in other types of custom segments.

FractalFir commented 1 year ago

Support for custom float attributes added in a164eb27d4ea822d44e71546b7267f84631f70f7.

FractalFir commented 1 year ago

Support for RGBA colors added in 6f7598a0124fc755ed3fbec757cae0ba8297bbe0.