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

Sharematerialの意味(URL参照)

sharematerialとは

同じマテリアルを使用しているものの設定を同時に変えることができる。
lineObj.AddComponent<MeshRenderer>().sharedMaterial = _parent._material;
こんな感じの使い方

同じマテリアルって言ってるけど、これだと左のマテリアルが共通化されてるのかな

正直詳細がわからないので下のリンクを参考にしてみる
マテリアルのプロパティをスクリプトから変更【Unity】

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

【Unity】Noitom Hi5とPerception Neuron PROを使った全身トラッキング環境の構築(+モーション記録)

最初に

Hi5とPerception Neuron PROはVTuberハッカソン 全国ツアー2019に参加した際に借りた機材になります。
個人で所有していないため、本機材に関する質問には、返答できない場合があります。
ご了承ください。

本記事の目標

Unity上でVRM形式のモデルをNeuron、Hi5で動かし、そのモーションを記録する

環境

【PC】Windows10 1903
【Unity】2019.2f1

トラッカー

SDK

お借りしたモデル

お借りしたスクリプト

モデルインポート

モーショントラッキング関係

モーション記録関係

設定

Noitom Perception Neuron PRO SDK

  1. ダウンロードページからAXIS NEURON PROをダウンロード、インストールし起動する

  2. [File]->[Settings]->[Output Format]のBVH Dataの項目のDisplacementの項目のチェックを外す
    output_format.png

  3. [File]->[Settings]->[Broadcasting]のBVHのEnableの項目にチェックを入れる
    bvh_enable.png

  4. OKで設定を反映

Unity

モデルインポート

  1. UniVRMリリースページから最新版の.unitypackageをダウンロード

  2. UnityのプロジェクトにUnity Packageをインポート

  3. VRM形式のモデルデータをAssetフォルダ直下にコピペする

  4. UniVRMがUnity用にプレハブを作成する

Noitom Perception Neuron PRO

  1. Perception Neuron PRO、Hi5設定ツールをダウンロードし、解凍する

  2. 解凍後のフォルダのAssetフォルダから、
    ・Neuronフォルダ
    ・NotionHi5フォルダ
    ・calibration.unity
    をUnityプロジェクトのAsset直下にコピペする
    コピーデータ.png

  3. 動かしたいモデルにNeuronAnimator.csをアタッチする

  4. 設定完了
    気になる人はUnityを再生して、AXIS NEURON PRO上の動きがモデルに反映されているか確認する

Noitom Hi5

  1. 上記Noitom Perception Neuron PROの項目1.、2.を行っていない人は行う

  2. モデルの右手首、左手首にHi5_InertiaInstance.csをアタッチ

  3. それぞれを以下の画像のように設定する
    設定が面倒な方はHi5_InertiaInstance.csの設定が面倒な人向けの項目を確認してください
    左手の設定サンプル(右手はそれぞれを右手のモデルに読み替えてください)
    Hi5_InertiaInstance設定.png

Hi5_InertiaInstance.csの設定が面倒な人向け

自動設定機能を追加します。

  1. Hi5_InertiaInstance.csにhttps://gist.github.com/neon-izm/395709df5af70021490625e4c03e59bdより引用した以下のコードを加える
