20210117のUnityに関する記事は5件です。

【Unity】カメラの揺らし方

方法

揺れるという動きを「視点が球内部のランダムな点に移動し続けた後、元の視点に戻る」という風に解釈します。掴みにくい方は以下の動画の立方体を追ってみてください。球内部の点にランダムで移動しているだけですが、立方体に注視することで目が回るような感覚に陥ると思います。

実装

実装はシンプルで以下のコードになります。

CameraShake.cs
using System.Collections;
using UnityEngine;

public class CameraShake : MonoBehaviour
{
    public IEnumerator Shake(float duration, float magnitude)
    {
        Vector3 originalPosition = transform.position;
        float elapsed = 0f;

        while (elapsed < duration)
        {
            transform.position = originalPosition + Random.insideUnitSphere * magnitude;
            elapsed += Time.deltaTime;
            yield return null;
        }
        transform.position = originalPosition;
    }
}

球の半径とカメラが揺れる時間を引数に渡して使用します。

transform.position = originalPosition + Random.insideUnitSphere * magnitude;

Random.insideUnitSphereとは半径1の球体の内部の点をランダムに返すメソッドになります。半径 = 1 * magnitudeとすることで、揺れの大きさを決定しています。

elapsed += Time.deltaTime;

ランダムに位置を変更する毎の時間をelapsedに追加しておき、指定時間を超えるまで処理を続けます。

使用方法

以下のように呼び出して使用します。

StartCoroutine(cameraShake.Shake(0.3f, 0.6f));

使用用途に合わせて、揺れの大きさや、揺れ時間を変更するとGOOD!

実装動画

 終わりに

  • 注意点として、Canvas内部は揺れません。UIや背景等も揺らしたい場合は、Canvasから外しましょう。
  • 一回作成しておくと、使い回しのきく便利なプログラムになると思います。是非参考にしてみてください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unity Bloomがうまくいかない

Unityで物体を発光させるためにBloomというものを使えば簡単にできるという
記事をみたのでやってみたのですが、なぜかうまくいかない
テストで下記画像のようにできた!!
と思っていたのですが、、2021-01-17 (2).png

プラットフォームをIosにしたら効果が反映されませんでした。
おそらく対応されてないのでしょう。
プラットフォームを変更したら下記のようになってしまいます
2021-01-17 (3).png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unityでカメラの方向が変になる問題の解消

問題

Blenderで作ったモデルをUnityでインポートして使っていたが、ゲームを実行すると、本来のカメラとは別の視点から表示されてしまう問題が発生した。

解消法

この原因は、Blenderで作ったモデルに含まれているカメラからの視点になってしまっていたため。
モデル内のカメラを無効化したら解消した。

UnityとBlenderを使っていて初めて経験した現象なので、必ず起こるというわけではなさそう。

確認環境

MacBook Pro (16-inch 2019)
macOS Catalina 10.15.7

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Unity] Humanoid の 親指に関する見栄えの問題について [VTuber]

Unity の親指ってなんかおかしくない?

エンジニアのハマりどころについてのお話。
モーキャプ界隈でよく出る話題、

『手の形おかしくない?』

というお話について、何か対策しようというお話。

ゲームであれば、まじまじと手の形を見るということ自体あまりないだろうが、
VTuberが世に出始めたのもあり、バストアップの映像の需要が高まったため、
手を見せることが多くなってきた。

そもそもにして、UnityにFBXをインポートする際に、正確な情報が良く分からなかったり、
エンジニアとデザイナーの中間の問題なせいで、当事者たちが「俺の仕事じゃないし」状態になりやすいという問題がある。

今回正しい情報と推定される情報を載せるのだが、
誰か正解を持っていたら教えて!

今回サンプルに出しているモデルは、
UnityちゃんURPモデルになる。© UTJ/UCL

先に要点

まず、Unityの親指の第一関節の角度制限の初期値がおかしいのではないかという問題。

これだけ書かれてもピンとこない人は、この記事を最後まで見てもらえればよいと思う。

FBXインポートに気を付ける事

そもそもどんな形でインポートするのが正しいのかというおさらいから。

Mecanim Humanoid についての Unity Blog。
https://blogs.unity3d.com/jp/2014/05/26/mecanim-humanoids/

The T-Stance の項目に、インポート時に必要なTポーズについての仕様が書いてある。
その中でも、親指については以下のようにある。

Thumbs straight parallel to the ground half way (45 degrees) between x and z axis

地面に並行X軸(左右)とZ軸(前後)について45度の角度に設定する、とある。
上からだとこんな感じ。

Tポーズの状態だと各関節のZ軸回転で折り曲げになるので、親指の爪が真横に見える
横からだとこんな感じ。

私自身はエンジニアなので完全に蛇足だが、
モデリング自体はやりやすい自然な指の形で行い、リギング時点で気にするとよいとか何とか。(余計なお世話)

角度制限とは?

Humanoid には、角度を設定できる機能がある。

アバターでHumanoidに設定するこれ ↓ のなかの、
image.png

これ ↓ (Configure Avatar - Muscle and Settings の項)
image.png

このプレビュー機能で、第一関節の Stretched を最大に開いてみる。

