Просмотр исходного кода

fixed rotation channel to use spherical linear interpolation

Daniel Salvadori 7 лет назад
Родитель
Сommit
28c03973c2
2 измененных файлов с 18 добавлено и 30 удалено
  1. 4 8
      animation/channel.go
  2. 14 22
      math32/quaternion.go

+ 4 - 8
animation/channel.go

@@ -179,11 +179,9 @@ func NewRotationChannel(node core.INode) *RotationChannel {
 				var q1, q2 math32.Vector4
 				rc.values.GetVector4(idx*4, &q1)
 				rc.values.GetVector4((idx+1)*4, &q2)
-				q1.Lerp(&q2, k)
 				quat1 := math32.NewQuaternion(q1.X, q1.Y, q1.Z, q1.W)
-				// TODO spherical linear interpolation (slerp) not working as expected for some reason (doing a lerp for now)
-				//quat2 := math32.NewQuaternion(q2.X, q2.Y, q2.Z, q2.W)
-				//quat1.Slerp(quat2, k)
+				quat2 := math32.NewQuaternion(q2.X, q2.Y, q2.Z, q2.W)
+				quat1.Slerp(quat2, k)
 				node.SetQuaternionQuat(quat1)
 			}
 		case CUBICSPLINE: // TODO
@@ -191,11 +189,9 @@ func NewRotationChannel(node core.INode) *RotationChannel {
 				var q1, q2 math32.Vector4
 				rc.values.GetVector4(idx*4, &q1)
 				rc.values.GetVector4((idx+1)*4, &q2)
-				q1.Lerp(&q2, k)
 				quat1 := math32.NewQuaternion(q1.X, q1.Y, q1.Z, q1.W)
-				// TODO spherical linear interpolation (slerp) not working for some reason
-				//quat2 := math32.NewQuaternion(q2.X, q2.Y, q2.Z, q2.W)
-				//quat1.Slerp(quat2, k)
+				quat2 := math32.NewQuaternion(q2.X, q2.Y, q2.Z, q2.W)
+				quat1.Slerp(quat2, k)
 				node.SetQuaternionQuat(quat1)
 			}
 		}

+ 14 - 22
math32/quaternion.go

@@ -329,50 +329,42 @@ func (q *Quaternion) Slerp(other *Quaternion, t float32) *Quaternion {
 	cosHalfTheta := w*other.W + x*other.X + y*other.Y + z*other.Z
 
 	if cosHalfTheta < 0 {
-
 		q.W = -other.W
 		q.X = -other.X
 		q.Y = -other.Y
 		q.Z = -other.Z
-
 		cosHalfTheta = -cosHalfTheta
-
 	} else {
-
 		q.Copy(other)
 	}
 
 	if cosHalfTheta >= 1.0 {
-
 		q.W = w
 		q.X = x
 		q.Y = y
 		q.Z = z
-
 		return q
-
 	}
 
-	halfTheta := Acos(cosHalfTheta)
-	sinHalfTheta := Sqrt(1.0 - cosHalfTheta + cosHalfTheta)
-
-	if Abs(sinHalfTheta) < 0.001 {
-
-		q.W = 0.5 * (w + q.W)
-		q.X = 0.5 * (x + q.X)
-		q.Y = 0.5 * (y + q.Y)
-		q.Z = 0.5 * (z + q.Z)
-
-		return q
+	sqrSinHalfTheta := 1.0 - cosHalfTheta * cosHalfTheta
+	if sqrSinHalfTheta < 0.001 {
+		s := 1-t
+		q.W = s*w + t*q.W
+		q.X = s*x + t*q.X
+		q.Y = s*y + t*q.Y
+		q.Z = s*z + t*q.Z
+		return q.Normalize()
 	}
 
+	sinHalfTheta := Sqrt( sqrSinHalfTheta )
+	halfTheta := Atan2( sinHalfTheta, cosHalfTheta )
 	ratioA := Sin((1-t)*halfTheta) / sinHalfTheta
 	ratioB := Sin(t*halfTheta) / sinHalfTheta
 
-	q.W = (w*ratioA + q.W*ratioB)
-	q.X = (x*ratioA + q.X*ratioB)
-	q.Y = (y*ratioA + q.Y*ratioB)
-	q.Z = (z*ratioA + q.Z*ratioB)
+	q.W = w*ratioA + q.W*ratioB
+	q.X = x*ratioA + q.X*ratioB
+	q.Y = y*ratioA + q.Y*ratioB
+	q.Z = z*ratioA + q.Z*ratioB
 
 	return q
 }