この記事はスライドバー的なUIを作りたいの続編となります。
リングタイプのスライドバーを作りたい
VRではUIを使いたいときに、あまりそういうコンポーネントが用意されているわけでもないので、各人作らないとなりません。特にバーチャルキャストはすべて自分で作らなくてはいけません。
いちいちUIで時間を消費するのもあまり良くないと思いますので、ここで共有したいと思います。
作るのは↓みたいな感じです。
#モデル
前回はモデリングせずに済みましたが、さすがに今回はモデリングが必要でした。といっても、Blenderでドーナツ(トーラス)を追加するだけでOKです。お好みで適当に細くして形を整えましょう。
unityのヒエラルキー(階層構造)は以下のようになります。
dummyが実際に持つアイテム(実際使う際は透明にしておくといいと思う)、Sphereが操作に連動して動くインジケーター、torusがドーナツ形リングで、レールみたいな役割をします。
前回同様バーチャルキャストではある経路に沿ってだけ動く、みたいな拘束はかけられないため、掴みたいスライドバーのつまみと、実際に掴んでいるものとを別にします。その上でドーナツ上のインジケーターの座標を計算してスクリプトで移動させるという形式を取ります。
#スクリプト
以下スクリプトを貼り付けておきます。前回の流用なので、例によって別オブジェクトの色を回転角度に応じて変えています。
local ctr = vci.assets.GetTransform("Sphere")
local dummy = vci.assets.GetSubItem("dummy")
local torus = vci.assets.GetSubItem("torus")
local lscale=0.5
torus.SetLocalScale(Vector3.one*lscale)
local flggrabdummy = False
local bufdummypos = dummy.GetPosition()
local bufctrpos = ctr.GetPosition()-- ctr.GetPosition()
local nowctrpos = bufctrpos
function update()
--持っているときはコントローラーをコライダーダミーに追従させ、放したときはダミーをコントローラーの位置に戻す
if flggrabdummy == false then
dummy.SetPosition(Vector3.MoveTowards(dummy.GetPosition(),ctr.GetPosition(),1))
else
nowctrpos = Vector3.ProjectOnPlane(dummy.GetPosition()-torus.GetPosition(),torus.GetRotation()*Vector3.up).normalized*.6*lscale
ctr.SetPosition(torus.GetPosition() + nowctrpos)
end
-- 色をつける
local hueangle = Vector3.SignedAngle(nowctrpos,torus.GetRotation()*Vector3.left,torus.GetRotation()*Vector3.up)+180
local starcolor = Color.HSVToRGB(hueangle/360,1,1)
print(starcolor)
vci.assets._ALL_SetMaterialColorFromName("blackbody", starcolor)
vci.assets._ALL_SetText("Temp", string.format("hue %d",hueangle))
end
function onGrab(target)
if target == "dummy" then
flggrabdummy = true
print("grabbing")
bufdummypos = dummy.GetPosition()
bufctrpos = ctr.GetPosition()
end
end
function onUngrab(target)
if target == "dummy" then
flggrabdummy = false
print("ungrabed")
end
end
骨子は前作のスライドバーと同じですが、スライドバーと違って、無限回転するので、角度をとります。
なのでポイントは
nowctrpos = Vector3.ProjectOnPlane(dummy.GetPosition()-torus.GetPosition(),torus.GetRotation()*Vector3.up).normalized*.6*lscale
ここですね。(ここの0.6はドーナツの大きさです)
local hueangle = Vector3.SignedAngle(nowctrpos, torus.GetRotation()*Vector3.left,torus.GetRotation()*Vector3.up)+180
ここもです。今回は回した角度を求めるのに、
- トーラス(リング)のある平面に、持っているdummyの位置を投影する
- 投影された位置と、基準となるベクトルの角度を求める。この時、Angle()ではなくSingnedAngleを使うことで360度求まる
- SignedAngleは-180度~180度の値をとるので、180を足して正規化する。
ということをやっています。ProjectOnPlaneはこういうのに使えるので、結構便利に使っています。
#おわりに
実際UIを一から作るのは以外に大変ですから、VCI製作者としては他にも使いたいUIはたくさんあると思うので、ぜひ皆さんも作ったら共有していってください。いちいちUIに消耗してるのはもったいないからね。
読んでいただきありがとうございました。