はじめに
本記事は「VCI(VirtualCast Interactive) Advent Calendar 2025」12/25の投稿となります。
なんてこった
11月のある日、小山内しのぶさんから、
「Quatanion強化週間をやりますので記事を書いていただけないでしょうか」(超略)
とご丁寧なメールをいただきました。
簡単に引き受けたのですが、オイラー角をQuatanionに変換するとき使うってくらいです。
過去の自分の記事を調べてみると少しだけ書いてました。
やばいぞ、ネタが無い。
魔法の杖でも作ってクルクルさせよう!
Itemをなんかいい感じに回転させるVCIを作って説明しましょう。
杖の先端がクルクル回るととか需要ありそうですよね。
と思ったら。
需要ありすぎて、すでにしろひげさんが説明していました・・・
「魔法陣を回転させよう(アイテムの追従とクォータニオン)」@sirohige (しろひげ)
それでも回したい
私が考えていた回し方とちょっと違うので、とりあえず作って比較してみようと思います。
しろひげさん方式のほかに2種類ほどサンプルを作ります。
杖の先に鉢巻みたいな帯をつけて回すサンプルを作ります。
テスト用3Dデータ作成
テストに使う3Dデータはこんな感じです。
黄色:杖1、SubSubItem方式1:棒01(SubItem)、帯01(棒01の下のSubItem)
赤色:杖2、SubSubItem方式2:棒02(SubItem)、帯02(棒02の下のSubItem)
青色:杖3、SubItem方式(しろひげさんの記事参照):棒03(SubItem)、帯03(SubItem)
帯にはそれぞれ01,02,03の番号を入れて回します。
良い感じの何か作るときはそれっぽいエフェクトや梵字でも入れてください。
帯01と帯02はいわゆるSubSubItemとなります、これが重要なポイントです。
それぞれの棒にはコライダーを入れて掴めるようにしておきましょう。
こんな感じでLuaを書いてみました
-- Quaternionを使った動作サンプル
-- 2025/11/17 検討開始
-- 2025/11/18 回すサンプルコード記載
print("GuruguruSample Ver.01")
-- 帯を回せ
-- アイテム取り込み
local Bou1 = vci.assets.GetTransform("Bou01")
local Bou2 = vci.assets.GetTransform("Bou02")
local Bou3 = vci.assets.GetTransform("Bou03")
local Obi1 = vci.assets.GetTransform("Obi01")
local Obi2 = vci.assets.GetTransform("Obi02")
local Obi3 = vci.assets.GetTransform("Obi03")
-- 回転パラメーター
local Step = 5
local R2 = Quaternion.Euler(0,Step,0) -- 柱BのY軸回転を示すQuaternion
-- 回転情報取得用
local rotate1 -- 棒1の角度を入れる変数宣言
local rotate2 -- 棒2の角度を入れる変数宣言
local rotate3 -- 棒3の角度を入れる変数宣言
local PosBou3 -- 帯3の位置を入れる変数宣言
-- 動作回数のパラメータ
-- フレームCMax回くらい動作させてみる
local Count = 0 -- カウンターの初期値
local CMax = 5 -- CMaxフレームに1回実行するための設定
local RCount = 0
local Offset = Vector2.__new(0.1, 0)
function updateAll()
--print("Test")
if Count <= CMax then -- フレームをスキップするための判定
Count = Count+1
return
end
Count = 0 -- スキップ分が終了したのでカウンターの初期化
--print("Test00")
-- 杖3の帯回転 SubItemなので所有者のみが帯移動と回転
if Bou3.IsMine then
--print("Test01")
rotate3 = Bou3.GetRotation() -- 角度の取り込み Quatanion
PosBou3 = Bou3.GetPosition() -- 座標の取り込み
Obi3.SetRotation(rotate3*Quaternion.Euler(0,Step*RCount,0)) -- 帯3角度を計算
Obi3.SetPosition(PosBou3 + Bou3.GetNormalizedUp(Bou3)*0.6) -- 帯3座標を計算
--print(RCount)
end
-- 杖1の帯回転
rotate1 = Bou1.GetRotation() -- 棒1の角度取り込み Quatanion
Obi1.SetRotation(rotate1*Quaternion.Euler(0,Step*RCount,0)) -- 帯1角度を変更
-- 杖2のテクスチャスクロール
vci.assets.material.SetTextureOffset("Obi02",Vector2.__new(1/(360/Step)*RCount, 0)) -- テクスチャスクロール
-- 帯の回転角度計算
RCount = RCount%(math.floor(360/Step))+1
end
杖1,3はQuaternionを使って帯を回しています。
杖3はしろひげさん方式なので、位置計算も行っていますね。すごい( ゚Д゚)
杖2は比較のためテクスチャスクロールを使って回しています。
杖1:SubSubItemをQuaternionで回す
杖2:テクスチャスクロールで回す
杖3:SubItemを回す(しろひげさん方式)
1,2,3の利点欠点は後で説明します。
VCIを出して動かしてみた
杖が止まっている状態で帯の回転を見てみましょう。
全部同じような感じで見えると思います。
同じように動いているのでとりあえず良しです。
杖を振り回してみよう
杖を振り回して帯の動きを見てみよう。
杖3のSubItemを計算して移動する方は、どうしても杖の先から遅れて動いてしまいます。
サンプルでは5フレームに1回位置を更新してますが、毎フレームで動かしてもずれます。
個人的には「ビヨンビヨン」と呼んでいます。
興味のある方は1フレームごとに書き換えてどれくらいずれるか確認してみてください。
別の方にVCIを握って振り回してもらおう
「ビヨンビヨン」は他の方に振り回してもらうとさらに大きくなります。
SubItemの同期で通信が発生するため、実際の杖の位置よりずれて帯が表示されるのだと思います。
杖1,2は振り回してもずれたりしないので平和です。
SubItemとSubSubItem方式どうちらがいいのか?
杖1,2,3どれも利点と欠点があるので、比較してみましょう
| 杖 | タイプ | 回転方法 | ビヨンビヨン | 凸者同期 | その他 |
|---|---|---|---|---|---|
| 1 | SubSub | Quotanion | なし | なし | 同期させる部分が大変 |
| 2 | SubSub | Texture | なし | なし | 回せるかはオブジェクトの形しだい |
| 3 | Sub | Quotanion | あり | 自動 | SubItemなので自動で同期 |
動きの遅いものは杖3の方式を使用して、振り回すような場合はSubSubItemを使用するのが良いかもしれません。
ただし、動きを同期する場合、入退出者やオーナーの変更処理等考える部分が多いのでかなり難しくなります。
サンプルの杖1,2は回るだけなので、実は非同期で動作しています。
杖3は同期していますが、回転だけなのでずれいても分からないですね。
杖2のテクスチャスクロールは今回のおまけですが、決まったオブジェクトの模様だけを動かす処理には向いていると思います。
あとはアニメーションを使用して動かすこともできますが、こちらも凸者の同期や、再生タイミングのずれが発生しますのでかなり難しいですね。
Quaternionでどこまでできるか?
今回の杖1で説明したSubSubItemを回転させる方法を使用して作ったVCIがこの動画です。
マッチ棒の先を立方体にして、杖の棒無しをQuotanionで回す感じです。
位置計算はかなり難しいです、このVCIはリリースしていません。
意外といい感じで回ってると思います。
結局どのやり方が良いか?
作りたいものに合わせていろいろ考えて、簡単なものを選んでください。
回す対象や、回し方、同期、移動させたいかどうかなどで複数組み合わせると楽しそうです。
ただ、SubSubItemは同期が大変なので、頑張ってください。
おわりに
今回のアドカレの機会をくださった小山内しのぶさん、ありがとうございました。
他の方の記事も楽しみたいと思います。

