3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

VCIAdvent Calendar 2021

Day 1

VCIでリング的なUIをつくりたい

Last updated at Posted at 2021-11-30

この記事はスライドバー的なUIを作りたいの続編となります。

リングタイプのスライドバーを作りたい

VRではUIを使いたいときに、あまりそういうコンポーネントが用意されているわけでもないので、各人作らないとなりません。特にバーチャルキャストはすべて自分で作らなくてはいけません。
いちいちUIで時間を消費するのもあまり良くないと思いますので、ここで共有したいと思います。

作るのは↓みたいな感じです。

#モデル
前回はモデリングせずに済みましたが、さすがに今回はモデリングが必要でした。といっても、Blenderでドーナツ(トーラス)を追加するだけでOKです。お好みで適当に細くして形を整えましょう。

unityのヒエラルキー(階層構造)は以下のようになります。
image.png

dummyが実際に持つアイテム(実際使う際は透明にしておくといいと思う)、Sphereが操作に連動して動くインジケーター、torusがドーナツ形リングで、レールみたいな役割をします。

前回同様バーチャルキャストではある経路に沿ってだけ動く、みたいな拘束はかけられないため、掴みたいスライドバーのつまみと、実際に掴んでいるものとを別にします。その上でドーナツ上のインジケーターの座標を計算してスクリプトで移動させるという形式を取ります。

#スクリプト
以下スクリプトを貼り付けておきます。前回の流用なので、例によって別オブジェクトの色を回転角度に応じて変えています。

main.lua

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

ここもです。今回は回した角度を求めるのに、

  1. トーラス(リング)のある平面に、持っているdummyの位置を投影する
  2. 投影された位置と、基準となるベクトルの角度を求める。この時、Angle()ではなくSingnedAngleを使うことで360度求まる
  3. SignedAngleは-180度~180度の値をとるので、180を足して正規化する。

ということをやっています。ProjectOnPlaneはこういうのに使えるので、結構便利に使っています。

#おわりに
実際UIを一から作るのは以外に大変ですから、VCI製作者としては他にも使いたいUIはたくさんあると思うので、ぜひ皆さんも作ったら共有していってください。いちいちUIに消耗してるのはもったいないからね。

読んでいただきありがとうございました。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?