/// <summary>
/// モデルを変えたときに HandBone をセットし直すのが面倒だったため、自動的にアタッチしてくれる関数
/// HandBones[0] に対象モデルのRoot(Animatorがアタッチされてるオブジェクト)を入れてから実行する。
/// </summary>
[ContextMenu("Automatic Set HandBone")]
void AutomaticSetHandBone()
{
    if (HandBones[0] == null)
    {
        Debug.LogError("HandBones[0] にモデルのRoot(Animatorとかあるオブジェクト)を入れてください。");
        return;
    }

    //Animator からボーン情報を持ってきたいので、Animator を取得
    var animator = HandBones[0].GetComponent<Animator>();
    if (animator == null)
    {
        Debug.LogError("Animator が見つかりません。");
        return;
    }

    //念の為初期化
    HandBones = new Transform[(int) Bones.NumOfHI5Bones];

    //左手と右手で取得すべきボーンが違うから判定
    switch (HandType)
    {
        case Hand.LEFT:
            HandBones[1] = animator.GetBoneTransform(HumanBodyBones.LeftHand);
            HandBones[2] = animator.GetBoneTransform(HumanBodyBones.LeftThumbProximal);
            HandBones[3] = animator.GetBoneTransform(HumanBodyBones.LeftThumbIntermediate);
            HandBones[4] = animator.GetBoneTransform(HumanBodyBones.LeftThumbDistal);

            HandBones[6] = animator.GetBoneTransform(HumanBodyBones.LeftIndexProximal);
            HandBones[7] = animator.GetBoneTransform(HumanBodyBones.LeftIndexIntermediate);
            HandBones[8] = animator.GetBoneTransform(HumanBodyBones.LeftIndexDistal);

            HandBones[10] = animator.GetBoneTransform(HumanBodyBones.LeftMiddleProximal);
            HandBones[11] = animator.GetBoneTransform(HumanBodyBones.LeftMiddleIntermediate);
            HandBones[12] = animator.GetBoneTransform(HumanBodyBones.LeftMiddleDistal);

            HandBones[14] = animator.GetBoneTransform(HumanBodyBones.LeftRingProximal);
            HandBones[15] = animator.GetBoneTransform(HumanBodyBones.LeftRingIntermediate);
            HandBones[16] = animator.GetBoneTransform(HumanBodyBones.LeftRingDistal);

            HandBones[18] = animator.GetBoneTransform(HumanBodyBones.LeftLittleProximal);
            HandBones[19] = animator.GetBoneTransform(HumanBodyBones.LeftLittleIntermediate);
            HandBones[20] = animator.GetBoneTransform(HumanBodyBones.LeftLittleDistal);
            break;

        case Hand.RIGHT:
            HandBones[1] = animator.GetBoneTransform(HumanBodyBones.RightHand);
            HandBones[2] = animator.GetBoneTransform(HumanBodyBones.RightThumbProximal);
            HandBones[3] = animator.GetBoneTransform(HumanBodyBones.RightThumbIntermediate);
            HandBones[4] = animator.GetBoneTransform(HumanBodyBones.RightThumbDistal);

            HandBones[6] = animator.GetBoneTransform(HumanBodyBones.RightIndexProximal);
            HandBones[7] = animator.GetBoneTransform(HumanBodyBones.RightIndexIntermediate);
            HandBones[8] = animator.GetBoneTransform(HumanBodyBones.RightIndexDistal);

            HandBones[10] = animator.GetBoneTransform(HumanBodyBones.RightMiddleProximal);
            HandBones[11] = animator.GetBoneTransform(HumanBodyBones.RightMiddleIntermediate);
            HandBones[12] = animator.GetBoneTransform(HumanBodyBones.RightMiddleDistal);

            HandBones[14] = animator.GetBoneTransform(HumanBodyBones.RightRingProximal);
            HandBones[15] = animator.GetBoneTransform(HumanBodyBones.RightRingIntermediate);
            HandBones[16] = animator.GetBoneTransform(HumanBodyBones.RightRingDistal);

            HandBones[18] = animator.GetBoneTransform(HumanBodyBones.RightLittleProximal);
            HandBones[19] = animator.GetBoneTransform(HumanBodyBones.RightLittleIntermediate);
            HandBones[20] = animator.GetBoneTransform(HumanBodyBones.RightLittleDistal);
            break;

        default:
            Debug.LogError("HandType が不正なものです。");
            break;
    }
}

  1. 下図の通り、
    ・Hand Baseの要素0にVRMのアニメーターがついているオブジェクトを設定
    ・自動設定を実行
    ・追加の設定
    を行う
    hi5設定.gif

  2. Asset直下のcalibration.unityを再生し、Hi5のキャリブレーションを行う(スペースキーで画面遷移します)
    詳細な手順は以下の動画をご確認ください
    https://youtu.be/FN1wvcpdOjk?t=157

レコーディング環境

