瀏覽代碼

improved gltf loader validation and docs

Daniel Salvadori 7 年之前
父節點
當前提交
b981571767
共有 3 個文件被更改,包括 163 次插入129 次删除
  1. 157 123
      loader/gltf/loader.go
  2. 1 1
      loader/gltf/material_common.go
  3. 5 5
      loader/gltf/material_pbr.go

+ 157 - 123
loader/gltf/loader.go

@@ -88,7 +88,7 @@ func ParseBinReader(r io.Reader, path string) (*GLTF, error) {
 
 	// Check magic and version
 	if header.Magic != GLBMagic {
-		return nil, fmt.Errorf("Invalid GLB Magic field")
+		return nil, fmt.Errorf("invalid GLB Magic field")
 	}
 	if header.Version < 2 {
 		return nil, fmt.Errorf("GLB version:%v not supported", header.Version)
@@ -133,7 +133,7 @@ func readChunk(r io.Reader, chunkType uint32) ([]byte, error) {
 
 	// Check chunk type
 	if chunk.Type != chunkType {
-		return nil, fmt.Errorf("expected GLB chunk type [%v] but obtained chunk type [%v]", chunkType, chunk.Type)
+		return nil, fmt.Errorf("expected GLB chunk type [%v] but found [%v]", chunkType, chunk.Type)
 	}
 
 	// Read chunk data
@@ -147,10 +147,10 @@ func readChunk(r io.Reader, chunkType uint32) ([]byte, error) {
 }
 
 // NewScene creates a parent Node which contains all nodes contained by
-// the specified scene index from the GLTF Scenes array
+// the specified scene index from the GLTF Scenes array.
 func (g *GLTF) NewScene(si int) (core.INode, error) {
 
-	log.Debug("Creating Scene %d", si)
+	log.Debug("Loading Scene %d", si)
 
 	// Check if provided scene index is valid
 	if si < 0 || si >= len(g.Scenes) {
@@ -174,7 +174,7 @@ func (g *GLTF) NewScene(si int) (core.INode, error) {
 // in the decoded GLTF Nodes array.
 func (g *GLTF) NewNode(i int) (core.INode, error) {
 
-	log.Debug("Creating Node %d", i)
+	log.Debug("Loading Node %d", i)
 
 	var in core.INode
 	var err error
@@ -182,13 +182,13 @@ func (g *GLTF) NewNode(i int) (core.INode, error) {
 
 	// Check if the node is a Mesh (triangles, lines, etc...)
 	if nodeData.Mesh != nil {
-		in, err = g.loadMesh(*nodeData.Mesh)
+		in, err = g.NewMesh(*nodeData.Mesh)
 		if err != nil {
 			return nil, err
 		}
 		// Check if the node is Camera
 	} else if nodeData.Camera != nil {
-		in, err = g.loadCamera(*nodeData.Camera)
+		in, err = g.NewCamera(*nodeData.Camera)
 		if err != nil {
 			return nil, err
 		}
@@ -236,11 +236,11 @@ func (g *GLTF) NewNode(i int) (core.INode, error) {
 	return in, nil
 }
 
-// NewAnimation creates a parent Node which contains all nodes contained by
-// the specified scene index from the GLTF Scenes array
+// NewAnimation creates an Animation for the specified
+// the animation index from the GLTF Animations array.
 func (g *GLTF) NewAnimation(i int) (*animation.Animation, error) {
 
-	log.Debug("Creating Animation %d", i)
+	log.Debug("Loading Animation %d", i)
 
 	// Check if provided scene index is valid
 	if i < 0 || i >= len(g.Animations) {
@@ -258,42 +258,56 @@ func (g *GLTF) NewAnimation(i int) (*animation.Animation, error) {
 		node := g.Nodes[target.Node].node
 		// TODO Instantiate node if not exists ?
 
+		var validTypes []string
+		var validComponentTypes []int
+
 		var ch animation.IChannel
 		if target.Path == "translation" {
 			ch = animation.NewPositionChannel(node)
+			validTypes = []string{VEC3}
+			validComponentTypes = []int{FLOAT}
 		} else if target.Path == "rotation" {
 			ch = animation.NewRotationChannel(node)
+			validTypes = []string{VEC4}
+			validComponentTypes = []int{FLOAT, BYTE, UNSIGNED_BYTE, SHORT, UNSIGNED_SHORT}
 		} else if target.Path == "scale" {
 			ch = animation.NewScaleChannel(node)
-		} //else if target.Path == "weights" {
-		//	for _, child := range node.GetNode().Children() {
-		//		gr, ok := child.(graphic.Graphic)
-		//		if ok {
-		//			gr.geom
-		//		}
-		//	}
-		//	ch = animation.NewMorphChannel(TODO) // TODO
-		//}
-
-		keyframes, err := g.loadAccessorF32(sampler.Input, []string{}, []int{})
+			validTypes = []string{VEC3}
+			validComponentTypes = []int{FLOAT}
+		} else if target.Path == "weights" {
+			validTypes = []string{SCALAR}
+			validComponentTypes = []int{FLOAT, BYTE, UNSIGNED_BYTE, SHORT, UNSIGNED_SHORT}
+			return nil, fmt.Errorf("morph animation (with 'weights' path) not supported yet")
+			// TODO
+			//	for _, child := range node.GetNode().Children() {
+			//		gr, ok := child.(graphic.Graphic)
+			//		if ok {
+			//			gr.geom
+			//		}
+			//	}
+			//	ch = animation.NewMorphChannel(TODO)
+		}
+
+		// TODO what if Input and Output accessors are interleaved? probably de-interleave in these 2 cases
+
+		keyframes, err := g.loadAccessorF32(sampler.Input, "Input", []string{SCALAR}, []int{FLOAT})
 		if err != nil {
 			return nil, err
 		}
-		values, err := g.loadAccessorF32(sampler.Output, []string{}, []int{})
+		values, err := g.loadAccessorF32(sampler.Output, "Output", validTypes, validComponentTypes)
 		if err != nil {
 			return nil, err
 		}
 		ch.SetBuffers(keyframes, values)
 		ch.SetInterpolationType(animation.InterpolationType(sampler.Interpolation))
-		//ch.SetInterpolationType(animation.STEP)//animation.InterpolationType(sampler.Interpolation))
 		anim.AddChannel(ch)
 	}
 	return anim, nil
 }
 
-// loadCamera creates and returns a Camera Node
-// from the specified GLTF.Cameras index
-func (g *GLTF) loadCamera(ci int) (core.INode, error) {
+// NewCamera creates and returns a Camera Node
+// from the specified GLTF.Cameras index.
+func (g *GLTF) NewCamera(ci int) (core.INode, error) {
 
 	log.Debug("Loading Camera %d", ci)
 
@@ -323,9 +337,9 @@ func (g *GLTF) loadCamera(ci int) (core.INode, error) {
 	return nil, fmt.Errorf("unsupported camera type: %s", camDesc.Type)
 }
 
-// loadMesh creates and returns a Graphic Node (graphic.Mesh, graphic.Lines, graphic.Points, etc)
-// from the specified GLTF Mesh index
-func (g *GLTF) loadMesh(mi int) (core.INode, error) {
+// NewMesh creates and returns a Graphic Node (graphic.Mesh, graphic.Lines, graphic.Points, etc)
+// from the specified GLTF.Meshes index.
+func (g *GLTF) NewMesh(mi int) (core.INode, error) {
 
 	log.Debug("Loading Mesh %d", mi)
 
@@ -356,7 +370,7 @@ func (g *GLTF) loadMesh(mi int) (core.INode, error) {
 		// Load primitive material
 		var grMat material.IMaterial
 		if p.Material != nil {
-			grMat, err = g.loadMaterial(*p.Material)
+			grMat, err = g.NewMaterial(*p.Material)
 			if err != nil {
 				return nil, err
 			}
@@ -373,13 +387,20 @@ func (g *GLTF) loadMesh(mi int) (core.INode, error) {
 		// Load primitive attributes
 		for name, aci := range p.Attributes {
 			accessor := g.Accessors[aci]
-			g.validateAccessorAttribute(accessor, name)
+
+			// Validate that accessor is compatible with attribute
+			err = g.validateAccessorAttribute(accessor, name)
+			if err != nil {
+				return nil, err
+			}
+
+			// Load data and add it to geometry's VBO
 			if g.isInterleaved(accessor) {
 				bvIdx := *accessor.BufferView
 				// Check if we already loaded this buffer view
 				vbo, ok := interleavedVBOs[bvIdx]
 				if ok {
-					// Already created VBO for buffer view
+					// Already created VBO for this buffer view
 					// Add attribute with correct byteOffset
 					g.addAttributeToVBO(vbo, name, uint32(*accessor.ByteOffset))
 				} else {
@@ -390,18 +411,21 @@ func (g *GLTF) loadMesh(mi int) (core.INode, error) {
 					}
 					data := g.bytesToArrayF32(buf, g.BufferViews[bvIdx].ByteLength)
 					vbo := gls.NewVBO(data)
-					g.addAttributeToVBO(vbo, name, uint32(vbo.StrideSize()))
-					interleavedVBOs[bvIdx] = vbo // Save reference to VBO keyed by index of the buffer view
+					g.addAttributeToVBO(vbo, name, 0)
+					// Save reference to VBO keyed by index of the buffer view
+					interleavedVBOs[bvIdx] = vbo
+					// Add VBO to geometry
 					geom.AddVBO(vbo)
 				}
 			} else {
-				bytes, err := g.loadAccessorBytes(accessor)
+				buf, err := g.loadAccessorBytes(accessor)
 				if err != nil {
 					return nil, err
 				}
-				data := g.bytesToArrayF32(bytes, accessor.Count*TypeSizes[accessor.Type])
+				data := g.bytesToArrayF32(buf, accessor.Count*TypeSizes[accessor.Type])
 				vbo := gls.NewVBO(data)
-				g.addAttributeToVBO(vbo, name, uint32(vbo.StrideSize()))
+				g.addAttributeToVBO(vbo, name, 0)
+				// Add VBO to geometry
 				geom.AddVBO(vbo)
 			}
 		}
@@ -436,112 +460,127 @@ func (g *GLTF) loadMesh(mi int) (core.INode, error) {
 	return meshNode, nil
 }
 
+// loadIndices loads the indices stored in the specified accessor.
+func (g *GLTF) loadIndices(ai int) (math32.ArrayU32, error) {
+
+	return g.loadAccessorU32(ai, "indices", []string{SCALAR}, []int{UNSIGNED_BYTE, UNSIGNED_SHORT, UNSIGNED_INT}) // TODO check that it's ELEMENT_ARRAY_BUFFER
+}
+
 // addAttributeToVBO adds the appropriate attribute to the provided vbo based on the glTF attribute name.
 func (g *GLTF) addAttributeToVBO(vbo *gls.VBO, attribName string, byteOffset uint32) {
 
-	parts := strings.Split(attribName, "_")
-	semantic := parts[0]
-	//set := parts[1] TODO e.g. TEXCOORD_0, TEXCOORD_1
-
 	if attribName == "POSITION" {
 		vbo.AddAttribOffset(gls.VertexPosition, byteOffset)
 	} else if attribName == "NORMAL" {
 		vbo.AddAttribOffset(gls.VertexNormal, byteOffset)
 	} else if attribName == "TANGENT" {
 		vbo.AddAttribOffset(gls.VertexTangent, byteOffset)
-	} else if semantic == "TEXCOORD" {
+	} else if attribName == "TEXCOORD_0" {
 		vbo.AddAttribOffset(gls.VertexTexcoord, byteOffset)
-	} else if semantic == "COLOR" {	// TODO glTF spec says COLOR can be VEC3 or VEC4
+	} else if attribName == "COLOR_0" {	// TODO glTF spec says COLOR can be VEC3 or VEC4
 		vbo.AddAttribOffset(gls.VertexColor, byteOffset)
-	} else if semantic == "JOINTS" {
+	} else if attribName == "JOINTS_0" {
 		// TODO
-	} else if semantic == "WEIGHTS" {
+	} else if attribName == "WEIGHTS_0" {
 		// TODO
+	} else {
+		panic(fmt.Sprintf("Attribute %v is not supported!", attribName))
 	}
 }
 
-// addAttributeToVBO adds the appropriate attribute to the provided vbo based on the glTF attribute name.
-func (g *GLTF) validateAccessorAttribute(ac Accessor, attribName string) {
+// validateAccessorAttribute validates the specified accessor for the given attribute name.
+func (g *GLTF) validateAccessorAttribute(ac Accessor, attribName string) error {
 
 	parts := strings.Split(attribName, "_")
 	semantic := parts[0]
-	//set := parts[1] TODO e.g. TEXCOORD_0, TEXCOORD_1
+
+	usage := "attribute " + attribName
 
 	if attribName == "POSITION" {
-		g.validateAccessor(ac, []string{VEC3}, []int{FLOAT})
+		return g.validateAccessor(ac, usage, []string{VEC3}, []int{FLOAT})
 	} else if attribName == "NORMAL" {
-		g.validateAccessor(ac, []string{VEC3}, []int{FLOAT})
+		return g.validateAccessor(ac, usage, []string{VEC3}, []int{FLOAT})
 	} else if attribName == "TANGENT" {
-		g.validateAccessor(ac, []string{VEC4}, []int{FLOAT})
+		return g.validateAccessor(ac, usage, []string{VEC4}, []int{FLOAT})
 	} else if semantic == "TEXCOORD" {
-		g.validateAccessor(ac, []string{VEC2}, []int{FLOAT, UNSIGNED_BYTE, UNSIGNED_SHORT})
+		return g.validateAccessor(ac, usage, []string{VEC2}, []int{FLOAT, UNSIGNED_BYTE, UNSIGNED_SHORT})
 	} else if semantic == "COLOR" {
-		g.validateAccessor(ac, []string{VEC3, VEC4}, []int{FLOAT, UNSIGNED_BYTE, UNSIGNED_SHORT})
+		return g.validateAccessor(ac, usage, []string{VEC3, VEC4}, []int{FLOAT, UNSIGNED_BYTE, UNSIGNED_SHORT})
 	} else if semantic == "JOINTS" {
-		g.validateAccessor(ac, []string{VEC4}, []int{UNSIGNED_BYTE, UNSIGNED_SHORT})
+		return g.validateAccessor(ac, usage, []string{VEC4}, []int{UNSIGNED_BYTE, UNSIGNED_SHORT})
 	} else if semantic == "WEIGHTS" {
-		g.validateAccessor(ac, []string{VEC4}, []int{FLOAT, UNSIGNED_BYTE, UNSIGNED_SHORT})
+		return g.validateAccessor(ac, usage, []string{VEC4}, []int{FLOAT, UNSIGNED_BYTE, UNSIGNED_SHORT})
+	} else {
+		return fmt.Errorf("attribute %v is not supported", attribName)
 	}
 }
 
-// TODO
-func (g *GLTF) validateAccessor(ac Accessor, validTypes []string, validComponentTypes []int) error {
-
-	// Check if points to a valid buffer view
-	//if ac.BufferView == nil {
-	//	return fmt.Errorf("Accessor.BufferView == nil NOT SUPPORTED")
-	//}
-	//
-	//// Check accessor ComponentType
-	//if ac.ComponentType != FLOAT {
-	//	return fmt.Errorf("Accessor.ComponentType != FLOAT NOT SUPPORTED")
-	//}
-	//
-	//// Check accessor Type
-	//if ac.Type != VEC3 {
-	//	return fmt.Errorf("Accessor.ComponentType != VEC3 NOT SUPPORTED")
-	//}
+// validateAccessor validates the specified attribute accessor with the specified allowed types and component types.
+func (g *GLTF) validateAccessor(ac Accessor, usage string, validTypes []string, validComponentTypes []int) error {
+
+	// Validate accessor type
+	validType := false
+	for _, vType := range validTypes {
+		if ac.Type == vType {
+			validType = true
+			break
+		}
+	}
+	if !validType {
+		return fmt.Errorf("invalid Accessor.Type %v for %s", ac.Type, usage)
+	}
+
+	// Validate accessor component type
+	validComponentType := false
+	for _, vComponentType := range validComponentTypes {
+		if ac.ComponentType == vComponentType {
+			validComponentType = true
+			break
+		}
+	}
+	if !validComponentType {
+		return fmt.Errorf("invalid Accessor.ComponentType %v for %s", ac.ComponentType, usage)
+	}
 
 	return nil
 }
 
+// newDefaultMaterial creates and returns the default material.
 func (g *GLTF) newDefaultMaterial() material.IMaterial {
 
 	return material.NewStandard(&math32.Color{0.5, 0.5, 0.5})
 }
 
-// loadMaterials loads the material specified by the material index
-func (g *GLTF) loadMaterial(mi int) (material.IMaterial, error) {
+// NewMaterial creates and returns a new material based on the material data with the specified index.
+func (g *GLTF) NewMaterial(mi int) (material.IMaterial, error) {
+
+	log.Debug("Loading Material %d", mi)
 
 	matData := g.Materials[mi]
-	// Checks for material extensions
+	// Check for material extensions
 	if matData.Extensions != nil {
 		for ext, v := range matData.Extensions {
 			if ext == "KHR_materials_common" {
 				return g.loadMaterialCommon(v)
 			} else {
-				return nil, fmt.Errorf("Unsupported extension:%s", ext)
+				return nil, fmt.Errorf("unsupported extension:%s", ext)
 			}
 		}
-		return nil, fmt.Errorf("Empty material extensions")
-		// Material should be PBR
+		return nil, fmt.Errorf("empty material extensions")
 	} else {
+		// Material is normally PBR
 		return g.loadMaterialPBR(&matData)
 	}
 }
 
-// loadTextureInfo loads the texture specified by the TextureInfo pointer
-func (g *GLTF) loadTextureInfo(ti *TextureInfo) (*texture.Texture2D, error) {
-
-	return g.loadTexture(ti.Index)
-}
+// NewTexture loads the texture specified by its index.
+func (g *GLTF) NewTexture(texi int) (*texture.Texture2D, error) {
 
-// loadTexture loads the texture specified by its index
-func (g *GLTF) loadTexture(texi int) (*texture.Texture2D, error) {
+	log.Debug("Loading Texture %d", texi)
 
 	// loads texture image
 	texDesc := g.Textures[texi]
-	img, err := g.loadImage(texDesc.Source)
+	img, err := g.NewImage(texDesc.Source)
 	if err != nil {
 		return nil, err
 	}
@@ -556,17 +595,18 @@ func (g *GLTF) loadTexture(texi int) (*texture.Texture2D, error) {
 	return tex, nil
 }
 
+// applySamplers applies the specified Sampler to the provided texture.
 func (g *GLTF) applySampler(sampler Sampler, tex *texture.Texture2D) {
 
 	// Magnification filter
-	magFilter := gls.NEAREST
+	magFilter := gls.LINEAR
 	if sampler.MagFilter != nil {
 		magFilter = *sampler.MagFilter
 	}
 	tex.SetMagFilter(uint32(magFilter))
 
 	// Minification filter
-	minFilter := gls.NEAREST
+	minFilter := gls.LINEAR_MIPMAP_LINEAR
 	if sampler.MinFilter != nil {
 		minFilter = *sampler.MinFilter
 	}
@@ -587,11 +627,12 @@ func (g *GLTF) applySampler(sampler Sampler, tex *texture.Texture2D) {
 	tex.SetWrapT(uint32(wrapT))
 }
 
-// loadImage loads the image specified by the index of GLTF.Images
-// Image can be loaded from binary chunk file or data URI or external file.
-func (g *GLTF) loadImage(ii int) (*image.RGBA, error) {
+// NewImage loads the image specified by the index of GLTF.Images.
+// Image can be loaded from binary chunk file or data URI or external file..
+func (g *GLTF) NewImage(ii int) (*image.RGBA, error) {
+
+	log.Debug("Loading Image %d", ii)
 
-	log.Error("loadImage:%v", ii)
 	imgDesc := g.Images[ii]
 	var data []byte
 	var err error
@@ -599,7 +640,7 @@ func (g *GLTF) loadImage(ii int) (*image.RGBA, error) {
 	if imgDesc.Uri == "" {
 		bvi := imgDesc.BufferView
 		if bvi == nil {
-			return nil, fmt.Errorf("Image has empty URI and no BufferView")
+			return nil, fmt.Errorf("image has empty URI and no BufferView")
 		}
 		bv := g.BufferViews[*bvi]
 		offset := 0
@@ -643,7 +684,7 @@ func (g *GLTF) loadImage(ii int) (*image.RGBA, error) {
 	return rgba, nil
 }
 
-
+// bytesToArrayU32 converts a byte array to ArrayU32.
 func (g *GLTF) bytesToArrayU32(data []byte, componentType, count int) (math32.ArrayU32, error) {
 
 	// If component is UNSIGNED_INT nothing to do
@@ -673,13 +714,14 @@ func (g *GLTF) bytesToArrayU32(data []byte, componentType, count int) (math32.Ar
 	return nil, fmt.Errorf("Unsupported Accessor ComponentType:%v", componentType)
 }
 
+// bytesToArrayF32 converts a byte array to ArrayF32.
 func (g *GLTF) bytesToArrayF32(data []byte, size int) math32.ArrayF32 {
 
 	return (*[1 << 30]float32)(unsafe.Pointer(&data[0]))[:size]
 }
 
-// loadAccessorData loads the indices array specified by the Accessor index.
-func (g *GLTF) loadAccessorU32(ai int, validTypes []string, validComponentTypes []int) (math32.ArrayU32, error) {
+// loadAccessorU32 loads data from the specified accessor and performs validation of the Type and ComponentType.
+func (g *GLTF) loadAccessorU32(ai int, usage string, validTypes []string, validComponentTypes []int) (math32.ArrayU32, error) {
 
 	// Get Accessor for the specified index
 	ac := g.Accessors[ai]
@@ -688,7 +730,7 @@ func (g *GLTF) loadAccessorU32(ai int, validTypes []string, validComponentTypes
 	}
 
 	// Validate type and component type
-	err := g.validateAccessor(ac, validTypes, validComponentTypes)
+	err := g.validateAccessor(ac, usage, validTypes, validComponentTypes)
 	if err != nil {
 		return nil, err
 	}
@@ -702,8 +744,8 @@ func (g *GLTF) loadAccessorU32(ai int, validTypes []string, validComponentTypes
 	return g.bytesToArrayU32(data, ac.ComponentType, ac.Count)
 }
 
-// TODO - change ai -> accessor
-func (g *GLTF) loadAccessorF32(ai int, validTypes []string, validComponentTypes []int) (math32.ArrayF32, error) {
+// loadAccessorF32 loads data from the specified accessor and performs validation of the Type and ComponentType.
+func (g *GLTF) loadAccessorF32(ai int, usage string, validTypes []string, validComponentTypes []int) (math32.ArrayF32, error) {
 
 	// Get Accessor for the specified index
 	ac := g.Accessors[ai]
@@ -712,7 +754,7 @@ func (g *GLTF) loadAccessorF32(ai int, validTypes []string, validComponentTypes
 	}
 
 	// Validate type and component type
-	err := g.validateAccessor(ac, validTypes, validComponentTypes)
+	err := g.validateAccessor(ac, usage, validTypes, validComponentTypes)
 	if err != nil {
 		return nil, err
 	}
@@ -726,7 +768,7 @@ func (g *GLTF) loadAccessorF32(ai int, validTypes []string, validComponentTypes
 	return g.bytesToArrayF32(data, ac.Count*TypeSizes[ac.Type]), nil
 }
 
-// loadAccessorBytes
+// loadAccessorBytes returns the base byte array used by an accessor.
 func (g *GLTF) loadAccessorBytes(ac Accessor) ([]byte, error) {
 
 	// Get the Accessor's BufferView
@@ -748,7 +790,7 @@ func (g *GLTF) loadAccessorBytes(ac Accessor) ([]byte, error) {
 	}
 	data = data[offset:]
 
-	// Check if interleaved and de-interleave if necessary
+	// Check if interleaved and de-interleave if necessary ? TODO
 
 	// Calculate the size in bytes of a complete attribute
 	itemSize := TypeSizes[ac.Type]
@@ -758,14 +800,13 @@ func (g *GLTF) loadAccessorBytes(ac Accessor) ([]byte, error) {
 	if (bv.ByteStride != nil) && (*bv.ByteStride != itemBytes) {
 		// BufferView data is interleaved, de-interleave
 		// TODO
-		log.Error("DATA IS INTERLEAVED - NOT SUPPORTED YET IN SOME CASES SUCH AS THIS!")
+		return nil, fmt.Errorf("data is interleaved - not supported for animation yet")
 	}
 
 	return data, nil
 }
 
-// isInterleaves checks if the BufferView used by the specified Accessor index is
-// interleaved or not
+// isInterleaves returns whether the BufferView used by the provided accessor is interleaved.
 func (g *GLTF) isInterleaved(accessor Accessor) bool {
 
 	// Get the Accessor's BufferView
@@ -788,14 +829,7 @@ func (g *GLTF) isInterleaved(accessor Accessor) bool {
 	return true
 }
 
-
-//
-func (g *GLTF) loadIndices(ai int) (math32.ArrayU32, error) {
-
-	return g.loadAccessorU32(ai, []string{SCALAR}, []int{UNSIGNED_BYTE, UNSIGNED_SHORT, UNSIGNED_INT}) // TODO check that it's ELEMENT_ARRAY_BUFFER
-}
-
-// loadBufferView loads and returns a byte slice with data from the specified BufferView index
+// loadBufferView loads and returns a byte slice with data from the specified BufferView.
 func (g *GLTF) loadBufferView(bv BufferView) ([]byte, error) {
 
 	// Load buffer view buffer
@@ -862,7 +896,7 @@ func (g *GLTF) loadBuffer(bi int) ([]byte, error) {
 	return data, nil
 }
 
-// dataURL describes a decoded data url string
+// dataURL describes a decoded data url string.
 type dataURL struct {
 	MediaType string
 	Encoding  string
@@ -878,7 +912,7 @@ const (
 
 var validMediaTypes = []string{mimeBIN, mimePNG, mimeJPEG}
 
-// isDataURL checks if the specified string has the prefix of data URL
+// isDataURL checks if the specified string has the prefix of data URL.
 func isDataURL(url string) bool {
 
 	if strings.HasPrefix(url, dataURLprefix) {
@@ -887,7 +921,7 @@ func isDataURL(url string) bool {
 	return false
 }
 
-// loadDataURL decodes the specified data URI string (base64)
+// loadDataURL decodes the specified data URI string (base64).
 func loadDataURL(url string) ([]byte, error) {
 
 	var du dataURL
@@ -905,12 +939,12 @@ func loadDataURL(url string) ([]byte, error) {
 		}
 	}
 	if !found {
-		return nil, fmt.Errorf("Data URI media type:%s not supported", du.MediaType)
+		return nil, fmt.Errorf("data URI media type:%s not supported", du.MediaType)
 	}
 
 	// Checks encoding
 	if du.Encoding != "base64" {
-		return nil, fmt.Errorf("Data URI encoding:%s not supported", du.Encoding)
+		return nil, fmt.Errorf("data URI encoding:%s not supported", du.Encoding)
 	}
 
 	// Decodes data from BASE64
@@ -926,20 +960,20 @@ func loadDataURL(url string) ([]byte, error) {
 // and if successfull returns true and updates the specified pointer with the parsed fields.
 func parseDataURL(url string, du *dataURL) error {
 
-	// Checks prefix
+	// Check prefix
 	if !isDataURL(url) {
-		return fmt.Errorf("Specified string is not a data URL")
+		return fmt.Errorf("specified string is not a data URL")
 	}
 
-	// Separates header from data
+	// Separate header from data
 	body := url[len(dataURLprefix):]
 	parts := strings.Split(body, ",")
 	if len(parts) != 2 {
-		return fmt.Errorf("Data URI contains more than one ','")
+		return fmt.Errorf("data URI contains more than one ','")
 	}
 	du.Data = parts[1]
 
-	// Separates media type from optional encoding
+	// Separate media type from optional encoding
 	res := strings.Split(parts[0], ";")
 	du.MediaType = res[0]
 	if len(res) < 2 {

+ 1 - 1
loader/gltf/material_common.go

@@ -74,7 +74,7 @@ func (g *GLTF) loadMaterialCommon(ext interface{}) (material.IMaterial, error) {
 			// Checks for texture index
 			if len(v) == 1 {
 				var err error
-				texDiffuse, err = g.loadTexture(int(v[0]))
+				texDiffuse, err = g.NewTexture(int(v[0]))
 				if err != nil {
 					return nil, err
 				}

+ 5 - 5
loader/gltf/material_pbr.go

@@ -60,7 +60,7 @@ func (g *GLTF) loadMaterialPBR(m *Material) (material.IMaterial, error) {
 
 	// BaseColorTexture
 	if pbr.BaseColorTexture != nil {
-		tex, err := g.loadTextureInfo(pbr.BaseColorTexture)
+		tex, err := g.NewTexture(pbr.BaseColorTexture.Index)
 		if err != nil {
 			return nil, err
 		}
@@ -69,7 +69,7 @@ func (g *GLTF) loadMaterialPBR(m *Material) (material.IMaterial, error) {
 
 	// MetallicRoughnessTexture
 	if pbr.MetallicRoughnessTexture != nil {
-		tex, err := g.loadTextureInfo(pbr.MetallicRoughnessTexture)
+		tex, err := g.NewTexture(pbr.MetallicRoughnessTexture.Index)
 		if err != nil {
 			return nil, err
 		}
@@ -78,7 +78,7 @@ func (g *GLTF) loadMaterialPBR(m *Material) (material.IMaterial, error) {
 
 	// NormalTexture
 	if m.NormalTexture != nil {
-		tex, err := g.loadTexture(m.NormalTexture.Index)
+		tex, err := g.NewTexture(m.NormalTexture.Index)
 		if err != nil {
 			return nil, err
 		}
@@ -87,7 +87,7 @@ func (g *GLTF) loadMaterialPBR(m *Material) (material.IMaterial, error) {
 
 	// OcclusionTexture
 	if m.OcclusionTexture != nil {
-		tex, err := g.loadTexture(m.OcclusionTexture.Index)
+		tex, err := g.NewTexture(m.OcclusionTexture.Index)
 		if err != nil {
 			return nil, err
 		}
@@ -96,7 +96,7 @@ func (g *GLTF) loadMaterialPBR(m *Material) (material.IMaterial, error) {
 
 	// EmissiveTexture
 	if m.EmissiveTexture != nil {
-		tex, err := g.loadTexture(m.EmissiveTexture.Index)
+		tex, err := g.NewTexture(m.EmissiveTexture.Index)
 		if err != nil {
 			return nil, err
 		}