Bläddra i källkod

gltf loader dev...

leonsal 8 år sedan
förälder
incheckning
3752efb304
5 ändrade filer med 126 tillägg och 33 borttagningar
  1. 4 0
      gls/gls.go
  2. 59 11
      gls/vbo.go
  3. 2 2
      gui/panel.go
  4. 11 0
      loader/gltf/gltf.go
  5. 50 20
      loader/gltf/loader.go

+ 4 - 0
gls/gls.go

@@ -80,6 +80,10 @@ const (
 	intTrue     = 1
 )
 
+const (
+	FloatSize = int32(unsafe.Sizeof(float32(0)))
+)
+
 // New creates and returns a new instance of an GLS object
 // which encapsulates the state of an OpenGL context
 // This should be called only after an active OpenGL context

+ 59 - 11
gls/vbo.go

@@ -22,7 +22,9 @@ type VBO struct {
 // VBOattrib describes one attribute of an OpenGL Vertex Buffer Object
 type VBOattrib struct {
 	Name     string // Name of of the attribute
-	ItemSize int32  // Number of elements for each item
+	ItemSize int32  // Number of elements for each item (1,2,3 or 4)
+	Stride   int32  // Specifies the byte offset between consecutive attributes
+	Offset   uint32 // Byte offset of this attribute from the start of the buffer
 }
 
 // NewVBO creates and returns a pointer to a new OpenGL Vertex Buffer Object
@@ -43,7 +45,9 @@ func (vbo *VBO) init() {
 	vbo.attribs = make([]VBOattrib, 0)
 }
 
-// AddAttrib adds a new attribute to this VBO
+// AddAttrib adds a new attribute to this VBO with the specified item size (1,2,3 or 4)
+// The attribute stride and offset are set to 0.
+// Use AddAttribEx to specify the stride and offset
 func (vbo *VBO) AddAttrib(name string, itemSize int32) *VBO {
 
 	vbo.attribs = append(vbo.attribs, VBOattrib{
@@ -53,6 +57,17 @@ func (vbo *VBO) AddAttrib(name string, itemSize int32) *VBO {
 	return vbo
 }
 
+func (vbo *VBO) AddAttribEx(name string, itemSize, stride int32, offset uint32) *VBO {
+
+	vbo.attribs = append(vbo.attribs, VBOattrib{
+		Name:     name,
+		ItemSize: itemSize,
+		Stride:   stride,
+		Offset:   offset,
+	})
+	return vbo
+}
+
 // Attrib finds and returns pointer the attribute with the specified name
 // or nil if not found
 func (vbo *VBO) Attrib(name string) *VBOattrib {
@@ -141,12 +156,6 @@ func (vbo *VBO) Transfer(gs *GLS) {
 	if vbo.gs == nil {
 		vbo.handle = gs.GenBuffer()
 		gs.BindBuffer(ARRAY_BUFFER, vbo.handle)
-		// Calculates stride
-		stride := vbo.Stride()
-		// For each attribute
-		var items uint32 = 0
-		var offset uint32 = 0
-		elsize := int32(unsafe.Sizeof(float32(0)))
 		for _, attrib := range vbo.attribs {
 			// Get attribute location in the current program
 			loc := gs.prog.GetAttribLocation(attrib.Name)
@@ -155,9 +164,7 @@ func (vbo *VBO) Transfer(gs *GLS) {
 			}
 			// Enables attribute and sets its stride and offset in the buffer
 			gs.EnableVertexAttribArray(uint32(loc))
-			gs.VertexAttribPointer(uint32(loc), attrib.ItemSize, FLOAT, false, int32(stride), offset)
-			items += uint32(attrib.ItemSize)
-			offset = uint32(elsize) * items
+			gs.VertexAttribPointer(uint32(loc), attrib.ItemSize, FLOAT, false, attrib.Stride, attrib.Offset)
 		}
 		vbo.gs = gs // this indicates that the vbo was initialized
 	}
@@ -169,3 +176,44 @@ func (vbo *VBO) Transfer(gs *GLS) {
 	gs.BufferData(ARRAY_BUFFER, vbo.buffer.Bytes(), &vbo.buffer[0], vbo.usage)
 	vbo.update = false
 }
+
+//// Transfer is called internally and transfer the data in the VBO buffer to OpenGL if necessary
+//func (vbo *VBO) Transfer(gs *GLS) {
+//
+//	// If the VBO buffer is empty, ignore
+//	if vbo.buffer.Bytes() == 0 {
+//		return
+//	}
+//
+//	// First time initialization
+//	if vbo.gs == nil {
+//		vbo.handle = gs.GenBuffer()
+//		gs.BindBuffer(ARRAY_BUFFER, vbo.handle)
+//		// Calculates stride
+//		stride := vbo.Stride()
+//		// For each attribute
+//		var items uint32 = 0
+//		var offset uint32 = 0
+//		elsize := int32(unsafe.Sizeof(float32(0)))
+//		for _, attrib := range vbo.attribs {
+//			// Get attribute location in the current program
+//			loc := gs.prog.GetAttribLocation(attrib.Name)
+//			if loc < 0 {
+//				continue
+//			}
+//			// Enables attribute and sets its stride and offset in the buffer
+//			gs.EnableVertexAttribArray(uint32(loc))
+//			gs.VertexAttribPointer(uint32(loc), attrib.ItemSize, FLOAT, false, int32(stride), offset)
+//			items += uint32(attrib.ItemSize)
+//			offset = uint32(elsize) * items
+//		}
+//		vbo.gs = gs // this indicates that the vbo was initialized
+//	}
+//	if !vbo.update {
+//		return
+//	}
+//	// Transfer the VBO data to OpenGL
+//	gs.BindBuffer(ARRAY_BUFFER, vbo.handle)
+//	gs.BufferData(ARRAY_BUFFER, vbo.buffer.Bytes(), &vbo.buffer[0], vbo.usage)
+//	vbo.update = false
+//}

+ 2 - 2
gui/panel.go

@@ -121,8 +121,8 @@ func (p *Panel) Initialize(width, height float32) {
 	geom := geometry.NewGeometry()
 	geom.SetIndices(indices)
 	geom.AddVBO(gls.NewVBO().
-		AddAttrib("VertexPosition", 3).
-		AddAttrib("VertexTexcoord", 2).
+		AddAttribEx("VertexPosition", 3, 5*gls.FloatSize, 0).
+		AddAttribEx("VertexTexcoord", 2, 5*gls.FloatSize, uint32(3*gls.FloatSize)).
 		SetBuffer(positions),
 	)
 

+ 11 - 0
loader/gltf/gltf.go

@@ -348,6 +348,17 @@ const (
 	MAT4       = "MAT4"
 )
 
+// TypeSizes maps the attribute type to the number of its elements
+var TypeSizes = map[string]int{
+	SCALAR: 1,
+	VEC2:   2,
+	VEC3:   3,
+	VEC4:   4,
+	MAT2:   4,
+	MAT3:   9,
+	MAT4:   16,
+}
+
 type GLB struct {
 	Header GLBHeader
 	JSON   GLBChunk

+ 50 - 20
loader/gltf/loader.go

@@ -264,11 +264,10 @@ func (g *GLTF) loadCamera(ci int) (core.INode, error) {
 // from the specified GLTF Mesh index
 func (g *GLTF) loadMesh(mi int) (core.INode, error) {
 
-	// Create attribute buffers
+	// Create buffers and VBO
 	indices := math32.NewArrayU32(0, 0)
-	positions := math32.NewArrayF32(0, 0)
-	normals := math32.NewArrayF32(0, 0)
-	uvs0 := math32.NewArrayF32(0, 0)
+	vbuf := math32.NewArrayF32(0, 0)
+	vbo := gls.NewVBO()
 
 	// Array of primitive materials
 	type matGroup struct {
@@ -322,12 +321,20 @@ func (g *GLTF) loadMesh(mi int) (core.INode, error) {
 
 		// Load primitive attributes
 		for name, aci := range p.Attributes {
+			//interleaved := g.isInterleaved(aci)
+			//if interleaved {
+			//	buf, err := g.loadBufferView(*g.Accessors[aci].BufferView)
+			//	if err != nil {
+			//		return nil, err
+			//	}
+			//}
 			if name == "POSITION" {
 				ppos, err := g.loadVec3(aci)
 				if err != nil {
 					return nil, err
 				}
-				positions = append(positions, ppos...)
+				vbo.AddAttribEx("VertexPosition", 3, 0, uint32(len(vbuf)*int(gls.FloatSize)))
+				vbuf = append(vbuf, ppos...)
 				continue
 			}
 			if name == "NORMAL" {
@@ -335,7 +342,8 @@ func (g *GLTF) loadMesh(mi int) (core.INode, error) {
 				if err != nil {
 					return nil, err
 				}
-				normals = append(normals, pnorms...)
+				vbo.AddAttribEx("VertexNormal", 3, 0, uint32(len(vbuf)*int(gls.FloatSize)))
+				vbuf = append(vbuf, pnorms...)
 				continue
 			}
 			if name == "TEXCOORD_0" {
@@ -343,31 +351,28 @@ func (g *GLTF) loadMesh(mi int) (core.INode, error) {
 				if err != nil {
 					return nil, err
 				}
-				uvs0 = append(uvs0, puvs...)
+				vbo.AddAttribEx("VertexTexcoord", 2, 0, uint32(len(vbuf)*int(gls.FloatSize)))
+				vbuf = append(vbuf, puvs...)
 				continue
 			}
 		}
 	}
 
-	// Creates Geometry and add attribute VBOs
+	// Creates Geometry and add attribute VBO
 	geom := geometry.NewGeometry()
 	if len(indices) > 0 {
 		geom.SetIndices(indices)
 	}
-	if len(positions) > 0 {
-		geom.AddVBO(gls.NewVBO().AddAttrib("VertexPosition", 3).SetBuffer(positions))
-	}
-	if len(normals) > 0 {
-		geom.AddVBO(gls.NewVBO().AddAttrib("VertexNormal", 3).SetBuffer(normals))
-	}
-	if len(uvs0) > 0 {
-		geom.AddVBO(gls.NewVBO().AddAttrib("VertexTexcoord", 2).SetBuffer(uvs0))
+	if len(vbuf) > 0 {
+		vbo.SetBuffer(vbuf)
+		geom.AddVBO(vbo)
 	}
 
 	//log.Error("positions:%v", positions)
 	//log.Error("indices..:%v", indices)
 	//log.Error("normals..:%v", normals)
 	//log.Error("uvs0.....:%v", uvs0)
+	log.Error("VBUF size in number of floats:%v", len(vbuf))
 
 	// Create Mesh
 	if mode == TRIANGLES {
@@ -478,7 +483,7 @@ func (g *GLTF) loadImage(ii int) (*image.RGBA, error) {
 	imgDesc := g.Images[ii]
 	var data []byte
 	var err error
-	// If Uri is empty, load image from chunk
+	// If Uri is empty, load image from GLB binary chunk
 	if imgDesc.Uri == "" {
 		bvi := imgDesc.BufferView
 		if bvi == nil {
@@ -496,9 +501,8 @@ func (g *GLTF) loadImage(ii int) (*image.RGBA, error) {
 		if err != nil {
 			return nil, err
 		}
-		// Loads external buffer file
-	} else {
 		// Load image data from file
+	} else {
 		fpath := filepath.Join(g.path, imgDesc.Uri)
 		f, err := os.Open(fpath)
 		if err != nil {
@@ -527,7 +531,8 @@ func (g *GLTF) loadImage(ii int) (*image.RGBA, error) {
 	return rgba, nil
 }
 
-// loadVec3 load array of Vector3 from the specified accessor index
+// loadVec3 load array of float32 values from the specified accessor index.
+// The acesssor must have type of VEC3 and component type of FLOAT
 func (g *GLTF) loadVec3(ai int) (math32.ArrayF32, error) {
 
 	// Get Accessor for the specified index
@@ -648,6 +653,31 @@ func (g *GLTF) loadIndices(ai int) (math32.ArrayU32, error) {
 	return nil, fmt.Errorf("Unsupported Accessor ComponentType:%v", ac.ComponentType)
 }
 
+// isInterleaves checks if the BufferView used by the specified Accessor index is
+// interleaved or not
+func (g *GLTF) isInterleaved(aci int) bool {
+
+	// Get the Accessor's BufferView
+	accessor := g.Accessors[aci]
+	if accessor.BufferView == nil {
+		return false
+	}
+	bv := g.BufferViews[*accessor.BufferView]
+
+	// Calculates the size in bytes of a complete attribute
+	itemSize := TypeSizes[accessor.Type]
+	itemBytes := int(gls.FloatSize) * itemSize
+
+	// If the BufferView stride is equal to the item size, the buffer is not interleaved
+	if bv.ByteStride == nil {
+		return false
+	}
+	if *bv.ByteStride == itemBytes {
+		return false
+	}
+	return true
+}
+
 // loadBufferView loads and returns a byte slice with data from the specified
 // BufferView index
 func (g *GLTF) loadBufferView(bvi int) ([]byte, error) {