qmuntal / gltf

Go library for encoding glTF 2.0 files
https://www.khronos.org/gltf/
BSD 2-Clause "Simplified" License
242 stars 32 forks source link

Add high level API for reading GLTF #26

Closed finnbear closed 3 years ago

finnbear commented 3 years ago

This is similar to #15 except that that was regarding a way to create a GLTF document whereas I would like a way to read GTLF document without any knowledge of GLTF.

The ideal API for me would take a document, a mesh index, and return vertices, normals, uvs, material indices, etc.

You could call the package scanner, reader, inspector, etc.

qmuntal commented 3 years ago

This proposal also makes sense, one does need to have a lot of glTF knowledge to decode common attributes, such as position and colours.

Yet this high level reader should maintain the glTF data model, it will just help decoding the binary buffers into higher level entities by using gltf/binary, therefore it will still require some glTF knowledge.

qmuntal commented 3 years ago

@finnbear I´ve added a new modeler.Read* api in v0.17.0. It does not work with meshes but with accessors, as I wanted to start from the bottom (bufferviews and accessors) and leave the higher level models (primitives and meshes) for the end. I´ll continue the work when I find enough inspiration.

Take a look at this new release, maybe it does meet your needs already.

finnbear commented 3 years ago

Take a look at this new release, maybe it does meet your needs already.

Thank you very much! I'll download the latest changes and try implementing my project again. I think I'll be able to say soon whether it meets my needs.

finnbear commented 3 years ago

Alright, I was able to implement basic reading of positions from my GLTF file:

package main

import (
    "fmt"
    "github.com/qmuntal/gltf"
    "github.com/qmuntal/gltf/modeler"
    "log"
)

var (
    objectPath = "../../objects/molding.glb"
)

func main() {
    doc, err := gltf.Open(objectPath)
    if err != nil {
        log.Fatal(err)
    }
    mesh := doc.Meshes[0]
    primitive := mesh.Primitives[0]
    positionIndex := primitive.Attributes["POSITION"]
    positionAccessor := doc.Accessors[positionIndex]
    positions, err := modeler.ReadPosition(doc, positionAccessor, nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%#v", positions)
}

I think this meets my basic needs, but I do have some suggestions:

  1. Consider making modeler.Read*(...) take the document and the index of the accessor, not the document and the accessor. It seems like the client has to dereference the accessor unecessarily (in my case, the positionAccessor := doc.Accessors[positionIndex] line).
  2. Consider exporting the const strings POSITION, NORMAL, etc. from your library, as they get used a lot to refer to attributes (including in your code, especially the test code).
  3. Please release an example that pretty much does the above (reads positions, possibly normals, from a GLTF file) somewhere in the README or documentation.
  4. While this brings me significantly closer to my goal of reading GLTF files in Go, it still doesn't abstract away every aspect of GLTF. Unfortunately, there is no Go standard (that I'm aware of) for 3d model importers/exporters, like there is for 2d images (the image package, which specific formats can register importers into). I think the thing the realistic next step is to remove the need to think about accessors and skip directly from primitives to positions, normals, etc. (but please take your time to make a well designed API)

Thank you @qmuntal!

Edit: feel free to close this issue

qmuntal commented 3 years ago

@finnbear thanks for the review and sorry for the late response, for whatever reason I did not see the notification.

Some comments about your suggestions:

  1. I already considered accepting the index instead of the accessor pointer, but it has the disadvantage that if someone is just passing the accessor around instead of the index then there is no easy way to know which is the index associated to the accessor.
  2. Will do!
  3. Will do!
  4. This same issue also hits me every time I want to use different file formats. It is in my todo list to create a package that defines a 3D mesh abstraction, but it won't happen in the near future.
EbodShojaei commented 1 year ago

Sorry to reopen this thread as I was looking to ask a question more than raise an “issue”.

1.) Will this package allow me to read and load my .glb file from Go into my THREE.js scene?

2.) Would I need to create my own accessor function to bridge Go to my JavaScript?

3.) Would using your library essentially remove the .glb from public storage and network traffic since it’s loaded with Go at runtime?

Sorry again if these are misinformed questions 😅 I’m new to Go and have been trying to find a way of encapsulating my .glb files to avoid:

I was initially inspired by SketchFab, which uses a proprietary .binz format that I can only assume uses some sort of decryption logic in a custom JavaScript loader.

The closest I saw to what I wanted was this Doom 3 in-browser port that uses JavaScript with WASM. The 3d assets weren’t publicly stored nor transferred network traffic (Link).

I’d love to hear your thoughts! Thank you 🙏