Closed chrisbward closed 4 months ago
Possible it is, but not implemented in here 😸. You will have to load the model using this library and then implement some custom logic to convert it to a 2d image.
thanks for the quick reply - I had a little fight with chatgippity, of which I had to debug for a while, and ended up with something that might be close?
func (gltfc *GLTFController) RenderToImageAttemptOne() {
// Load the glTF file
doc, err := gltf.Open("./helloworld.gltf")
if err != nil {
log.Fatal(err)
}
// Create a context for rendering
const width = 1024
const height = 768
dc := gg.NewContext(width, height)
// Loop through each scene
for _, scene := range doc.Scenes {
// Loop through each node in the scene
for _, nodeIndex := range scene.Nodes {
// Get the node
node := doc.Nodes[nodeIndex]
// If the node has mesh, render it
if node.Mesh != nil {
renderMesh(dc, *doc.Meshes[*node.Mesh], doc)
}
}
}
// Save the rendered image
if err := dc.SavePNG("output.png"); err != nil {
log.Fatal(err)
}
fmt.Println("Image rendered successfully!")
}
func renderMesh(dc *gg.Context, mesh gltf.Mesh, doc *gltf.Document) {
logrus.Infoln("rendering the mesh")
// Loop through each primitive in the mesh
for _, primitive := range mesh.Primitives {
logrus.Infoln(primitive)
// Get the accessor for the position attribute
// positionAccessor := primitive.GetAttribute("POSITION")
// if positionAccessor == nil {
// continue
// }
positionIndex, found := primitive.Attributes["POSITION"]
if !found {
logrus.Infoln("gltfController - positionindex not found")
continue
}
// Get the accessor for the position attribute
positionAccessor := doc.Accessors[positionIndex]
// Get the buffer view for the accessor
bufferView := doc.BufferViews[*positionAccessor.BufferView]
// Get the buffer data
bufferData := make([]byte, bufferView.ByteLength)
copy(bufferData, doc.Buffers[bufferView.Buffer].Data[bufferView.ByteOffset:])
logrus.Infoln("buffer is", bufferData)
// Assuming position attribute is of type "VEC3"
positions := make([][3]float32, positionAccessor.Count)
for i := 0; i < int(positionAccessor.Count); i++ {
offset := int(positionAccessor.ByteOffset) + i*12 // Assuming VEC3, each component is 4 bytes
logrus.Infoln("offset is ", offset)
positions[i][0] = float32(bufferData[offset])
positions[i][1] = float32(bufferData[offset+4])
positions[i][2] = float32(bufferData[offset+8])
}
logrus.Infoln("positions from buffer", positions, positionAccessor.Count)
// Render each triangle in the primitive
// Get the indices of the primitive
logrus.Infoln("Get the indices of the primitive")
var indices []uint32
if primitive.Indices != nil {
accessor := doc.Accessors[*primitive.Indices]
bufferView := doc.BufferViews[*accessor.BufferView]
bufferData := doc.Buffers[bufferView.Buffer].Data
logrus.Infoln("accessor.ComponentType is ", accessor.ComponentType)
switch accessor.ComponentType {
case gltf.ComponentUbyte: // gltf.ComponentTypeUnsignedByte
logrus.Info("gltf.ComponentUbyte")
for i := 0; i < len(bufferData); i++ {
indices = append(indices, uint32(bufferData[i]))
}
case gltf.ComponentUshort: // gltf.ComponentTypeUnsignedShort
logrus.Info("gltf.ComponentUshort")
for i := 0; i < len(bufferData)/2; i++ {
indices = append(indices, uint32(bufferData[i*2])|uint32(bufferData[i*2+1])<<8)
}
case gltf.ComponentUint: // gltf.ComponentTypeUnsignedInt
logrus.Info("gltf.ComponentUint")
for i := 0; i < len(bufferData)/4; i++ {
indices = append(indices, uint32(bufferData[i*4])|uint32(bufferData[i*4+1])<<8|uint32(bufferData[i*4+2])<<16|uint32(bufferData[i*4+3])<<24)
}
}
} else {
logrus.Infoln("primative.Indices was nil")
// If indices are not specified, generate them assuming triangle fan topology
indices = make([]uint32, len(positions))
for i := 0; i < len(indices); i++ {
indices[i] = uint32(i)
}
}
// Render each triangle in the primitive
logrus.Infoln("Render each triangle in the primitive")
for i := 0; i < len(indices); i += 3 {
logrus.Infoln("rendering triangle")
// Get the indices of the vertices of the triangle
i1, i2, i3 := indices[i], indices[i+1], indices[i+2]
logrus.Infoln("indices are", i1, i2, i3)
// Get the positions of the vertices
p1, p2, p3 := positions[i1], positions[i2], positions[i3]
logrus.Infoln("positions are", p1, p2, p3)
// Render the triangle (you can use any rendering technique here)
dc.Push()
dc.MoveTo(float64(p1[0]), float64(p1[1]))
dc.LineTo(float64(p2[0]), float64(p2[1]))
dc.LineTo(float64(p3[0]), float64(p3[1]))
dc.ClosePath()
dc.SetRGB(1, 0, 0) // Set color to red (for example)
dc.Fill()
dc.Pop()
}
}
}
it's probably trash, but due to my lack of knowledge of this space I couldn't figure how to draw the points - the positions are outside of the range so it errors.
It should be something along those lines. At least your are missing to factor in the gltf.Node transforms (matrix, rotation, scale, translation). Also, you can use the github.com/qmuntal/gltf/modeler package, which facilitates reading data from buffers.
Sadly, I have to admit this entire domain is beyond my knowledge and experience - I will likely do this on the frontend, leveraging Threejs in an upload-asset workflow.
Thank you so much regardless!
Closing this off, thank you
Hi,
Repo looks cool, I'm just getting in to 3D modelling - so please forgive me if I'm asking in the wrong place.
Is it possible to load in a model and save out a render as a jpeg/png using this library?
Cheers
Chris