1.EasyMotionRecorderリリースページから最新版のunitypackageをダウンロード、プロジェクトにインポート

2.Asset -> EasyMotionRecorder -> Prefubs -> EasyMotionRecorderをシーンにドラッグアンドドロップ

3.オブジェクトEasyMotionRecorderのMotionDataRecoder.csのアニメーターにモデルをドラッグアンドドロップ

動作

上記設定の項目を行った状態で再生すると、Hi5とPerception Neuron PROを着用した人のモーションがモデルに反映されます。
デモ用に取ったモーションを再生したもの
demo.gif

レコーディング

記録

Unityを再生中にEasyMotionRecorderのMotionDataRecorder.csに設定したキーで録画開始、終了ができます。
記録されたモーションはAsset -> Resourcesに記録されます。

アニメーションに変換

そのままでは、アニメーターで再生できないので、アニメーションに変換します。
Asset -> Resourcesに記録された.assetファイルを選択し、下図の通りHumanoid Animation Clipとしてエクスポートします。
アニメーション変換.png
あとは、アニメーションコントローラーに張り付けて使用してください。

参考文献

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

Unity メッセージのないエラーログ

エラーメッセージのないエラー発生

先日から突然Unityで意味不明なエラーログが発生しだしかなり苦労させられたので、備忘録に残しておきます。

環境

Unity2018.4.2f
Mac 10.14.5

現象

Unityを触っていたらこのような意味不明なエラーログが4つほど発生。

スクリーンショット 2019-10-20 23.14.22.png

試したこと

  • 他のプロジェクトでも立ち上げると同じエラーが発生
  • 新規プロジェクト作成するも同じエラー発生

どうやら、Unity自体に問題がありそう。。

ここの記事を参考にUnityをクリアインストールを試すが解決せず。。

発見その1

昔使っていたUnity2018.2.5では謎のエラーは発生せず正常運転!

Unityのバージンで問題があるかもしれないと推測し、バージョンごとにテストした結果

Unity2018.2.xx以下ではOK
Unity2018.3.xx以上ではNG

スクリーンショット 2019-10-21 18.18.19.png

Unityのバージョンで問題があるのならば、もっと大きな問題になっているはずなので、根本的にはバージョンの問題ではない気がする。

発見その2

Bootcampで入れたWindows10側でUnity2018.4.11をインストールして試してみると、正常運転!

やはり、Unityのバージョンが問題ではなく、MacOSとUnityの組み合わせで問題が出ている気がする。

解決

結局、MacOSのバージョンをMojave(10.14.5)から最新のCatalina(10.15)へアップデートすることで謎のエラーは出なくなりました。
根本的な解決ではないような気もしますが、とりあえず結果オーライということで。

スクリーンショット 2019-10-21 18.34.18.png

あとがき

アップデートしてソフトウェアが動かなくなることは多々ありますが、アップデートしないことで動かないという現象は初めての経験でした。

OSのアップデートは、不具合も多いのでいつもは1ヶ月ほど様子見てからにするのですが、今回のようなこともあるので、また一つ勉強になりました。

ちなみに、最近調子悪かったAdobe Creative Cloudもアップデート後は正常運転するようになってくれて、いろいろと問題が解決できました!!

スクリーンショット 2019-10-21 18.37.58.png

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

