Explorar o código

implemented skinning and glTF loading of rigged meshes

Daniel Salvadori %!s(int64=7) %!d(string=hai) anos
pai
achega
9233aba005

+ 1 - 1
geometry/geometry.go

@@ -162,7 +162,7 @@ func (g *Geometry) AddVBO(vbo *gls.VBO) {
 			if existingVbo.AttribName(attrib.Name) != nil {
 				panic("Geometry.AddVBO: geometry already has a VBO with attribute name:" + attrib.Name)
 			}
-			if existingVbo.Attrib(attrib.Type) != nil {
+			if attrib.Type != gls.Undefined && existingVbo.Attrib(attrib.Type) != nil {
 				panic("Geometry.AddVBO: geometry already has a VBO with attribute type:" + strconv.Itoa(int(attrib.Type)))
 			}
 		}

+ 11 - 0
graphic/graphic.go

@@ -25,6 +25,8 @@ type Graphic struct {
 	cullable    bool               // Cullable flag
 	renderOrder int                // Render order
 
+	ShaderDefines gls.ShaderDefines // Graphic-specific shader defines
+
 	mvm  math32.Matrix4 // Cached ModelView matrix
 	mvpm math32.Matrix4 // Cached ModelViewProjection matrix
 }
@@ -71,6 +73,7 @@ func (gr *Graphic) Init(igeom geometry.IGeometry, mode uint32) *Graphic {
 	gr.materials = make([]GraphicMaterial, 0)
 	gr.renderable = true
 	gr.cullable = true
+	gr.ShaderDefines = *gls.NewShaderDefines()
 	return gr
 }
 
@@ -192,6 +195,14 @@ func (gr *Graphic) GetMaterial(vpos int) material.IMaterial {
 	return nil
 }
 
+// SetIGraphic sets the IGraphic on all this Graphic's GraphicMaterials.
+func (gr *Graphic) SetIGraphic(ig IGraphic) {
+
+	for i := range gr.materials {
+		gr.materials[i].igraphic = ig
+	}
+}
+
 // CalculateMatrices calculates the model view and model view projection matrices.
 func (gr *Graphic) CalculateMatrices(gs *gls.GLS, rinfo *core.RenderInfo) {
 

+ 59 - 0
graphic/rigged_mesh.go

@@ -0,0 +1,59 @@
+// Copyright 2016 The G3N Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package graphic
+
+import (
+	"github.com/g3n/engine/gls"
+	"strconv"
+	"github.com/g3n/engine/core"
+)
+
+// MaxBoneInfluencers is the maximum number of bone influencers per vertex.
+const MaxBoneInfluencers = 4
+
+// RiggedMesh is a Mesh associated with a skeleton.
+type RiggedMesh struct {
+	*Mesh    // Embedded mesh
+	skeleton *Skeleton
+	mBones   gls.Uniform
+}
+
+// NewRiggedMesh returns a new rigged mesh.
+func NewRiggedMesh(mesh *Mesh) *RiggedMesh {
+
+	rm := new(RiggedMesh)
+	rm.Mesh = mesh
+	rm.SetIGraphic(rm)
+	rm.mBones.Init("mBones")
+	rm.ShaderDefines.Set("BONE_INFLUENCERS", strconv.Itoa(MaxBoneInfluencers))
+	rm.ShaderDefines.Set("TOTAL_BONES", "0")
+
+	return rm
+}
+
+// SetSkeleton sets the skeleton used by the rigged mesh.
+func (rm *RiggedMesh) SetSkeleton(sk *Skeleton) {
+
+	rm.skeleton = sk
+	rm.ShaderDefines.Set("TOTAL_BONES", strconv.Itoa(len(rm.skeleton.Bones())))
+}
+
+// SetSkeleton returns the skeleton used by the rigged mesh.
+func (rm *RiggedMesh) Skeleton() *Skeleton {
+
+	return rm.skeleton
+}
+
+// RenderSetup is called by the renderer before drawing the geometry.
+func (rm *RiggedMesh) RenderSetup(gs *gls.GLS, rinfo *core.RenderInfo) {
+
+	// Call base mesh's RenderSetup
+	rm.Mesh.RenderSetup(gs, rinfo)
+
+	// Transfer bone matrices
+	boneMatrices := rm.skeleton.BoneMatrices()
+	location := rm.mBones.Location(gs)
+	gs.UniformMatrix4fv(location, int32(len(boneMatrices)), false, &boneMatrices[0][0])
+}

+ 73 - 0
graphic/skeleton.go

@@ -0,0 +1,73 @@
+// Copyright 2016 The G3N Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package graphic
+
+import (
+	"github.com/g3n/engine/core"
+	"github.com/g3n/engine/math32"
+	)
+
+// Skeleton contains armature information.
+type Skeleton struct {
+	core.INode
+	inverseBindMatrices []math32.Matrix4
+	boneMatrices        []math32.Matrix4
+	bones               []*core.Node
+}
+
+// NewSkeleton creates and returns a pointer to a new Skeleton.
+func NewSkeleton(node core.INode) *Skeleton {
+
+	sk := new(Skeleton)
+	sk.INode = node
+	sk.boneMatrices = make([]math32.Matrix4, 0)
+	sk.bones = make([]*core.Node, 0)
+	return sk
+}
+
+// AddBone adds a bone to the skeleton along with an optional inverseBindMatrix.
+func (sk *Skeleton) AddBone(node *core.Node, inverseBindMatrix *math32.Matrix4) {
+
+	// Useful for debugging:
+	//node.Add(NewAxisHelper(0.2))
+
+	sk.bones = append(sk.bones, node)
+	sk.boneMatrices = append(sk.boneMatrices, *math32.NewMatrix4())
+	if inverseBindMatrix == nil {
+		inverseBindMatrix = math32.NewMatrix4() // Identity matrix
+	}
+
+	sk.inverseBindMatrices = append(sk.inverseBindMatrices, *inverseBindMatrix)
+}
+
+// Bones returns the list of bones in the skeleton.
+func (sk *Skeleton) Bones() []*core.Node {
+
+	return sk.bones
+}
+
+// BoneMatrices calculates and returns the bone world matrices to be sent to the shader.
+func (sk *Skeleton) BoneMatrices() []math32.Matrix4 {
+
+	// Obtain inverse matrix world
+	var invMat math32.Matrix4
+	node := sk.GetNode()
+	node.UpdateMatrixWorld()
+	nMW := node.MatrixWorld()
+	err := invMat.GetInverse(&nMW)
+	if err != nil {
+		log.Error("Skeleton.BoneMatrices: inverting matrix failed!")
+	}
+
+	// Update bone matrices
+	for i := range sk.bones {
+		sk.bones[i].UpdateMatrixWorld()
+		bMat := sk.bones[i].MatrixWorld()
+		bMat.MultiplyMatrices(&bMat, &sk.inverseBindMatrices[i])
+		sk.boneMatrices[i].MultiplyMatrices(&invMat, &bMat)
+	}
+
+	return sk.boneMatrices
+}

+ 1 - 1
loader/gltf/gltf.go

@@ -275,7 +275,7 @@ type Scene struct {
 // Joints and matrices defining a skin.
 type Skin struct {
 	InverseBindMatrices int                    // The index of the accessor containing the floating-point 4x4 inverse-bind matrices. The default is that each matrix is a 4x4 identity matrix, which implies that inverse-bind matrices were pre-applied. Not required.
-	Skeleton            int                    // The index of the node used as a skeleton root. When undefined, joints transforms resolve to scene root. Not required.
+	Skeleton            *int                   // The index of the node used as a skeleton root. When undefined, joints transforms resolve to scene root. Not required.
 	Joints              []int                  // Indices of skeleton nodes, used as joints in this skin. Required.
 	Name                string                 // The user-define named of this object. Not required.
 	Extensions          map[string]interface{} // Dictionary object with extension-specific objects. Not required.

+ 90 - 12
loader/gltf/loader.go

@@ -186,6 +186,52 @@ func (g *GLTF) NewNode(i int) (core.INode, error) {
 		if err != nil {
 			return nil, err
 		}
+
+		if nodeData.Skin != nil {
+			children := in.GetNode().Children()
+			if len(children) > 1 {
+				//log.Error("skinning/rigging meshes with more than a single primitive is not supported")
+				return nil, fmt.Errorf("skinning/rigging meshes with more than a single primitive is not supported")
+			}
+			mesh := children[0].(*graphic.Mesh)
+			// Create RiggedMesh
+			rm := graphic.NewRiggedMesh(mesh)
+			// Create Skeleton and set it on Rigged mesh
+			skinData := g.Skins[*nodeData.Skin]
+			var topNode core.INode
+			if skinData.Skeleton != nil {
+				topNode = g.Nodes[*skinData.Skeleton].node
+				topNode.UpdateMatrixWorld()
+			}  else {
+				return nil, fmt.Errorf("skinning/rigging meshes with nil skeleton is not supported (yet)")
+				//defaultSceneIdx := 0
+				//if g.Scene != nil {
+				//	defaultSceneIdx = *g.Scene
+				//}
+				//topNode = g.Scenes[defaultSceneIdx]
+			}
+			skeleton := graphic.NewSkeleton(mesh) // TODO SPEC SAYS IT SHOULD BE TOP SKELETON NODE HERE
+
+			// Load inverseBindMatrices
+			// TODO
+			ibmData, err := g.loadAccessorF32(skinData.InverseBindMatrices, "ibm", []string{MAT4}, []int{FLOAT})
+			if err != nil {
+				return nil, err
+			}
+
+			fmt.Println("ibmData", ibmData)
+
+			for i := range skinData.Joints {
+				jointNode := g.Nodes[skinData.Joints[i]].node
+				var ibm math32.Matrix4
+				ibmData.GetMatrix4(16 * i, &ibm)
+				skeleton.AddBone(jointNode.GetNode(), &ibm)
+			}
+
+			rm.SetSkeleton(skeleton)
+			in = rm
+		}
+
 		// Check if the node is Camera
 	} else if nodeData.Camera != nil {
 		in, err = g.NewCamera(*nodeData.Camera)
@@ -459,7 +505,10 @@ func (g *GLTF) loadAttributes(geom *geometry.Geometry, attributes map[string]int
 				if err != nil {
 					return err
 				}
-				data := g.bytesToArrayF32(buf, g.BufferViews[bvIdx].ByteLength)
+				data, err := g.bytesToArrayF32(buf, accessor.ComponentType, accessor.Count*TypeSizes[accessor.Type])
+				if err != nil {
+					return err
+				}
 				vbo := gls.NewVBO(data)
 				g.addAttributeToVBO(vbo, name, 0)
 				// Save reference to VBO keyed by index of the buffer view
@@ -472,7 +521,10 @@ func (g *GLTF) loadAttributes(geom *geometry.Geometry, attributes map[string]int
 			if err != nil {
 				return err
 			}
-			data := g.bytesToArrayF32(buf, accessor.Count*TypeSizes[accessor.Type])
+			data, err := g.bytesToArrayF32(buf, accessor.ComponentType, accessor.Count*TypeSizes[accessor.Type])
+			if err != nil {
+				return err
+			}
 			vbo := gls.NewVBO(data)
 			g.addAttributeToVBO(vbo, name, 0)
 			// Add VBO to geometry
@@ -508,9 +560,11 @@ func (g *GLTF) addAttributeToVBO(vbo *gls.VBO, attribName string, byteOffset uin
 	} else if attribName == "COLOR_0" {	// TODO glTF spec says COLOR can be VEC3 or VEC4
 		vbo.AddAttribOffset(gls.VertexColor, byteOffset)
 	} else if attribName == "JOINTS_0" {
-		// TODO
+		vbo.AddCustomAttribOffset("matricesIndices", 4, byteOffset)
+		fmt.Println("matricesIndices", vbo.Buffer())
 	} else if attribName == "WEIGHTS_0" {
-		// TODO
+		vbo.AddCustomAttribOffset("matricesWeights", 4, byteOffset)
+		fmt.Println("matricesWeights", vbo.Buffer())
 	} else {
 		panic(fmt.Sprintf("Attribute %v is not supported!", attribName))
 	}
@@ -740,13 +794,37 @@ func (g *GLTF) bytesToArrayU32(data []byte, componentType, count int) (math32.Ar
 		return out, nil
 	}
 
-	return nil, fmt.Errorf("Unsupported Accessor ComponentType:%v", componentType)
+	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 {
+func (g *GLTF) bytesToArrayF32(data []byte, componentType, count int) (math32.ArrayF32, error) {
+
+	// If component is UNSIGNED_INT nothing to do
+	if componentType == UNSIGNED_INT {
+		arr := (*[1 << 30]float32)(unsafe.Pointer(&data[0]))[:count]
+		return math32.ArrayF32(arr), nil
+	}
+
+	// Converts UNSIGNED_SHORT to UNSIGNED_INT
+	if componentType == UNSIGNED_SHORT {
+		out := math32.NewArrayF32(count, count)
+		for i := 0; i < count; i++ {
+			out[i] = float32(data[i*2]) + float32(data[i*2+1])*256
+		}
+		return out, nil
+	}
+
+	// Converts UNSIGNED_BYTE indices to UNSIGNED_INT
+	if componentType == UNSIGNED_BYTE {
+		out := math32.NewArrayF32(count, count)
+		for i := 0; i < count; i++ {
+			out[i] = float32(data[i])
+		}
+		return out, nil
+	}
 
-	return (*[1 << 30]float32)(unsafe.Pointer(&data[0]))[:size]
+	return (*[1 << 30]float32)(unsafe.Pointer(&data[0]))[:count], nil
 }
 
 // loadAccessorU32 loads data from the specified accessor and performs validation of the Type and ComponentType.
@@ -755,7 +833,7 @@ func (g *GLTF) loadAccessorU32(ai int, usage string, validTypes []string, validC
 	// Get Accessor for the specified index
 	ac := g.Accessors[ai]
 	if ac.BufferView == nil {
-		return nil, fmt.Errorf("Accessor.BufferView == nil NOT SUPPORTED YET") // TODO
+		return nil, fmt.Errorf("accessor.BufferView == nil NOT SUPPORTED YET") // TODO
 	}
 
 	// Validate type and component type
@@ -770,7 +848,7 @@ func (g *GLTF) loadAccessorU32(ai int, usage string, validTypes []string, validC
 		return nil, err
 	}
 
-	return g.bytesToArrayU32(data, ac.ComponentType, ac.Count)
+	return g.bytesToArrayU32(data, ac.ComponentType, ac.Count*TypeSizes[ac.Type])
 }
 
 // loadAccessorF32 loads data from the specified accessor and performs validation of the Type and ComponentType.
@@ -779,7 +857,7 @@ func (g *GLTF) loadAccessorF32(ai int, usage string, validTypes []string, validC
 	// Get Accessor for the specified index
 	ac := g.Accessors[ai]
 	if ac.BufferView == nil {
-		return nil, fmt.Errorf("Accessor.BufferView == nil NOT SUPPORTED")
+		return nil, fmt.Errorf("accessor.BufferView == nil NOT SUPPORTED YET") // TODO
 	}
 
 	// Validate type and component type
@@ -794,7 +872,7 @@ func (g *GLTF) loadAccessorF32(ai int, usage string, validTypes []string, validC
 		return nil, err
 	}
 
-	return g.bytesToArrayF32(data, ac.Count*TypeSizes[ac.Type]), nil
+	return g.bytesToArrayF32(data, ac.ComponentType, ac.Count*TypeSizes[ac.Type])
 }
 
 // loadAccessorBytes returns the base byte array used by an accessor.
@@ -802,7 +880,7 @@ func (g *GLTF) loadAccessorBytes(ac Accessor) ([]byte, error) {
 
 	// Get the Accessor's BufferView
 	if ac.BufferView == nil {
-		return nil, fmt.Errorf("Accessor has nil BufferView") // TODO
+		return nil, fmt.Errorf("accessor has nil BufferView") // TODO
 	}
 	bv := g.BufferViews[*ac.BufferView]
 

+ 22 - 0
math32/array.go

@@ -110,6 +110,28 @@ func (a ArrayF32) GetVector4(pos int, v *Vector4) {
 	v.W = a[pos+3]
 }
 
+// GetMatrix4 stores in the specified Matrix4 the
+// values from the array starting at the specified pos.
+func (a ArrayF32) GetMatrix4(pos int, m *Matrix4) {
+
+	m[0] = a[pos]
+	m[1] = a[pos+1]
+	m[2] = a[pos+2]
+	m[3] = a[pos+3]
+	m[4] = a[pos+4]
+	m[5] = a[pos+5]
+	m[6] = a[pos+6]
+	m[7] = a[pos+7]
+	m[8] = a[pos+8]
+	m[9] = a[pos+9]
+	m[10] = a[pos+10]
+	m[11] = a[pos+11]
+	m[12] = a[pos+12]
+	m[13] = a[pos+13]
+	m[14] = a[pos+14]
+	m[15] = a[pos+15]
+}
+
 // GetColor stores in the specified Color the
 // values from the array starting at the specified pos
 func (a ArrayF32) GetColor(pos int, v *Color) {

+ 2 - 0
renderer/renderer.go

@@ -380,11 +380,13 @@ func (r *Renderer) renderScene(iscene core.INode, icam camera.ICamera) error {
 		for _, grmat := range grmats {
 			mat := grmat.IMaterial().GetMaterial()
 			geom := grmat.IGraphic().GetGeometry()
+			gr := grmat.IGraphic().GetGraphic()
 
 			// Add defines from material and geometry
 			r.specs.Defines = *gls.NewShaderDefines()
 			r.specs.Defines.Add(&mat.ShaderDefines)
 			r.specs.Defines.Add(&geom.ShaderDefines)
+			r.specs.Defines.Add(&gr.ShaderDefines)
 
 			// Sets the shader specs for this material and sets shader program
 			r.specs.Name = mat.Shader()

+ 28 - 0
renderer/shaders/include/bones_vertex.glsl

@@ -0,0 +1,28 @@
+#if BONE_INFLUENCERS > 0
+
+    mat4 influence = mBones[int(matricesIndices[0])] * matricesWeights[0];
+    #if BONE_INFLUENCERS > 1
+        influence += mBones[int(matricesIndices[1])] * matricesWeights[1];
+        #if BONE_INFLUENCERS > 2
+            influence += mBones[int(matricesIndices[2])] * matricesWeights[2];
+            #if BONE_INFLUENCERS > 3
+                influence += mBones[int(matricesIndices[3])] * matricesWeights[3];
+//                #if BONE_INFLUENCERS > 4
+//                    influence += mBones[int(matricesIndicesExtra[0])] * matricesWeightsExtra[0];
+//                    #if BONE_INFLUENCERS > 5
+//                        influence += mBones[int(matricesIndicesExtra[1])] * matricesWeightsExtra[1];
+//                        #if BONE_INFLUENCERS > 6
+//                            influence += mBones[int(matricesIndicesExtra[2])] * matricesWeightsExtra[2];
+//                            #if BONE_INFLUENCERS > 7
+//                                influence += mBones[int(matricesIndicesExtra[3])] * matricesWeightsExtra[3];
+//                            #endif
+//                        #endif
+//                    #endif
+//                #endif
+            #endif
+        #endif
+    #endif
+
+    finalWorld = finalWorld * influence;
+
+#endif

+ 9 - 0
renderer/shaders/include/bones_vertex_declaration.glsl

@@ -0,0 +1,9 @@
+#if BONE_INFLUENCERS > 0
+	uniform mat4 mBones[TOTAL_BONES];
+    in vec4 matricesIndices;
+    in vec4 matricesWeights;
+//    #if BONE_INFLUENCERS > 4
+//        in vec4 matricesIndicesExtra;
+//        in vec4 matricesWeightsExtra;
+//    #endif
+#endif

+ 3 - 4
renderer/shaders/include/morphtarget_vertex.glsl

@@ -1,6 +1,5 @@
 #ifdef MORPHTARGETS
-	vPosition += MorphPosition{i} * morphTargetInfluences[{i}];
-  #ifdef MORPHTARGETS_NORMAL
-	vNormal += MorphNormal{i} * morphTargetInfluences[{i}];
-  #endif
+
+    #include <morphtarget_vertex2> [MORPHTARGETS]
+
 #endif

+ 4 - 0
renderer/shaders/include/morphtarget_vertex2.glsl

@@ -0,0 +1,4 @@
+	vPosition += MorphPosition{i} * morphTargetInfluences[{i}];
+  #ifdef MORPHTARGETS_NORMAL
+	vNormal += MorphNormal{i} * morphTargetInfluences[{i}];
+  #endif

+ 5 - 2
renderer/shaders/phong_vertex.glsl

@@ -10,6 +10,7 @@ uniform mat4 MVP;
 
 #include <material>
 #include <morphtarget_vertex_declaration>
+#include <bones_vertex_declaration>
 
 // Output variables for Fragment shader
 out vec4 Position;
@@ -38,8 +39,10 @@ void main() {
 #endif
     FragTexcoord = texcoord;
     vec3 vPosition = VertexPosition;
-    #include <morphtarget_vertex> [MORPHTARGETS]
+    mat4 finalWorld = mat4(1.0);
+    #include <morphtarget_vertex>
+    #include <bones_vertex>
 
-    gl_Position = MVP * vec4(vPosition, 1.0);
+    gl_Position = MVP * finalWorld * vec4(vPosition, 1.0);
 }
 

+ 6 - 2
renderer/shaders/physical_vertex.glsl

@@ -10,6 +10,7 @@ uniform mat3 NormalMatrix;
 uniform mat4 MVP;
 
 #include <morphtarget_vertex_declaration>
+#include <bones_vertex_declaration>
 
 // Output variables for Fragment shader
 out vec3 Position;
@@ -39,9 +40,12 @@ void main() {
     FragTexcoord = texcoord;
 
     vec3 vPosition = VertexPosition;
-    #include <morphtarget_vertex> [MORPHTARGETS]
+    mat4 finalWorld = mat4(1.0);
+    #include <morphtarget_vertex>
+    #include <bones_vertex>
+
+    gl_Position = MVP * finalWorld * vec4(vPosition, 1.0);
 
-    gl_Position = MVP * vec4(vPosition, 1.0);
 }
 
 

+ 68 - 10
renderer/shaders/sources.go

@@ -17,6 +17,47 @@ layout(location = 5) in  vec4  VertexTexoffsets;
 
 `
 
+const include_bones_vertex_source = `#if BONE_INFLUENCERS > 0
+
+    mat4 influence = mBones[int(matricesIndices[0])] * matricesWeights[0];
+    #if BONE_INFLUENCERS > 1
+        influence += mBones[int(matricesIndices[1])] * matricesWeights[1];
+        #if BONE_INFLUENCERS > 2
+            influence += mBones[int(matricesIndices[2])] * matricesWeights[2];
+            #if BONE_INFLUENCERS > 3
+                influence += mBones[int(matricesIndices[3])] * matricesWeights[3];
+//                #if BONE_INFLUENCERS > 4
+//                    influence += mBones[int(matricesIndicesExtra[0])] * matricesWeightsExtra[0];
+//                    #if BONE_INFLUENCERS > 5
+//                        influence += mBones[int(matricesIndicesExtra[1])] * matricesWeightsExtra[1];
+//                        #if BONE_INFLUENCERS > 6
+//                            influence += mBones[int(matricesIndicesExtra[2])] * matricesWeightsExtra[2];
+//                            #if BONE_INFLUENCERS > 7
+//                                influence += mBones[int(matricesIndicesExtra[3])] * matricesWeightsExtra[3];
+//                            #endif
+//                        #endif
+//                    #endif
+//                #endif
+            #endif
+        #endif
+    #endif
+
+    finalWorld = finalWorld * influence;
+
+#endif
+`
+
+const include_bones_vertex_declaration_source = `#if BONE_INFLUENCERS > 0
+	uniform mat4 mBones[TOTAL_BONES];
+    in vec4 matricesIndices;
+    in vec4 matricesWeights;
+//    #if BONE_INFLUENCERS > 4
+//        in vec4 matricesIndicesExtra;
+//        in vec4 matricesWeightsExtra;
+//    #endif
+#endif
+`
+
 const include_lights_source = `//
 // Lights uniforms
 //
@@ -112,13 +153,17 @@ uniform vec3 Material[6];
 `
 
 const include_morphtarget_vertex_source = `#ifdef MORPHTARGETS
-	vPosition += MorphPosition{i} * morphTargetInfluences[{i}];
-  #ifdef MORPHTARGETS_NORMAL
-	vNormal += MorphNormal{i} * morphTargetInfluences[{i}];
-  #endif
+
+    #include <morphtarget_vertex2> [MORPHTARGETS]
+
 #endif
 `
 
+const include_morphtarget_vertex2_source = `	vPosition += MorphPosition{i} * morphTargetInfluences[{i}];
+  #ifdef MORPHTARGETS_NORMAL
+	vNormal += MorphNormal{i} * morphTargetInfluences[{i}];
+  #endif`
+
 const include_morphtarget_vertex_declaration_source = `#ifdef MORPHTARGETS
 	uniform float morphTargetInfluences[MORPHTARGETS];
 	#include <morphtarget_vertex_declaration2> [MORPHTARGETS]
@@ -499,6 +544,7 @@ uniform mat4 MVP;
 
 #include <material>
 #include <morphtarget_vertex_declaration>
+#include <bones_vertex_declaration>
 
 // Output variables for Fragment shader
 out vec4 Position;
@@ -527,9 +573,11 @@ void main() {
 #endif
     FragTexcoord = texcoord;
     vec3 vPosition = VertexPosition;
-    #include <morphtarget_vertex> [MORPHTARGETS]
+    mat4 finalWorld = mat4(1.0);
+    #include <morphtarget_vertex>
+    #include <bones_vertex>
 
-    gl_Position = MVP * vec4(vPosition, 1.0);
+    gl_Position = MVP * finalWorld * vec4(vPosition, 1.0);
 }
 
 `
@@ -963,6 +1011,7 @@ uniform mat3 NormalMatrix;
 uniform mat4 MVP;
 
 #include <morphtarget_vertex_declaration>
+#include <bones_vertex_declaration>
 
 // Output variables for Fragment shader
 out vec3 Position;
@@ -992,9 +1041,12 @@ void main() {
     FragTexcoord = texcoord;
 
     vec3 vPosition = VertexPosition;
-    #include <morphtarget_vertex> [MORPHTARGETS]
+    mat4 finalWorld = mat4(1.0);
+    #include <morphtarget_vertex>
+    #include <bones_vertex>
+
+    gl_Position = MVP * finalWorld * vec4(vPosition, 1.0);
 
-    gl_Position = MVP * vec4(vPosition, 1.0);
 }
 
 
@@ -1205,6 +1257,7 @@ uniform mat4 MVP;
 #include <material>
 #include <phong_model>
 #include <morphtarget_vertex_declaration>
+#include <bones_vertex_declaration>
 
 // Outputs for the fragment shader.
 out vec3 ColorFrontAmbdiff;
@@ -1239,9 +1292,11 @@ void main() {
 #endif
     FragTexcoord = texcoord;
     vec3 vPosition = VertexPosition;
-    #include <morphtarget_vertex> [MORPHTARGETS]
+    mat4 finalWorld = mat4(1.0);
+    #include <morphtarget_vertex>
+    #include <bones_vertex>
 
-    gl_Position = MVP * vec4(vPosition, 1.0);
+    gl_Position = MVP * finalWorld * vec4(vPosition, 1.0);
 }
 
 `
@@ -1250,9 +1305,12 @@ void main() {
 var includeMap = map[string]string{
 
 	"attributes":                      include_attributes_source,
+	"bones_vertex":                    include_bones_vertex_source,
+	"bones_vertex_declaration":        include_bones_vertex_declaration_source,
 	"lights":                          include_lights_source,
 	"material":                        include_material_source,
 	"morphtarget_vertex":              include_morphtarget_vertex_source,
+	"morphtarget_vertex2":             include_morphtarget_vertex2_source,
 	"morphtarget_vertex_declaration":  include_morphtarget_vertex_declaration_source,
 	"morphtarget_vertex_declaration2": include_morphtarget_vertex_declaration2_source,
 	"phong_model":                     include_phong_model_source,

+ 5 - 2
renderer/shaders/standard_vertex.glsl

@@ -12,6 +12,7 @@ uniform mat4 MVP;
 #include <material>
 #include <phong_model>
 #include <morphtarget_vertex_declaration>
+#include <bones_vertex_declaration>
 
 // Outputs for the fragment shader.
 out vec3 ColorFrontAmbdiff;
@@ -46,8 +47,10 @@ void main() {
 #endif
     FragTexcoord = texcoord;
     vec3 vPosition = VertexPosition;
-    #include <morphtarget_vertex> [MORPHTARGETS]
+    mat4 finalWorld = mat4(1.0);
+    #include <morphtarget_vertex>
+    #include <bones_vertex>
 
-    gl_Position = MVP * vec4(vPosition, 1.0);
+    gl_Position = MVP * finalWorld * vec4(vPosition, 1.0);
 }