image.png

親指は明らかに開きすぎなのでは?
これの角度制限でいうと、プラス側の値になる。
角度制限を -20 ~ 0 に設定してみた場合、以下のようになる。
hand.gif
自分の親指を動かして見てほしいが、親指の第一関節は意外と動かない
このくらいがまだ自然な値ではないだろうか。

というか、Humanoid の仕様上、最大値側の値をマイナスにすることができない
0 の値でもやや開きすぎてる感もあるが、残念ながら Humanoid の仕様としての限界という事になる。
これ以上はインポート時に何かしらの試行錯誤を試すしかない。

そもそも Humanoid (Muscle) とは何か?

Unity Humanoid は、人間の骨格を特定のルールで標準化した値を使って人間の骨格を操作する。
それが Muscle と呼ばれるものの値であり、-1 ~ +1 の値で標準化され、Humanoid Animation ファイルとして扱われる。

Muscle の値がすべて 0 とは何なのか。
よく見るこれである↓
image.png
これを中心の値として、プラス、マイナス方向に、それぞれどこまで曲がるかを設定することが出来る。
それが Muscle and Settings を使った角度制限の値となる。

先ほどの項目でも書いたが、プラス側の最大値をマイナスの値に設定できないのは、この仕組みが起因しているようだ。
人間が持っている各関節の中間値はこれ、と定義したのが、この Muscule = 0 と思われ、
この値が共通になっているがために、アニメーションの途中の値が破綻しにくい構造になっている(と思われる)

SDユニティちゃんのような、極端に手足の短いモデルであっても、角度制限の値を調節することで、
似たようなモーションとして再生することが出来るわけだ。

蛇足となるが、Humanoid の .anim ファイルには、FootIKの値も入っているようで、(未検証)
歩いたり走ったモーションが接地する場合に、この値を使って接地していると思われる。(これも未検証)
足の関節の比率が違うモデルの場合は、接地が破綻するはずなのでFootIK機能で調整する必要が発生する。
FootIKとMuscleは直接関係がない(更にこれも未検証)
Humanoid Animation は、基本的にFKなのである。

更に蛇足だが、最大値を0にした場合、プラス方向への値は一切動かなくなる。
当然、0 ~ 0 の制限範囲にすると、Animation でどんな値が来てもその関節は全く動かなくなる。
モーションをマッチングするうえで、0が基準値で、それを跨ぐことはないという考え方のようだ。

Humanoid を使う理由

当たり前だが、汎用性を持たせるためである。

VRM モデルや VRC モデルが Humanoid である理由はこの辺りが要因で、
モーション編集用ツールを使わず、Unity 上で直接動かす場合も当然 Humanoid で動かしたいわけだ。

そして、手の見た目変だよね問題にぶち当たるわけである。
(手の形がきれいに見えない理由は他にもあるが、
Unity Humanoid の範囲を超えてしまうものもあるので今回は扱わないものとする。)

ガチンコで指の角度を割り当てる方法もあると思うが、
特に親指は、作業者によって一定の角度であることは少ないので、
ガッチリをルール付けでもしておかない限り、
Humanoid 対応モデルとして読み込んでも、残念な見た目になることは容易に想像できる。

ついでに、手のモーキャプ機材は様々な要因でイケてないことが多く
この場合でも残念な見た目になりやすい。

この辺りは別記事にでも書きたいと思っているが、
まあシンプルに手に関する表現は沼と言っていいだろう。

ちょっと気になる点

じゃあ -20 ~ 0にすれば解決だよね? と思われるかもしれないが、少し気になる記載がある。
Unity Blog に以下のような記載がある。

Muscle range adjustments
By default muscle ranges are set to values that best represent human muscle ranges.
Most of the time, they should not be modified.
For some more cartoony character you may want to reduce the range to prevent arms entering body or augment it to exaggerate legs motion.
If you are creating a Humanoid Rig to retarget MOCAP data you should not modify the ranges since the produced animation clip will not respect default.

殆どの場合は変更しないで下さいとある。
はて? これは如何にするべきなのか。
答えは出しようがないのだが、見た目が変なので変えざるを得ない。
変える以上は変えた値に責任をもって対応するだけでしかないだろうか。

親指は2軸で大きく動くし、伸ばしきった値をどこで取っていいのか、
作っていても直観的に正解が分かりにくい。
他の4本の指の場合は、最大値でも伸ばしきるか曲げきるかのシンプルな構造なので、
正解にたどり着くのは容易なのだが。

それに加えて、親指の初期値がおかしいとなると、
"理論上おかしくないと思うが、思った見た目にならない"という状態に陥りやすい。
エンジニアかデザイナーのどちらかが正しく理解していないと、答えが無くハマる可能性は大いにある。

個人的には、親指初期値に関しては、Unityのソフト自体が最初から 0 にしてもらうのが望ましいのではないかと思ってはいる。

まとめ

取りあえず、
Thumb 1 Stretched のプラスの値を 0 にしてみろ

ってことで。
後はウェイト調整で頑張って!(急に丸投げ)

より高みを目指したい方は以下も参考にされたし。

