Quaternion

このページは過去の情報となります。
新しいスクリプトリファレンスはこちらになります。

QuaternionはX,Y,Z,Wの4つの値を持ったクラスです。
回転を表現するクラスですが、値を直接指定してQuaternionを直接変化させる事はありません。
基本的に、変化させたい場合は下記にあげる関数を使用して変化させます。

名前 説明 バージョン
_new 初期化
FromToRotation fromDirection→toDirectionへ回転
Inverse rotationと逆のQuaternionを作成
Slerp a と b の間を t で球面補間 [0≦t≦1]
SlerpUnclamped t の値を制限しないSlerp
Lerp a と b の間を t で線形補間 [0≦t≦1](バネ)
LerpUnclamped t の値を制限しないSlerp(バネ)
AngleAxis Axisのベクトルを軸にAngle度回転
LookRotation forwardとupwardsに対応する方向に設定
Dot 2の回転 a と b の内積を返す
Angle 2つの回転 a と b の角度を返す
Euler オイラー角でQuaternionを作成
ToAngleAxis(使用不可) 回転を座標に対する角度の値 (AngleAxis) に変換
RotateTowards 2つのQuaternion間の最大となる回転を補間
Normalize qのノルムを1にし、単位Quaternionを返す
GetHashCode 使用しない
ToString 文字列に変換
ToEuler(非推奨) オイラー角に変換する場合は'eulerAngles'が推奨
ToEulerAngles(非推奨) オイラー角に変換する場合は'eulerAngles'が推奨
identity (0, 0, 0, 1)の基準となるQuaternionを作成
eulerAngles 回転をオイラー角の値で返す
normalized 単位Quaternionを返す
x num ※基本的に直接Quaternionを変更しない
y num
z num
w num
kEpsilon num

初期化について

サンプル

main.lua
rotate = Quaternion.identity
print(rotate)

実行結果

(0.0, 0.0, 0.0, 1.0)

基本的にQuaternion.identityでQuaternionを初期化します。
__new()でも宣言可能ですが、Quaternionを直接扱う事は少ないです。
また、上記のサンプルではrotate.x = 1とする事で、各要素に対して直接アクセス可能ですが、Quaternionを操作する際は用意された関数を使い操作する事を推奨します。

サンプル

main.lua
--SunItemのゲームオブジェクト名とGetTransform("")の("")の中を一致させる必要があります。
Subitem = vci.assets.GetTransform("Subitem")
function onUngrab()
    local rotate = Quaternion.identity
    local velocity = Vector3.zero
    Subitem.SetLocalRotation(rotate)
    Subitem.SetVelocity(velocity)
end

実行結果

(VCIをつかんだ状態から離すと、回転(Rotation)が初期状態(x = 0, y = 0, z = 0)になります。)

SetLocalRotation()を使う事で、作成したQuaternionの姿勢にする事ができます。
その際は、姿勢を変更した後にSetVelocity()を0にする事で、rigidbodyによる姿勢の更新を防ぎます。

FromToRotation

FromToRotation fun(fromDirection: Vec3, toDirection: Vec3): Quaternion
2つのベクトルの差分をQuaternionで返します。

サンプル

main.lua
local Subitem = vci.assets.GetTransform("Subitem")
local Subitem2 = vci.assets.GetTransform("Subitem2")
 
function updateAll()
    local Vec1 = Subitem.GetUp();
    local Vec2 = Subitem2.GetPosition() - Subitem.GetPosition();
    local Rot1 = Subitem.GetRotation();
    local Rot2 = Quaternion.FromToRotation(Vec1, Vec2);
    local Rot3 = Rot2*Rot1;
 
    Subitem.SetRotation(Rot3);
end

実行結果

Subitemの上面(up)が常にSubitem2の方向を向きます。
ただし、LookRotationを使った方が安定します。

Inverse

Inverse fun(rotation: Quaternion): Quaternion
逆のQuaternionを作成します。

サンプル

main.lua
local Subitem = vci.assets.GetTransform("Subitem")
local Subitem2 = vci.assets.GetTransform("Subitem2")
 