【Unity(C#)】Emptyなオブジェクトを可視化してEdit簡略化

Transformだけのオブジェクト

Create EmptyしたObjcetって文字通りメッシュも何もないので、
位置調整が必要なオブジェクトとして設定してしまった場合、微調整がけっこう大変ですよね。

AudioSourceだけのオブジェクトで音源の位置を変化させた場合なんかも、
視覚情報だけでデバッグしたいところです。

そこで、ギズモを描画する機能を使って編集、デバッグをしやすくします。

もうすでにきれいにまとめてくださっている方がいらっしゃったので、らくちんでした。
UnityのGizmosを使ってシーンビューで視覚的なデバッグの補助をする

コード

#if UNITY_EDITOR
using UnityEditor;
using UnityEngine;
/// <summary>
/// ギズモちゃん
/// </summary>
public class DrowGizmo : MonoBehaviour {

    [SerializeField]
    enum MODE
    {
        CUBE,
        WIRECUBE,
        SPHERE,
        WIRESPHERE
    }

    [SerializeField,Header("描画モード選択")]
    MODE m_mode;

    [SerializeField, Range(0,5),Header("ギズモの大きさ")]
    float m_gizmoSize = 0.3f;

    [SerializeField, Header("ギズモの色")]
    Color m_gizmoColor = new Color(1f, 0, 0, 0.3f);

    void OnDrawGizmos()
    {
        Gizmos.color = m_gizmoColor;

        Vector3 thisObjPos = this.gameObject.transform.position;
        switch (m_mode)
        {
            case MODE.CUBE:
                Gizmos.DrawCube(thisObjPos,Vector3.one*m_gizmoSize);
                break;

            case MODE.SPHERE:
                Gizmos.DrawSphere(thisObjPos, m_gizmoSize);
                break;

            case MODE.WIRECUBE:
                Gizmos.DrawWireCube(thisObjPos, Vector3.one * m_gizmoSize);
                break;

            case MODE.WIRESPHERE:
                Gizmos.DrawWireSphere(thisObjPos, m_gizmoSize);
                break;
        }

    }

    [CustomEditor(typeof(DrowGizmo))]
    public class CustomWindow : Editor
    {
        public override void OnInspectorGUI()
        {
            EditorGUILayout.BeginVertical(GUI.skin.box);
            {
                EditorGUILayout.HelpBox("ギズモでEditサポート", MessageType.Info);
            }
            EditorGUILayout.EndVertical();

            base.OnInspectorGUI();
        }
    }
}
#endif

上記コードをアタッチしたらギズモが表示されます。
gizumoDemo.PNG

OnDrawGizmos

OnDrawGizmos内に書いた処理はオブジェクトを選択していなくても表示されます。
基本こちらしか使わないかな~?と思います。

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

ハードエッジでも縁崩れしない理想的なアウトラインシェーダを作ってみた

はじめに

仕事でUnityゲーム開発しているyoship1639です。
ハードエッジでもこの様に縁崩れせずにアウトラインを奇麗に出すシェーダを思いついたので公開します。

edge003.png

縁取りをするシェーダは多々ありますが、特定のパターンで上手くいかない場合があります。
それぞれ代表的な既存のアウトラインシェーダの特徴と、上手くいかないパターンは以下の通りです。

  • モデルを拡大する手法
    特徴:一般的な手法。1パス目で拡大したモデルをアウトライン色で描画し、2パス目で通常描画する
    ダメなパターン:ハードエッジモデルの場合やモデルの中心(各頂点の中心)が0じゃない場合に破綻する

  • ステンシルバッファを使う手法
    特徴:これも一般的な手法。1パス目で拡大したモデルをステンシルバッファに描画し、2パス目で通常描画する。ポストプロセス等でアウトラインに色を付ける
    ダメなパターン:モデルを拡大する手法と同様

  • 法線を使う手法
    特徴:カメラ視点から見てモデルの法線がほぼ垂直になる(内積がほぼ0になる)ピクセルをアウトライン色にする手法
    ダメなパターン:アウトラインが超絶汚い

  • 深度バッファを使う手法
    特徴:深度バッファを使って深度が急変する箇所をアウトラインとみなす手法。
    ダメなパターン:シーン全体にアウトラインがかかってしまう

各手法の細かい説明等はこちらを参考にしてください
【Unity】【シェーダ】4種のアウトライン描画方法とその特徴

と、上記の様に一長一短があります。

理想的なのは、特定のハードエッジなモデルでもきれいなアウトラインを表示することです。
そこで、上記のダメなパターンを払拭したアウトラインシェーダを思いついたので解説したいと思います。

アルゴリズム解説

今回思いついたのは、GrabPassを用いたアウトラインシェーダです。
GrabPassは簡単に説明すると、直前までのパスの描画結果を背景含めてテクスチャとして出力することです。Grabテクスチャはその描画結果のテクスチャを指します。

アルゴリズム概要は以下の通りです。

  1. 【1パス目】モデルをシーン上で絶対使わないような色(ダミー色)でソリッド描画する
  2. 1の結果をGrabPassとして2パス目に渡す
  3. 【2パス目】ピクセルシェーダでGrabテクスチャのUV値付近をアウトライン幅で一定数サンプリングする
  4. サンプリングの結果ダミー色が含まれていなかった場合、アウトライン付近と判断しアウトライン色で描画する。それ以外は通常描画する。

上記のアルゴリズムでモデルを描画すると、ハードエッジであってもきれいにアウトラインを描画することができます。

それぞれ説明します。

1. 【1パス目】でモデルをシーン上で絶対使わないような色(ダミー色)でソリッド描画する

まず、1パス目でアウトライン描画したいモデルをシーン上で絶対使わないような色でモデルを膨らませずに塗りつぶし描画します。なぜシーン上で絶対使わないような色でないといけないかというと、Grabテクスチャの背景と被る色だとアウトラインが破綻する可能性があるからです。この色をダミー色と呼んでおきます。アウトライン色ではありませんのでご注意。

使いやすいダミー色はrgb(255,0,255)なので、この色を使います。

Pass
{
    CGPROGRAM
    #pragma vertex vert
    #pragma fragment frag

    #include "UnityCG.cginc"

    struct appdata
    {
        half4 vertex : POSITION;
    };

    struct v2f
    {
        half4 vertex : SV_POSITION;
    };

    v2f vert(appdata v)
    {
        v2f o;
        o.vertex = UnityObjectToClipPos(v.vertex);
        return o;
    }

    fixed4 frag(v2f i) : SV_Target
    {
        return fixed4(1.0, 0.0, 1.0, 0);
    }
    ENDCG
}

2. 1の結果をGrabPassとして2パス目に渡す

これは特に何も考えずにシェーダコード内でGrabPass {}と書けば大丈夫です。これで1パス目の結果をテクスチャとして2パス目に渡すことができます。

3. 【2パス目】ピクセルシェーダでGrabテクスチャのUV値付近をアウトライン幅で一定数サンプリングする

ここが今回の手法のミソです。
頂点シェーダはいつもの感じに行いますが、ピクセルシェーダは少し違います。

まず、GrabPassで入手したGrabテクスチャのピクセルのUV値を算出します。これは頂点シェーダでComputeGrabScreenPosを呼べばUnityが勝手に算出してくれます。このUV値のサンプリング結果はモデルのピクセル値と一致します。(つまりrgb(255,0,255)です)

UV値を算出したら、そのUV値の付近をアウトライン幅分ずらして一定数サンプリングします。一定数というのはアウトラインと判定するのに十分な数です。今回の手法は6方向分サンプリングすれば十分です。

#define SAMPLE_NUM 6
#define SAMPLE_INV 0.16666666
#define PI2 6.2831852
#define EPSILON 0.001
#define DUMMY_COLOR fixed3(1.0, 0.0, 1.0)

sampler2D _GrabTexture;
half _OutlineWidth;

v2f vert(appdata v)
{
    v2f o;
    o.pos = UnityObjectToClipPos(v.vertex);
    o.grabPos = ComputeGrabScreenPos(o.pos);

    return o;
}

fixed4 frag(v2f i) : SV_Target
{
    // サンプリングのオフセット(アウトラインの幅)
    half2 delta = (1 / _ScreenParams.xy) * _OutlineWidth;

    int edge = 0;
    [unroll]
    for (int j = 0; j < SAMPLE_NUM && edge == 0; j++)
    {
        // オフセット分ずらしてサンプリング
        fixed4 tex = tex2D(_GrabTexture, i.grabPos.xy / i.grabPos.w + half2(sin(SAMPLE_INV * j * PI2) * delta.x, cos(SAMPLE_INV * j * PI2) * delta.y));
        // ダミー色と同でないならアウトラインであると判定
        edge += distance(tex.rgb, DUMMY_COLOR) < EPSILON ? 0 : 1;
    }
    ...     

4. サンプリングの結果ダミー色が含まれていなかった場合、アウトライン付近と判断しアウトライン色で描画する。それ以外は通常描画する。

edge002.png

サンプリングした結果、ダミー色しか含まれていない場合はアウトライン付近ではないと判断し通常のモデル描画を行います。
ダミー色以外が1つ以上含まれていた場合は、アウトライン付近であると判断できるので、アウトライン色で塗りつぶします。
これを実現すると、ハードエッジであっても関係なく、かつ特定のモデルのみアウトラインを適用させることができます。

シェーダコード

今回作成したアウトラインシェーダのシェーダコード全文です。コピペすれば動きます。
必要最小限のコードしか書いていないので、ライト処理やシャドー処理などは行いません。

Shader "Custom/Outline"
{
    Properties
    {
        _MainColor("Main Color", Color) = (1, 1, 1, 1)
        _MainTex("Texture", 2D) = "white" {}
        _OutlineColor("Outline Color", Color) = (0.0, 0.0, 0.0, 1)
        [Slider(0.1)] _OutlineWidth("Outline Width", Range(0.0, 10.0)) = 3
    }
    SubShader
    {
        Tags { "RenderType" = "Opaque" }
        LOD 100

        // 【1パス目】ダミー色で塗りつぶし
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                half4 vertex : POSITION;
            };

            struct v2f
            {
                half4 vertex : SV_POSITION;
            };

            v2f vert(appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                return o;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                return fixed4(1.0, 0.0, 1.0, 0);
            }
            ENDCG
        }

        GrabPass {}

        // 【2パス目】Grabテクスチャを使ってアウトライン+通常描画
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            #define SAMPLE_NUM 6
            #define SAMPLE_INV 0.16666666
            #define PI2 6.2831852
            #define EPSILON 0.001
            #define DUMMY_COLOR fixed3(1.0, 0.0, 1.0)

            struct appdata
            {
                half4 vertex : POSITION;
                half2 uv : TEXCOORD0;
            };

            struct v2f
            {
                half4 pos : SV_POSITION;
                half2 uv : TEXCOORD0;
                half4 grabPos : TEXCOORD1;
            };

            sampler2D _GrabTexture;
            fixed4 _MainColor;
            sampler2D _MainTex;
            half4 _MainTex_ST;
            fixed4 _OutlineColor;
            half _OutlineWidth;

            v2f vert(appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                o.grabPos = ComputeGrabScreenPos(o.pos);

                return o;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                half2 delta = (1 / _ScreenParams.xy) * _OutlineWidth;

                int edge = 0;
                [unroll]
                for (int j = 0; j < SAMPLE_NUM && edge == 0; j++)
                {
                    fixed4 tex = tex2D(_GrabTexture, i.grabPos.xy / i.grabPos.w + half2(sin(SAMPLE_INV * j * PI2) * delta.x, cos(SAMPLE_INV * j * PI2) * delta.y));
                    edge += distance(tex.rgb, DUMMY_COLOR) < EPSILON ? 0 : 1;
                }

                fixed4 col = lerp(tex2D(_MainTex, i.uv) * _MainColor, _OutlineColor, edge);
                return col;
            }
            ENDCG
        }
    }
}

下図の様にハードエッジモデルと通常のモデル両方で扱えます。
038.png

おわりに

上記のシェーダコードはアウトラインを表示するための必要最小限の機能しか実装していません。しかし、アウトライン部分以外はいくらでも追加実装することができるので汎用性は高いのではないかと思います。

また、良い感じに描画してくれるアウトラインシェーダですが弱点があります。それはアウトラインシェーダを適用させたモデルを重ねた時です。この場合、GrabPassがモデルと背景の境界を正しく判定できなくなるので、アウトラインが多少破綻してしまいます。そのため、ダミー色をマテリアルごとに変えたりといった工夫が必要になるかもしれません。それ以外の場面では現状問題なく描画できます。

その他不具合があったらご連絡ください。改良版を考えます。
良きUnityライフを。

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