更に高みを目指したいなら、ブレンドシェイプで連動とかしないとダメだろうなぁ。
肘関節とかも、そうやったほうが早いと聞いた気がするし。

以上

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Unity】シーン遷移時のBGM制御を一元管理するManagerの設計を考えてみた

初めに

各シーンで流すBGM制御を一元管理できないものかと思い設計に至る。
この記事では、

  • 遷移前:BGMなし → 遷移後:BGMなし
  • 遷移前:BGMなし → 遷移後:BGMあり(新規再生)
  • 遷移前:BGMあり → 遷移後:BGMなし(停止)
  • 遷移前:BGMあり → 遷移後:BGMあり(BGM切り替え)

この4つの制御を一元管理する方法について紹介する。

また、似たような問題としてButtonのSEを管理するManagerの設計についても記事を書いているので、もしよければそちらも参考にしていただきたい。
アプリ内のSEを楽に管理するManagerの設計を考えてみた

環境

Unity:2019.1.5f1
おそらくバージョン依存の処理はないと思う。

設計の方針

  • BGMの追加、差し替えなどはすべてこのManagerで完結する
  • Managerはシングルトンにし、アプリのBoot画面などでDontDestroyOnLoadに登録しておく
  • 鳴らしたいBGMは全てManagerにアタッチしておく
  • シーン名とそのシーンで鳴らすBGMの対応を辞書で作る
  • シーンが切り替わるタイミングで上記4つのどれかが行われるようにする

作ったサンプルの設定

画面遷移図.png
上記4パターンを全て取り入れた。
scene1 → scene2の遷移ではBGMは途切れないようにしたい。

Code

BGMManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using System.Linq;

public class BGMManager : MonoBehaviour
{
    //シングルトンにしておく
    public static BGMManager bgmManagerInstance;

    //シーン名の一覧。この辺は適宜別ファイルに分けること。
    //私の場合、実際はScriptableObjectを継承させている
    public class SceneNames
    {
        public const string Boot = "Boot";
        public const string SampleScene = "SampleScene";
        public const string scene1 = "scene1";
        public const string scene2 = "scene2";
        public const string scene3 = "scene3";
        public const string scene4 = "scene4";
        public const string scene5 = "scene5";
    }

    //使いたいBGMはここに追記&インスペクタからアタッチ
    [Header("BGM")]
    public AudioSource bgm1;
    public AudioSource bgm2;
    public AudioSource bgm3;

    //遷移前のシーン名
    private string beforeScene = string.Empty;

    //bgm用の辞書
    private Dictionary<string, AudioSource> bgmDic = new Dictionary<string, AudioSource>();

    //Bootシーケンスでのみ呼ばれる想定
    private void Awake()
    {
        //シングルトン
        if (bgmManagerInstance == null)
        {
            bgmManagerInstance = this;
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
        }

        //ここに各シーンで使いたいbgmを追加
        bgmDic.Add(string.Empty, null);//bootだけは名前が取って来れないので追加
        bgmDic.Add(SceneNames.SampleScene, null);
        bgmDic.Add(SceneNames.scene1, bgm1);
        bgmDic.Add(SceneNames.scene2, bgm1);
        bgmDic.Add(SceneNames.scene3, null);
        bgmDic.Add(SceneNames.scene4, bgm3);
        bgmDic.Add(SceneNames.scene5, bgm2);
    }

    void Start()
    {
        //Sceneが切り替わった時にメソッドが呼ばれるように登録
        SceneManager.activeSceneChanged += OnActiveSceneChanged;
    }

    //BGM再生
    public void BgmStart(string sceneName) { bgmDic[sceneName]?.Play(); }
    //BGM停止
    public void BgmStop(string sceneName) { bgmDic[sceneName]?.Stop(); }

    //シーン遷移時の処理
    private void OnActiveSceneChanged(Scene prevScene, Scene presentScene)
    {
        ControllBGM(beforeScene, presentScene.name);
        beforeScene = presentScene.name;
    }

    //シーンに応じたBGMを再生する
    public void ControllBGM(string beforeSceneName, string presentSceneName)
    {
        //遷移前後のシーンで使うBGMが不変なら何もしない
        if (bgmDic[beforeSceneName]?.clip.name == bgmDic[presentSceneName]?.clip.name)
        {
            return;
        }

        //遷移前シーンのBGMを停止
        BgmStop(beforeSceneName);
        //遷移先シーンのBGMを再生
        BgmStart(presentSceneName);
    }
}

動作確認

スクリーンショット 2021-01-17 2.21.48.png
BootにBGMManagerを配置。
BGMはあらかじめインスペクタからアタッチする。
Loopやその他音量などの設定はよしなに。
あとは上の画像のように遷移を作ればBGMが意図通り制御できる。

最後に

ミニマムで作ったので今回はこれだけの実装だが、今後はシーン遷移のフェードアウトに合わせてBGMもフェードアウトする、などの機能を適宜追加して実用できるものにしていきたい。

ここまで読んでいただきありがとうございました。
コメントやアドバイス、指摘等お待ちしております。(LGTM励みになります、そちらもよければ!)
この記事が何かの役に立てば幸いです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む