function updateAll()
    Subitem.SetRotation(Quaternion.Inverse(Subitem2.GetRotation()));
end

実行結果

Subitemが常にSubitem2と逆に回転します。

Slerp

Slerp fun(a: Quaternion, b: Quaternion, t: num): Quaternion
第一引数 と 第二引数 の間を 第三引数の値 で球面補間します。
第三引数の値 は[0, 1]の範囲です。

サンプル1

main.lua
local Subitem = vci.assets.GetTransform("Subitem")
local Subitem2 = vci.assets.GetTransform("Subitem2")
 
function updateAll()
    -- time [0,1]
    local time = 0.5 * math.sin(os.time()) + 0.5
    local rotate = Quaternion.identity
    Subitem.SetRotation(Quaternion.Slerp(rotate, Subitem2.GetRotation(), time));
end

実行結果1

Subitemが(0,0,0,1)からSubitem2の角度へ球面補間を行って往復回転します。


サンプル2

main.lua
local Subitem = vci.assets.GetTransform("Subitem")
local Subitem2 = vci.assets.GetTransform("Subitem2")
 
function updateAll()
    Subitem.SetRotation(Quaternion.Slerp(Subitem.GetRotation(), Subitem2.GetRotation(), 0.01));
end

実行結果2

SubitemがSubitem2の角度へゆっくり回転します。

SlerpUnclamped

SlerpUnclamped fun(a: Quaternion, b: Quaternion, t: num): Quaternion
Slerpと同じですが、第三引数 の値を[0, 1]に制限しません。

サンプル

main.lua
local Subitem = vci.assets.GetTransform("Subitem")
local Subitem2 = vci.assets.GetTransform("Subitem2")
 
function updateAll()
    -- time [0,2]
    local time = math.sin(os.time()) + 1
    local rotate = Quaternion.identity
    Subitem.SetRotation(Quaternion.SlerpUnclamped(rotate, Subitem2.GetRotation(), time));
end

実行結果

Subitemが(0,0,0,1)からSubitem2の角度を通り越して球面補間を行って往復回転します。

Lerp

Lerp fun(a: Quaternion, b: Quaternion, t: num): Quaternion
第一引数 と 第二引数 の間を 第三引数の値 で線形補間します。
第三引数の値 は[0, 1]の範囲です。

サンプル1

main.lua
local Subitem = vci.assets.GetTransform("Subitem")
local Subitem2 = vci.assets.GetTransform("Subitem2")
 
function updateAll()
    -- time [0,1]
    local time = 0.5 * math.sin(os.time()) + 0.5
    local rotate = Quaternion.identity
    Subitem.SetRotation(Quaternion.Lerp(rotate, Subitem2.GetRotation(), time));
end

実行結果1

Subitemが(0,0,0,1)からSubitem2の角度へ線形補間を行って往復回転します。


サンプル2

main.lua
--SunItemのゲームオブジェクト名とGetTransform("")の("")の中を一致させる必要があります。
Subitem = vci.assets.GetTransform("Subitem")
base = Quaternion.identity
target = Quaternion.Euler(0, 90, 0)
function update()
    local time = math.abs(math.sin((vci.me.FrameCount / 60)))
    local lerp = Quaternion.Lerp(base, target, time)
    Subitem.SetRotation(lerp)
end

実行結果2

(Subitemがゆっくりと振幅するように90度回転します。)

説明
基準となるQuaternionと、ターゲットになるQuaternionの中間を補間するQuaternionを作成します。
0-1の値で指定すると指定した値の%に応じたQuaternionが返ってきます。
ゆっくりと値を変化させることで、特定の姿勢から特定の姿勢にゆっくりと変化します。

LerpUnclamped

LerpUnclamped fun(a: Quaternion, b: Quaternion, t: num): Quaternion
Lerpと同じですが、第三引数 の値を[0, 1]に制限しません。

サンプル

main.lua
local Subitem = vci.assets.GetTransform("Subitem")
local Subitem2 = vci.assets.GetTransform("Subitem2")
 
function updateAll()
    -- time [0,2]
    local time = math.sin(os.time()) + 1
    local rotate = Quaternion.identity
    Subitem.SetRotation(Quaternion.LerpUnclamped(rotate, Subitem2.GetRotation(), time));
end

実行結果

Subitemが(0,0,0,1)からSubitem2の角度を通り越して線形補間を行って往復回転します。

AngleAxis

AngleAxis fun(angle: number, axis: Vector3): Quaternion
Vector3で方向を指定してその方向を回転の軸とし、angleの値だけ回転させます。
サンプルではaxis = Vector3.upで下から上に向かった軸を作成して回転させています。
angleは0~360の値で指定します。

サンプル

main.lua
--SunItemのゲームオブジェクト名とGetTransform("")の("")の中を一致させる必要があります。
local _subitem = vci.assets.GetTransform("Subitem")
local _angle = 0
function onUse()
    _angle = _angle + 10
    if _angle > 360 then
        _angle = 0
    end
    print("angle : ".._angle)
 
    local axis = Vector3.up
    local rotate = Quaternion.AngleAxis(_angle, axis)
    Subitem.SetRotation(rotate)
end

実行結果

(VCIをUseすると10度づつ回転します)

LookRotation

LookRotation fun(forward: Vector3, upwards: Vector3): Quaternion
upのベクトルと、forwardのベクトルを使用して、Quaternionを作成します。
サンプルではrotatevci.assets.GetTransform(target).GetRotation()は同じ値をとります。

サンプル1

main.lua
function onUngrab(target)
    local forward = vci.assets.GetTransform(target).GetForward()
    local up = vci.assets.GetTransform(target).GetUp()
    local rotate = Quaternion.LookRotation(forward, up)
    print(rotate)
    print(vci.assets.GetTransform(target).GetRotation())
end

実行結果1

(0.0, -0.3, -0.1, 1.0)
(0.0, -0.3, -0.1, 1.0)
(0.0, 0.9, 0.0, 0.4)
(0.0, 0.9, 0.0, 0.4)


サンプル2

main.lua
local Subitem = vci.assets.GetTransform("Subitem")
local Subitem2 = vci.assets.GetTransform("Subitem2")
 
function updateAll()
    local Vec = Subitem2.GetPosition() - Subitem.GetPosition();
    Subitem.SetRotation(Quaternion.LookRotation(Vec));
end

実行結果2

Subitemが常にSubitem2の方を向きます。

Dot

Dot fun(a: Quaternion, b: Quaternion): number
2つのQuaternionを比較して、その内積をとります。
戻り値は-1~1の間になります。

サンプル

main.lua
function onUngrab(target)
    local rotate = vci.assets.GetTransform(target).GetRotation()
    local base = Quaternion.identity
    print(Quaternion.Dot(rotate, base))
end

実行結果

0.886427819728851
-0.289039075374603
(VCIを手から離した時に、つかんだアイテムとbaseとの内積をとります)

Angle

Angle fun(a: Quaternion, b: Quaternion): number
第一引数 と 第二引数 の角度を返します。

サンプル

main.lua
function onUse(use)
    local base = Quaternion.Euler(0, 10, 0)
    local target = Quaternion.Euler(0, 135, 0)
    print(Quaternion.Angle(base, target));
end

実行結果

(125)

Euler

Euler fun(x: number, y: number, z: number): Quaternion
回転をオイラー角(0°~360°)の値で指定し、Quaternionを作成します。
要素の指定は前から X → Y → Z の順に行います。

サンプル

main.lua
---SunItemのゲームオブジェクト名とGetTransform("")の("")の中を一致させる必要があります。
Subitem = vci.assets.GetTransform("Subitem")
function onUngrab()
    local rotate = Quaternion.Euler(30, 45, 60)
    local velocity = Vector3.zero
    Subitem.SetLocalRotation(rotate)
    Subitem.SetVelocity(velocity)
end

実行結果

(VCIをつかんだ状態から離すと、回転(Rotation)(x = 30, y = 45, z = 60)になります。)

ToAngleAxis(使用不可)

