「VCS/Quaternion2」の編集履歴(バックアップ)一覧はこちら

VCS/Quaternion2 - (2012/12/15 (土) 08:57:18) の1つ前との変更点

追加された行は緑色になります。

削除された行は赤色になります。

|開発環境|Microsoft Visual C# 2010 Express (SP1)| |実行環境|Microsoft Windows XP Home Edition (SP3)| |プロジェクトの種類|空のプロジェクト| |プロジェクト名|Quaternion| 参考 -[[床井研究室 - ゲームグラフィックス特論>http://marina.sys.wakayama-u.ac.jp/~tokoi/?date=20040430]] -[[クォータニオンを"使わない"球面線形補間>http://marupeke296.com/DXG_No57_SheareLinearInterWithoutQu.html]] Program.cs #highlight(c#){{ // Quaternion2 球面線形補間の実験2 using System; using Microsoft.Xna.Framework; // .NET参照 class Program { static void Main() { float rad = MathHelper.ToRadians(120); float x = (float)Math.Cos(rad); float y = (float)Math.Sin(rad); Vector3 v1 = new Vector3(1, 0, 0); Vector3 v2 = new Vector3(x, y, 0); Quaternion q1 = new Quaternion(v1, 0); Quaternion q2 = new Quaternion(v2, 0); Print(v1); Print(v2); Print(q1); Print(q2); int div = 4; float dot = Vector3.Dot(v1, v2); Console.WriteLine(string.Format("dot={0:f2}", dot)); Console.WriteLine("Quaternion.Slerp"); for (int n = 0; n <= div; n++) { float t = n / (float)div; Quaternion q = Quaternion.Slerp(q1, q2, t); float lat = MathHelper.ToDegrees((float)Math.Asin(q.Y)); Console.Write(string.Format("{0} lat={1:f1} / ", n, lat)); Print(q); } Console.WriteLine("Slerp(Quaternion)"); for (int n = 0; n <= div; n++) { float t = n / (float)div; Quaternion q = Slerp(q1, q2, t); float lat = MathHelper.ToDegrees((float)Math.Asin(q.Y)); Console.Write(string.Format("{0} lat={1:f1} / ", n, lat)); Print(q); } Console.WriteLine("Slerp(Vector3)"); for (int n = 0; n <= div; n++) { float t = n / (float)div; Vector3 v = Slerp(v1, v2, t); float lat = MathHelper.ToDegrees((float)Math.Asin(v.Y)); Console.Write(string.Format("{0} lat={1:f1} / ", n, lat)); Print(v); } Console.ReadLine(); } static void Print(Vector3 v) { Console.WriteLine(string.Format("x={0:f2} y={1:f2} z={2:f2} len={3:f2}", v.X, v.Y, v.Z, v.Length())); } static void Print(Quaternion q) { Console.WriteLine(string.Format("x={0:f2} y={1:f2} z={2:f2} w={2:f2} len={3:f2}", q.X, q.Y, q.Z, q.W, q.Length())); } static Vector3 Slerp(Vector3 value1, Vector3 value2, float amount) { value1.Normalize(); value2.Normalize(); float dot = Vector3.Dot(value1, value2); // cosθ float angle = (float)Math.Acos(dot); // 2ベクトル間の角度 float Ps = (float)Math.Sin(angle * (1 - amount)); float Pe = (float)Math.Sin(angle * amount); Vector3 v = (Ps * value1 + Pe * value2) / (float)Math.Sin(angle); v.Normalize(); return v; } static Quaternion Slerp(Quaternion value1, Quaternion value2, float amount) { value1.Normalize(); value2.Normalize(); float dot = Quaternion.Dot(value1, value2); // cosθ float angle = (float)Math.Acos(dot); // 2ベクトル間の角度 float sinTheta = (float)Math.Sin(angle); float Ps = (float)Math.Sin(angle * (1 - amount)) / sinTheta; float Pe = (float)Math.Sin(angle * amount) / sinTheta; Quaternion q = value1 * Ps + value2 * Pe; q.Normalize(); return q; } } }} 出力 x=1.00 y=0.00 z=0.00 len=1.00 x=-0.50 y=0.87 z=0.00 len=1.00 x=1.00 y=0.00 z=0.00 w=0.00 len=0.00 x=-0.50 y=0.87 z=0.00 w=0.00 len=0.00 dot=-0.50 Quaternion.Slerp 0 lat=0.0 / x=1.00 y=0.00 z=0.00 w=0.00 len=0.00 1 lat=-15.0 / x=0.97 y=-0.26 z=0.00 w=0.00 len=0.00 2 lat=-30.0 / x=0.87 y=-0.50 z=0.00 w=0.00 len=0.00 3 lat=-45.0 / x=0.71 y=-0.71 z=0.00 w=0.00 len=0.00 4 lat=-60.0 / x=0.50 y=-0.87 z=0.00 w=0.00 len=0.00 Slerp(Quaternion) 0 lat=0.0 / x=1.00 y=0.00 z=0.00 w=0.00 len=0.00 1 lat=30.0 / x=0.87 y=0.50 z=0.00 w=0.00 len=0.00 2 lat=60.0 / x=0.50 y=0.87 z=0.00 w=0.00 len=0.00 3 lat=90.0 / x=0.00 y=1.00 z=0.00 w=0.00 len=0.00 4 lat=60.0 / x=-0.50 y=0.87 z=0.00 w=0.00 len=0.00 Slerp(Vector3) 0 lat=0.0 / x=1.00 y=0.00 z=0.00 len=1.00 1 lat=30.0 / x=0.87 y=0.50 z=0.00 len=1.00 2 lat=60.0 / x=0.50 y=0.87 z=0.00 len=1.00 3 lat=90.0 / x=0.00 y=1.00 z=0.00 len=1.00 4 lat=60.0 / x=-0.50 y=0.87 z=0.00 len=1.00 考察 クォータニオンの内積は|q1||q2|cosθであり、θが+-90°を超えるとマイナスになる。 つまりベクトルの地球を突き抜けた後ろ側が近くなる。 円周でたとえるなら、0°と120°のベクトルでは120°の後ろ側-60°との距離が最短になる。 それがQuaternion.Slerpの仕様なのかお節介なのかは分からない。 Slerp関数を用意するなら球面線形補間はVector3で済む。
|開発環境|Microsoft Visual C# 2010 Express (SP1)| |実行環境|Microsoft Windows XP Home Edition (SP3)| |プロジェクトの種類|空のプロジェクト| |プロジェクト名|Quaternion| 参考 -[[床井研究室 - ゲームグラフィックス特論>http://marina.sys.wakayama-u.ac.jp/~tokoi/?date=20040430]] -[[クォータニオンを"使わない"球面線形補間>http://marupeke296.com/DXG_No57_SheareLinearInterWithoutQu.html]] Program.cs #highlight(c#){{ // Quaternion2 球面線形補間の実験2 using System; using Microsoft.Xna.Framework; // .NET参照 class Program { static void Main() { float rad = MathHelper.ToRadians(120); float x = (float)Math.Cos(rad); float y = (float)Math.Sin(rad); Vector3 v1 = new Vector3(1, 0, 0); Vector3 v2 = new Vector3(x, y, 0); Quaternion q1 = new Quaternion(v1, 0); Quaternion q2 = new Quaternion(v2, 0); Print(v1); Print(v2); Print(q1); Print(q2); int div = 4; float dot = Vector3.Dot(v1, v2); Console.WriteLine(string.Format("dot={0:f2}", dot)); Console.WriteLine("Quaternion.Slerp"); for (int n = 0; n <= div; n++) { float t = n / (float)div; Quaternion q = Quaternion.Slerp(q1, q2, t); float lat = MathHelper.ToDegrees((float)Math.Asin(q.Y)); Console.Write(string.Format("{0} lat={1:f1} / ", n, lat)); Print(q); } Console.WriteLine("Slerp(Quaternion)"); for (int n = 0; n <= div; n++) { float t = n / (float)div; Quaternion q = Slerp(q1, q2, t); float lat = MathHelper.ToDegrees((float)Math.Asin(q.Y)); Console.Write(string.Format("{0} lat={1:f1} / ", n, lat)); Print(q); } Console.WriteLine("Slerp(Vector3)"); for (int n = 0; n <= div; n++) { float t = n / (float)div; Vector3 v = Slerp(v1, v2, t); float lat = MathHelper.ToDegrees((float)Math.Asin(v.Y)); Console.Write(string.Format("{0} lat={1:f1} / ", n, lat)); Print(v); } Console.ReadLine(); } static void Print(Vector3 v) { Console.WriteLine(string.Format("x={0:f2} y={1:f2} z={2:f2} len={3:f2}", v.X, v.Y, v.Z, v.Length())); } static void Print(Quaternion q) { Console.WriteLine(string.Format("x={0:f2} y={1:f2} z={2:f2} w={3:f2} len={4:f2}", q.X, q.Y, q.Z, q.W, q.Length())); } static Vector3 Slerp(Vector3 value1, Vector3 value2, float amount) { value1.Normalize(); value2.Normalize(); float dot = Vector3.Dot(value1, value2); // cosθ float angle = (float)Math.Acos(dot); // 2ベクトル間の角度 float Ps = (float)Math.Sin(angle * (1 - amount)); float Pe = (float)Math.Sin(angle * amount); Vector3 v = (Ps * value1 + Pe * value2) / (float)Math.Sin(angle); v.Normalize(); return v; } static Quaternion Slerp(Quaternion value1, Quaternion value2, float amount) { value1.Normalize(); value2.Normalize(); float dot = Quaternion.Dot(value1, value2); // cosθ float angle = (float)Math.Acos(dot); // 2ベクトル間の角度 float sinTheta = (float)Math.Sin(angle); float Ps = (float)Math.Sin(angle * (1 - amount)) / sinTheta; float Pe = (float)Math.Sin(angle * amount) / sinTheta; Quaternion q = value1 * Ps + value2 * Pe; q.Normalize(); return q; } } }} 出力 x=1.00 y=0.00 z=0.00 len=1.00 x=-0.50 y=0.87 z=0.00 len=1.00 x=1.00 y=0.00 z=0.00 w=0.00 len=1.00 x=-0.50 y=0.87 z=0.00 w=0.00 len=1.00 dot=-0.50 Quaternion.Slerp 0 lat=0.0 / x=1.00 y=0.00 z=0.00 w=0.00 len=1.00 1 lat=-15.0 / x=0.97 y=-0.26 z=0.00 w=0.00 len=1.00 2 lat=-30.0 / x=0.87 y=-0.50 z=0.00 w=0.00 len=1.00 3 lat=-45.0 / x=0.71 y=-0.71 z=0.00 w=0.00 len=1.00 4 lat=-60.0 / x=0.50 y=-0.87 z=0.00 w=0.00 len=1.00 Slerp(Quaternion) 0 lat=0.0 / x=1.00 y=0.00 z=0.00 w=0.00 len=1.00 1 lat=30.0 / x=0.87 y=0.50 z=0.00 w=0.00 len=1.00 2 lat=60.0 / x=0.50 y=0.87 z=0.00 w=0.00 len=1.00 3 lat=90.0 / x=0.00 y=1.00 z=0.00 w=0.00 len=1.00 4 lat=60.0 / x=-0.50 y=0.87 z=0.00 w=0.00 len=1.00 Slerp(Vector3) 0 lat=0.0 / x=1.00 y=0.00 z=0.00 len=1.00 1 lat=30.0 / x=0.87 y=0.50 z=0.00 len=1.00 2 lat=60.0 / x=0.50 y=0.87 z=0.00 len=1.00 3 lat=90.0 / x=0.00 y=1.00 z=0.00 len=1.00 4 lat=60.0 / x=-0.50 y=0.87 z=0.00 len=1.00 考察 クォータニオンの内積は|q1||q2|cosθであり、θが+-90°を超えるとマイナスになる。 つまりベクトルの地球を突き抜けた後ろ側が近くなる。 円周でたとえるなら、0°と120°のベクトルでは120°の後ろ側-60°との距離が最短になる。 それがQuaternion.Slerpの仕様なのかお節介なのかは分からない。 Slerp関数を用意するなら球面線形補間はVector3で済む。

表示オプション

横に並べて表示:
変化行の前後のみ表示: