Bläddra i källkod

fixed morph geometry and morph target animation

Daniel Salvadori 7 år sedan
förälder
incheckning
472d9f7944
2 ändrade filer med 52 tillägg och 29 borttagningar
  1. 6 4
      animation/channel.go
  2. 46 25
      geometry/morph.go

+ 6 - 4
animation/channel.go

@@ -270,10 +270,11 @@ func NewMorphChannel(mg *geometry.MorphGeometry) *MorphChannel {
 				start2 := (idx+1)*numWeights
 				weights1 := mc.values[start1:start1+numWeights]
 				weights2 := mc.values[start2:start2+numWeights]
+				weightsNew := make([]float32, numWeights)
 				for i := range weights1 {
-					weights1[i] += (weights2[i]-weights1[i])*k
+					weightsNew[i] = weights1[i] + (weights2[i]-weights1[i])*k
 				}
-				mg.SetWeights(weights1)
+				mg.SetWeights(weightsNew)
 			}
 		case CUBICSPLINE: // TODO
 			mc.interpAction = func(idx int, k float32) {
@@ -281,10 +282,11 @@ func NewMorphChannel(mg *geometry.MorphGeometry) *MorphChannel {
 				start2 := (idx+1)*numWeights
 				weights1 := mc.values[start1:start1+numWeights]
 				weights2 := mc.values[start2:start2+numWeights]
+				weightsNew := make([]float32, numWeights)
 				for i := range weights1 {
-					weights1[i] += (weights2[i]-weights1[i])*k
+					weightsNew[i] = weights1[i] + (weights2[i]-weights1[i])*k
 				}
-				mg.SetWeights(weights1)
+				mg.SetWeights(weightsNew)
 			}
 		}
 	}

+ 46 - 25
geometry/morph.go

@@ -92,6 +92,12 @@ func (mg *MorphGeometry) AddMorphTargets(morphTargets ...*Geometry) {
 	}
 	mg.targets = append(mg.targets, morphTargets...)
 
+	// Update all target attributes if we have few enough that we are able to send them
+	// all to the shader without sorting and choosing the ones with highest current weight
+	if len(mg.targets) <= NumMorphTargets {
+		mg.UpdateTargetAttributes(mg.targets)
+	}
+
 }
 
 // AddMorphTargetDeltas add multiple morph target deltas to the morph geometry.
@@ -101,6 +107,12 @@ func (mg *MorphGeometry) AddMorphTargetDeltas(morphTargetDeltas ...*Geometry) {
 		mg.weights = append(mg.weights, 0)
 	}
 	mg.targets = append(mg.targets, morphTargetDeltas...)
+
+	// Update all target attributes if we have few enough that we are able to send them
+	// all to the shader without sorting and choosing the ones with highest current weight
+	if len(mg.targets) <= NumMorphTargets {
+		mg.UpdateTargetAttributes(mg.targets)
+	}
 }
 
 // ActiveMorphTargets sorts the morph targets by weight and returns the top n morph targets with largest weight.
@@ -111,27 +123,25 @@ func (mg *MorphGeometry) ActiveMorphTargets() ([]*Geometry, []float32) {
 		return nil, nil
 	}
 
-	sortedMorphTargets := make([]*Geometry, numTargets)
-	copy(sortedMorphTargets, mg.targets)
-	sort.Slice(sortedMorphTargets, func(i, j int) bool {
-		return mg.weights[i] > mg.weights[j]
-	})
-
-	sortedWeights := make([]float32, numTargets)
-	copy(sortedWeights, mg.weights)
-	sort.Slice(sortedWeights, func(i, j int) bool {
-		return mg.weights[i] > mg.weights[j]
-	})
-
-
-	// TODO check current 0 weights
+	if numTargets <= NumMorphTargets {
+		// No need to sort - just return the targets and weights directly
+		return mg.targets, mg.weights
+	} else {
+		// Need to sort them by weight and only return the top N morph targets with largest weight (N = NumMorphTargets)
+		// TODO test this (more than [NumMorphTargets] morph targets)
+		sortedMorphTargets := make([]*Geometry, numTargets)
+		copy(sortedMorphTargets, mg.targets)
+		sort.Slice(sortedMorphTargets, func(i, j int) bool {
+			return mg.weights[i] > mg.weights[j]
+		})
 
-	//if len(mg.targets) < NumMorphTargets-1 {
+		sortedWeights := make([]float32, numTargets)
+		copy(sortedWeights, mg.weights)
+		sort.Slice(sortedWeights, func(i, j int) bool {
+			return mg.weights[i] > mg.weights[j]
+		})
 		return sortedMorphTargets, sortedWeights
-	//} else {
-	//	return sortedMorphTargets[:NumMorphTargets-1]
-	//}
-
+	}
 }
 
 // SetIndices sets the indices array for this geometry.
@@ -164,6 +174,16 @@ func (mg *MorphGeometry) Dispose() {
 	}
 }
 
+// UpdateTargetAttributes updates the attribute names of the specified morph targets in order.
+func (mg *MorphGeometry) UpdateTargetAttributes(morphTargets []*Geometry) {
+
+	for i, mt := range morphTargets {
+		mt.SetAttributeName(gls.VertexPosition, "MorphPosition"+strconv.Itoa(i))
+		mt.SetAttributeName(gls.VertexNormal, "MorphNormal"+strconv.Itoa(i))
+		mt.SetAttributeName(gls.VertexTangent, "MorphTangent"+strconv.Itoa(i))
+	}
+}
+
 // RenderSetup is called by the renderer before drawing the geometry.
 func (mg *MorphGeometry) RenderSetup(gs *gls.GLS) {
 
@@ -172,13 +192,14 @@ func (mg *MorphGeometry) RenderSetup(gs *gls.GLS) {
 	// Sort weights and find top 8 morph targets with largest current weight (8 is the max sent to shader)
 	activeMorphTargets, activeWeights := mg.ActiveMorphTargets()
 
-	for i, mt := range activeMorphTargets {
-
-		mt.SetAttributeName(gls.VertexPosition, "MorphPosition"+strconv.Itoa(i))
-		mt.SetAttributeName(gls.VertexNormal, "MorphNormal"+strconv.Itoa(i))
-		//mt.SetAttributeName(vTangent, fmt.Sprintf("MorphTangent[%d]", i))
+	// If the morph geometry has more targets than the shader supports we need to update attribute names
+	// as weights change - we only send the top morph targets with highest weight
+	if len(mg.targets) > NumMorphTargets {
+		mg.UpdateTargetAttributes(activeMorphTargets)
+	}
 
-		// Transfer morphed geometry VBOs
+	// Transfer morphed geometry VBOs
+	for _, mt := range activeMorphTargets {
 		for _, vbo := range mt.VBOs() {
 			vbo.Transfer(gs)
 		}