ToAngleAxis fun(angle: usertype, axis: usertype)
回転を座標に対する角度の値 (AngleAxis) に変換します。
※現在使用することが出来ません。

サンプル

main.lua
function onUse(use)
    local rotate = Quaternion.AngleAxis(30.0, Vector3.up)
    local angle = 0
    local axis = Vector3.zero
    print(rotate)
    rotate.ToAngleAxis(angle, axis)
    print(angle)
    print(axis)
end

実行結果

現在ToAngleAxisを使用することができません。

RotateTowards

RotateTowards fun(from: Quaternion, to: Quaternion, maxDegreesDelta: num): Quaternion
2つのQuaternion間の最大となる回転を補間します。

サンプル

main.lua
local Subitem = vci.assets.GetTransform("Subitem")
local Subitem2 = vci.assets.GetTransform("Subitem2")
 
function updateAll()
    local move = Quaternion.RotateTowards(Subitem.GetRotation(), Subitem2.GetRotation(), 0.25,0)
    Subitem.SetRotation(move)
end

実行結果

Subitemの回転がSubitem2の角度と同じになるように毎フレーム0.25度ずつ回転します

Normalize

Normalize fun(q: Quaternion): Quaternion
qのノルムを1にし、単位Quaternionを返します。
引数なしで四元数quatの関数として使った場合(例:quat.Normalize())、オブジェクト側(quat)の値の変更がなされます。

サンプル

main.lua
function onUse(use)
    local zero = Quaternion.identity
    local rotate = Quaternion.Euler(0, 280, 180)
    rotate.x = 2
    print(rotate)
    print(Quaternion.Normalize(rotate))
end

実行結果

(2.0, 0.0, -0.8, 0.0)
(0.9, 0.0, -0.4, 0.0)

ToString

ToString fun(): string
文字列に変換します。

サンプル

main.lua
function onUse(use)
    local rotate = Quaternion.identity
    print(rotate.ToString())
end

実行結果

"(0.0, 0.0, 0.0, 1.0)"

ToEuler(非推奨)

ToEuler fun(): Vector3
ToEuler()は非推奨です。オイラー角に変換する場合は'eulerAngles'が推奨されます。
-πrad ~ πradの範囲で値を返します。

サンプル

main.lua
function onUse(use)
    local rotate = Quaternion.Euler(60, 270, 30)
    print(rotate)
    print(rotate.ToEuler()*180/3.14159265359)
end

実行結果

(60, -90, 30)

ToEulerAngles(非推奨)

EulerAngles fun(x: number, y: number, z: number): Quaternion
ToEulerAngles()は非推奨です。オイラー角に変換する場合は'eulerAngles'が推奨されます。
-πrad ~ πradの範囲で値を返します。

サンプル

main.lua
function onUse(use)
    local rotate = Quaternion.Euler(60, 270, 30)
    print(rotate)
    print(rotate.ToEulerAngles()*180/3.14159265359)
end

実行結果

(60, -90, 30)

identity

identity Quaternion
基本的にQuaternion.identityでQuaternionを初期化します。

サンプル

main.lua
rotate = Quaternion.identity
print(rotate)

実行結果

(0.0, 0.0, 0.0, 1.0)

eulerAngles

eulerAngles Vector3
Quaternionの値をオイラー角の値で返します。
eulerAngles.の後にアクセスしたい要素を指定する事で個別にアクセスする事も可能です。

サンプル

main.lua
euler = Quaternion.Euler(30, 45, 60)
print(euler)
print(euler.eulerAngles)
print(euler.eulerAngles.x)
print(euler.eulerAngles.y)
print(euler.eulerAngles.z)

実行結果

(0.4, 0.2, 0.4, 0.8)
(30.0, 45.0, 60.0)
30.0000019073486
45
60.0000038146973

normalized

normalized Quaternion 単位Quaternionを返します。

サンプル

main.lua
function onUse(use)
    local rotate = Quaternion.Euler(0,280, 180)
    rotate.x = 2
    print(rotate)
    print(rotate.normalized)
end

実行結果

(2.0, 0.0, -0.8, 0.0)
(0.9, 0.0, -0.4, 0.0)