| 404 | } |
| 405 | |
| 406 | void Quaternion::GetRotationFromTo(const Float3& from, const Float3& to, Quaternion& result, const Float3& fallbackAxis) |
| 407 | { |
| 408 | // Based on Stan Melax's article in Game Programming Gems |
| 409 | |
| 410 | Float3 v0 = from; |
| 411 | Float3 v1 = to; |
| 412 | v0.Normalize(); |
| 413 | v1.Normalize(); |
| 414 | |
| 415 | // If dot == 1, vectors are the same |
| 416 | const float d = Float3::Dot(v0, v1); |
| 417 | if (d >= 1.0f) |
| 418 | { |
| 419 | result = Identity; |
| 420 | return; |
| 421 | } |
| 422 | |
| 423 | if (d < 1e-6f - 1.0f) |
| 424 | { |
| 425 | if (fallbackAxis != Float3::Zero) |
| 426 | { |
| 427 | // Rotate 180 degrees about the fallback axis |
| 428 | RotationAxis(fallbackAxis, PI, result); |
| 429 | } |
| 430 | else |
| 431 | { |
| 432 | // Generate an axis |
| 433 | Float3 axis = Float3::Cross(Float3::UnitX, from); |
| 434 | if (axis.LengthSquared() < ZeroTolerance) // Pick another if colinear |
| 435 | axis = Float3::Cross(Float3::UnitY, from); |
| 436 | axis.Normalize(); |
| 437 | RotationAxis(axis, PI, result); |
| 438 | } |
| 439 | } |
| 440 | else |
| 441 | { |
| 442 | const float s = Math::Sqrt((1 + d) * 2); |
| 443 | const float invS = 1 / s; |
| 444 | |
| 445 | Float3 c; |
| 446 | Float3::Cross(v0, v1, c); |
| 447 | |
| 448 | result.X = c.X * invS; |
| 449 | result.Y = c.Y * invS; |
| 450 | result.Z = c.Z * invS; |
| 451 | result.W = s * 0.5f; |
| 452 | result.Normalize(); |
| 453 | } |
| 454 | } |
| 455 | |
| 456 | void Quaternion::FindBetween(const Float3& from, const Float3& to, Quaternion& result) |
| 457 | { |
nothing calls this directly
no test coverage detected