そういうのがいいブログ

アプリ個人開発 まるブログ

アプリ開発覚え書き

【Unity】ランタイムでAvatarを生成する

要件

Unity6000.026f1

はじめに

本記事での"Avatar"とはHumanoid型の3Dモデルを使う時にAnimator
に割りついているAvatar要素のことです。

ランタイムで生成する必要があったためメモします。

必要な情報

Avatarを生成するためには以下の関数を実行します。

AvatarBuilder.BuildHumanAvatar(GameObject型の引数, HumanDescription型の引数);

docs.unity3d.com


引数は次の2つです。
① GameObject 型の引数:Avatarを生成したい対象のゲームオブジェクト
② HumanDescription型の引数:アバターの情報

①は対象のゲームオブジェクトを指定するだけなので簡単です。

問題は②のHumanDescription型の引数です。

HumanDescription型はUnityのスクリプトリファレンスを見ると
以下の10個の変数から成っており、これらを指定する必要があります。

プロパティ名 説明
armStretch IK 使用時の腕の長さの引き伸ばし許容量
armStretch IK 使用時の腕の長さの引き伸ばし許容量
feetSpacing ヒューマノイドモデル脚部の最小距離の調整
hasTranslationDoF Degree of Freedom (自由度:DoF) 表現を持つすべてのヒューマンに対して true を返します。デフォルトで false に設定されます。
human Mecanim ボーン名とリグのボーン名の間におけるマッピング
legStretch IK 使用のときに許容する脚の伸び幅
lowerArmTwist 回転/ひねりを肘と手首にどの割合で反映するか定義します
lowerLegTwist 回転/ひねりを膝や足首にどの割合で反映するか定義します
skeleton モデルに含めるボーン Transform のリスト
upperArmTwist 回転/ひねりを肩と肘にどの割合で反映するか定義します
upperLegTwist 回転/ひねりを脚の付け根おと膝にどの割合で反映するか定義します

docs.unity3d.com

HumanDescriptionの設定

HumanDescriptionを設定するにあたって変数が10個あると言いましたが、
humanとskeleton以外は以下のデフォルト値があるのでその値を使用します。
(デフォルト値はHumanDescriptionの
 スクリプトリファレンスの変数ページに書いてあります。)

HumanDescription humanDescription = new HumanDescription
{
   armStretch = 0.05f,//IK(インバースキネマティクス)使用時の腕の長さの引き伸ばし許容量を設定します。0.05fは、腕が5%まで引き伸ばされることを許容することを意味します。
   feetSpacing = 0.0f,//ヒューマノイドモデルの脚部の最小距離の調整を設定します。0.0fは、脚部の間隔がデフォルトのままであることを意味します。
   hasTranslationDoF = false,//アバターの関節に対して平行移動の自由度を持たせないことを指定します。通常必要ないためfalseに設定します。
   human = 設定方法はこの後説明
   legStretch = 0.05f,//IK使用時の脚の長さの引き伸ばし許容量を設定します。0.05fは、脚が5%まで引き伸ばされることを許容することを意味します。
   lowerArmTwist = 0.5f,//回転/ひねりを肘と手首にどの割合で反映するかを定義します。0.5fは、回転が肘と手首に均等に分配されることを意味します。
   lowerLegTwist = 0.5f,//回転/ひねりを膝と足首にどの割合で反映するかを定義します。0.5fは、回転が膝と足首に均等に分配されることを意味します。
   skeleton = 設定方法はこの後説明
   upperArmTwist = 0.5f,//回転/ひねりを肩と肘にどの割合で反映するかを定義します。0.5fは、回転が肩と肘に均等に分配されることを意味します。
   upperLegTwist = 0.5f,//回転/ひねりを脚の付け根と膝にどの割合で反映するかを定義します。0.5fは、回転が脚の付け根と膝に均等に分配されることを意味します。
};


humanとskeletonについて見ていきます。


skeleton

取得がhumanより簡単なskeletonからいきます。

skeletonにはモデルが持つ配下オブジェクト全てのSkeletonBone型の情報を配列で渡します。

SkeletonBone型の情報とは以下の内容になります。

変数名 内容
name ボーンがマッピングされているトランスフォーム名
position ローカル空間でボーンの T ポーズの位置
rotation ローカル空間でボーンの T ポーズの角度
scale ローカル空間でボーンの T ポーズのスケール


Tポーズになっているという前提ですが、
Transform型を取得できていればSkeletonBone型の情報は次のスクリプトで取得できます。
※Tポーズでない状態の情報を設定した場合、どのような不具合がでるかは未検証です。

    SkeletonBone bone = new SkeletonBone
    {
        name = Transform型の変数.name,
        position = Transform型の変数.localPosition,
        rotation = Transform型の変数.localRotation,
        scale = Transform型の変数.localScale
    };


あとは指定した親ゲームオブジェクトのTrasnform型から
配下全てのTransform型へアクセスすればskeletonの情報は作成できます。

まず、SkeletonBone型のリスト作成と、
配下オブジェクトにアクセスして情報を取得する関数を設置します。

    /// <summary>
    /// HumanDescription.skeleton 用の SkeletonBone 配列を生成
    /// </summary>
    /// <param name="root">スケルトン階層のルート Transform</param>
    /// <returns>SkeletonBone 配列</returns>
    private static SkeletonBone[] GenerateSkeleton(Transform root)
    {
        // 引数が null の場合はエラー
        if (root == null)
        {
            Debug.LogError("Root Transform is null.");
            return null;
        }
        
        // スケルトンボーンのリストを作成
        List<SkeletonBone> skeletonBones = new List<SkeletonBone>();
        
        // 再帰的にスケルトンを構築
        BuildSkeletonRecursive(root, skeletonBones);
        
        // スケルトンボーンのリストを配列に変換して返す
        return skeletonBones.ToArray();
    }
    
    /// <summary>
    /// 再帰的に SkeletonBone を構築
    /// </summary>
    /// <param name="current">現在の Transform</param>
    /// <param name="skeletonBones">構築中の SkeletonBone リスト</param>
    private static void BuildSkeletonRecursive(Transform current, List<SkeletonBone> skeletonBones)
    {
        // SkeletonBone を作成
        SkeletonBone bone = new SkeletonBone
        {
            name = current.name,
            position = current.localPosition,
            rotation = current.localRotation,
            scale = current.localScale
        };
        
        // 作成した SkeletonBone をリストに追加
        skeletonBones.Add(bone);
        
        // 子要素を再帰的に処理
        // 子要素がない場合は何もしない
        // foreachでTransform型に対してループをまわすと子要素に対して処理ができる
        foreach (Transform child in current)
        {
            BuildSkeletonRecursive(child, skeletonBones);
        }
    }


そして、関数GenerateSkeleton に親ゲームオブジェクトのTrasnform型の情報を
渡して実行することで取得可能です。

        // ターゲットのオブジェクトのTransformからモデルのTransformの配列を作成
        SkeletonBone[] skeletonBones = GenerateSkeleton(親ゲームオブジェクトのTrasnform型);

以上がskeletonの取得方法になります。


human

humanにはHumanBone型の情報を配列で渡します。

HumanBone型の情報とは以下の内容になります。

変数名 内容
boneName Mecanim のヒューマノイド型ボーンがマッピングされたボーン名
humanName モデルにおけるボーンのマッピング元となる Mecanim のヒューマノイド型ボーン名
limit ボーンにおける割り込みの可動域を返す


説明欄にマッピングという言葉が出てきて困惑しますね。
HumanBone型は簡単に言えば、
"Unityが定義しているボーン名 humanName "に対する
"3Dモデルが持つボーン名 boneName ”の対応情報です。

Unity上にて3Dモデル配下のAvatarを選択し「アバターを設定」を押すと表示される情報を
作るためのものといえばわかりやすいでしょうか。



設定可能なボーン情報は以下の55種類です。
(最後のLastBoneは飾りみたいなものなのでカウント対象外です。)

そのうち、登録が必須のボーン情報は赤文字の15種類になります。

HumanBone型の humanName に対しては
下表の"ボーン名"のいずれかを指定することになります。

番号 ボーン名
1 Hips
2 LeftUpperLeg
3 RightUpperLeg
4 LeftLowerLeg
5 RightLowerLeg
6 LeftFoot
7 RightFoot
8 Spine
9 Chest
10 UpperChest
11 Neck
12 Head
13 LeftShoulder
14 RightShoulder
15 LeftUpperArm
16 RightUpperArm
17 LeftLowerArm
18 RightLowerArm
19 LeftHand
20 RightHand
21 LeftToes
22 RightToes
23 LeftEye
24 RightEye
25 Jaw
26 LeftThumbProximal
27 LeftThumbIntermediate
28 LeftThumbDistal
29 LeftIndexProximal
30 LeftIndexIntermediate
31 LeftIndexDistal
32 LeftMiddleProximal
33 LeftMiddleIntermediate
34 LeftMiddleDistal
35 LeftRingProximal
36 LeftRingIntermediate
37 LeftRingDistal
38 LeftLittleProximal
39 LeftLittleIntermediate
40 LeftLittleDistal
41 RightThumbProximal
42 RightThumbIntermediate
43 RightThumbDistal
44 RightIndexProximal
45 RightIndexIntermediate
46 RightIndexDistal
47 RightMiddleProximal
48 RightMiddleIntermediate
49 RightMiddleDistal
50 RightRingProximal
51 RightRingIntermediate
52 RightRingDistal
53 RightLittleProximal
54 RightLittleIntermediate
55 RightLittleDistal
56 LastBone


話は少しそれますが、アバター情報をよくみると必須ボーンと任意設定ボーンでは
アイコンが異なっていることがわかります。

設定必須のボーン アイコン

任意設定のボーン アイコン


ではプログラムで
"Unityが定義しているボーン名 humanName "に対する
"3Dモデルが持つボーン名 boneName ”の対応情報を設定します。

繰り返しで処理するためDictionary型を使用して
humanName と boneName の対応関係を書きます。

        Dictionary<string, string> boneNameMap = new Dictionary<string, string>
        {
            ["Hips"] = 対応するボーン名,
            ["LeftUpperLeg"] = 対応するボーン名,
            ["RightUpperLeg"] = 対応するボーン名,
            ["LeftLowerLeg"] = 対応するボーン名,
            ["RightLowerLeg"] = 対応するボーン名,
            ["LeftFoot"] = 対応するボーン名,
            ["RightFoot"] = 対応するボーン名,
            ["Spine"] = 対応するボーン名,
            ["Head"] = 対応するボーン名,
            ["LeftUpperArm"] = 対応するボーン名,
            ["RightUpperArm"] =対応するボーン名,
            ["LeftLowerArm"] = 対応するボーン名,
            ["RightLowerArm"] = 対応するボーン名,
            ["LeftHand"] = 対応するボーン名,
            ["RightHand"] = 対応するボーン名,
        };


具体例としてmixamoからダウンロードできる
"Hip Hop Dancing"というモデルデータで設定してみます。

このモデルのアバター情報は以下です。


必須ボーンの"Hips"や"LeftUpperLeg"に対応するボーン名を
インスペクターから把握して先ほどのプログラムを作ります。


例えば、必須ボーン"Hips"に対応しているボーン名は
"mixamorig:Hips"であることが把握できます。

そのため"Hips"に対応する名前は"mixamorig:Hips"と書きます。

        Dictionary<string, string> boneNameMap = new Dictionary<string, string>
        {
             ["Hips"] = "mixamorig:Hips",
     ・
     ・
      省略
     ・
     ・
        };


今回のモデルでは必須ボーンに対応するボーン名は以下になりました。

        // ボーン名マッピングの情報
        Dictionary<string, string> boneNameMap = new Dictionary<string, string>
        {
            ["Hips"] = "mixamorig:Hips",
            ["LeftUpperLeg"] = "mixamorig:LeftUpLeg",
            ["RightUpperLeg"] = "mixamorig:RightUpLeg",
            ["LeftLowerLeg"] = "mixamorig:LeftLeg",
            ["RightLowerLeg"] = "mixamorig:RightLeg",
            ["LeftFoot"] = "mixamorig:LeftFoot",
            ["RightFoot"] = "mixamorig:RightFoot",
            ["Spine"] = "mixamorig:Spine",
            ["Head"] = "mixamorig:Head",
            ["LeftUpperArm"] = "mixamorig:LeftArm",
            ["RightUpperArm"] = "mixamorig:RightArm",
            ["LeftLowerArm"] = "mixamorig:LeftForeArm",
            ["RightLowerArm"] = "mixamorig:RightForeArm",
            ["LeftHand"] = "mixamorig:LeftHand",
            ["RightHand"] = "mixamorig:RightHand",
        };


このDictionary型の情報から以下のプログラムでHumanBone型の配列を作ります。

    /// <summary>
    /// ボーン名マッピング情報から HumanBone 配列を生成
    /// </summary>
    /// <param name="boneNameMap">ボーン名マッピング情報</param>
    /// <returns></returns>
    private HumanBone[] CreateHumanBones(Dictionary<string, string> boneNameMap)
    {
        // HumanBone のリストを作成
        List<HumanBone> humanBones = new List<HumanBone>();
        
        // マッピング情報を元に HumanBone を作成
        foreach (var pair in boneNameMap)
        {
            // HumanBone を作成
            HumanBone humanBone = new HumanBone
            {
                humanName = pair.Key,
                boneName = pair.Value,
                limit = new HumanLimit { useDefaultValues = true }
            };
            
            // HumanBone をリストに追加
            humanBones.Add(humanBone);
        }
        
        // HumanBone のリストを配列に変換して返す
        return humanBones.ToArray();
    }


上記プログラムの中でHumanBone型を作成する部分は以下です。
こちらをDictionary型の要素分繰り返しています。
HumanBone型の中のlimitはHumanLimit型になります。
こちらはデフォルト値を使用する書き方で書きました。

            // HumanBone を作成
            HumanBone humanBone = new HumanBone
            {
                humanName = pair.Key,
                boneName = pair.Value,
                limit = new HumanLimit { useDefaultValues = true } // デフォルト値を使用
            };

あとは、関数CreateHumanBones に
ボーン名マッピング情報が入ったDictionary型の情報を渡して実行することで取得可能です。

        // ボーン名マッピングの情報からHumanBoneのリストを作成
        HumanBone[] humanBones = CreateHumanBones(Dictionary型のボーンマッピング情報);

以上がhumanの取得方法になります。

プログラム全文

mixamoからダウンロードできる"Hip Hop Dancing"の
モデルデータを使用する前提のプログラムです。

using System.Collections.Generic;
using UnityEngine;

public class GenerateAvatarTest : MonoBehaviour
{
    //アバターを生成したい対象のゲームオブジェクト
    [SerializeField] private GameObject _targetModel;
    
    //アバターを生成する対象のアニメーターコンポーネント
    private Animator _animator;
    
    void Start()
    {
        // アニメーターコンポーネントを取得
        _animator = _targetModel.GetComponent<Animator>();

        // アバターを生成
        GenerateAvatar();
    }

    
    
    /// <summary>
    /// アバターを生成
    /// </summary>
    private void GenerateAvatar()
    {
        //最終的にAvatarBuilder.BuildHumanAvatar (引数1 GameObject型, 引数2 HumanDescription型);を使用してアバターを生成する
        //引数1はアバターを生成したいゲームオブジェクト
        //引数2はアバターの構造を定義するHumanDescription構造体
        
        
        // ボーン名マッピングの情報
        Dictionary<string, string> boneNameMap = new Dictionary<string, string>
        {
            ["Hips"] = "mixamorig:Hips",
            ["LeftUpperLeg"] = "mixamorig:LeftUpLeg",
            ["RightUpperLeg"] = "mixamorig:RightUpLeg",
            ["LeftLowerLeg"] = "mixamorig:LeftLeg",
            ["RightLowerLeg"] = "mixamorig:RightLeg",
            ["LeftFoot"] = "mixamorig:LeftFoot",
            ["RightFoot"] = "mixamorig:RightFoot",
            ["Spine"] = "mixamorig:Spine",
            ["Head"] = "mixamorig:Head",
            ["LeftUpperArm"] = "mixamorig:LeftArm",
            ["RightUpperArm"] = "mixamorig:RightArm",
            ["LeftLowerArm"] = "mixamorig:LeftForeArm",
            ["RightLowerArm"] = "mixamorig:RightForeArm",
            ["LeftHand"] = "mixamorig:LeftHand",
            ["RightHand"] = "mixamorig:RightHand",
        };
        
        // ボーン名マッピングの情報からHumanBoneのリストを作成
        HumanBone[] humanBones = CreateHumanBones(boneNameMap);
        
        // ターゲットのオブジェクトのTransformからモデルのTransformの配列を作成
        SkeletonBone[] skeletonBones = GenerateSkeleton(_targetModel.transform);
        
        HumanDescription humanDescription = new HumanDescription
        {
            armStretch = 0.05f,//IK(インバースキネマティクス)使用時の腕の長さの引き伸ばし許容量を設定します。0.05fは、腕が5%まで引き伸ばされることを許容することを意味します。
            feetSpacing = 0.0f,//ヒューマノイドモデルの脚部の最小距離の調整を設定します。0.0fは、脚部の間隔がデフォルトのままであることを意味します。
            hasTranslationDoF = false,//アバターの関節に対して平行移動の自由度を持たせないことを指定します。通常必要ないためfalseに設定します。
            human = humanBones,
            legStretch = 0.05f,//IK使用時の脚の長さの引き伸ばし許容量を設定します。0.05fは、脚が5%まで引き伸ばされることを許容することを意味します。
            lowerArmTwist = 0.5f,//回転/ひねりを肘と手首にどの割合で反映するかを定義します。0.5fは、回転が肘と手首に均等に分配されることを意味します。
            lowerLegTwist = 0.5f,//回転/ひねりを膝と足首にどの割合で反映するかを定義します。0.5fは、回転が膝と足首に均等に分配されることを意味します。
            skeleton = skeletonBones,
            upperArmTwist = 0.5f,//回転/ひねりを肩と肘にどの割合で反映するかを定義します。0.5fは、回転が肩と肘に均等に分配されることを意味します。
            upperLegTwist = 0.5f,//回転/ひねりを脚の付け根と膝にどの割合で反映するかを定義します。0.5fは、回転が脚の付け根と膝に均等に分配されることを意味します。
        };
        
        // アバターを生成
        var avatar = AvatarBuilder.BuildHumanAvatar (_targetModel, humanDescription);
        
        //確認
        if (avatar.isValid && avatar.isHuman)
        {
            _animator.avatar = avatar;
            Debug.Log("Avatar created successfully!");
        }
        else
        {
            Debug.LogError("Avatar creation failed.");
        }
        
    }
    
    
    /// <summary>
    /// ボーン名マッピング情報から HumanBone 配列を生成
    /// </summary>
    /// <param name="boneNameMap">ボーン名マッピング情報</param>
    /// <returns></returns>
    private HumanBone[] CreateHumanBones(Dictionary<string, string> boneNameMap)
    {
        // HumanBone のリストを作成
        List<HumanBone> humanBones = new List<HumanBone>();
        
        // マッピング情報を元に HumanBone を作成
        foreach (var pair in boneNameMap)
        {
            // HumanBone を作成
            HumanBone humanBone = new HumanBone
            {
                humanName = pair.Key,
                boneName = pair.Value,
                limit = new HumanLimit { useDefaultValues = true } // デフォルト値を使用
            };
            
            // HumanBone をリストに追加
            humanBones.Add(humanBone);
        }
        
        // HumanBone のリストを配列に変換して返す
        return humanBones.ToArray();
    }
    
    
    /// <summary>
    /// HumanDescription.skeleton 用の SkeletonBone 配列を生成
    /// </summary>
    /// <param name="root">スケルトン階層のルート Transform</param>
    /// <returns>SkeletonBone 配列</returns>
    private static SkeletonBone[] GenerateSkeleton(Transform root)
    {
        // 引数が null の場合はエラー
        if (root == null)
        {
            Debug.LogError("Root Transform is null.");
            return null;
        }
        
        // スケルトンボーンのリストを作成
        List<SkeletonBone> skeletonBones = new List<SkeletonBone>();
        
        // 再帰的にスケルトンを構築
        BuildSkeletonRecursive(root, skeletonBones);
        
        // スケルトンボーンのリストを配列に変換して返す
        return skeletonBones.ToArray();
    }
    
    
    /// <summary>
    /// 再帰的に SkeletonBone を構築
    /// </summary>
    /// <param name="current">現在の Transform</param>
    /// <param name="skeletonBones">構築中の SkeletonBone リスト</param>
    private static void BuildSkeletonRecursive(Transform current, List<SkeletonBone> skeletonBones)
    {
        // SkeletonBone を作成
        SkeletonBone bone = new SkeletonBone
        {
            name = current.name,
            position = current.localPosition,
            rotation = current.localRotation,
            scale = current.localScale
        };
        
        // 作成した SkeletonBone をリストに追加
        skeletonBones.Add(bone);
        
        // 子要素を再帰的に処理
        // 子要素がない場合は何もしない
        // foreachでTransform型に対してループをまわすと子要素に対して処理ができる
        foreach (Transform child in current)
        {
            BuildSkeletonRecursive(child, skeletonBones);
        }
    }
    
}


実行

実際に動かします。

モデルをヒエラルキー上に配置すると
Animatorコンポーネントの"Avatar"はすでに設定されているので予めを削除しておきます。

作成した"GenerateAvatarTest"スクリプトを割り当てて"Target Model"を指定します。

実行するとAvatarが生成されたことが確認できます。

ボーンマッピング情報作成方法が肝

今回、必須ボーンに対するボーン名は事前に把握できている状態でしたが、
ランタイムでインポートしたモデルは対応するボーン名が事前にわかりません。

このような場合はボーンマッピング情報をどのようなアルゴリズムで決定するのかが
正常なAvatar生成に関して肝になってきます。

Avatar生成が成功していてもHipsに対応するボーンを足のボーンに設定しまったとしたら
アニメーションした時におかしな動きになるのが想像できると思います。

Unity上ではUnityが勝手に対応するボーンを判定して設定してくれますが、
そのアルゴリズムは公開されていないようなので
自分でアルゴリズムを見出す必要があるようです。

おわりに

アバター生成に必要な必須のボーン情報はスクリプトリファレンスの
HumanTrait.RequiredBoneの例文を実行することで確認することができます。

docs.unity3d.com

Unityバージョンで結果が異なる可能性があるためAvatar生成前に
必須ボーン情報が存在するかを確認すると良さそうですね。

参考

docs.unity3d.com

docs.unity3d.com

【Unity】Mac向けにビルドしたアプリでデバックログを確認する方法

要件

Unityバージョン 6000.0.26f1

はじめに

Mac向けのビルドしたアプリのデバッグログを確認する方法をメモ

「プレイヤーログを使用」にチェックをいれてプレイヤーログを開くだけでした。

事前確認

「プレイヤーログを使用」にチェックをいれます。

→編集
→プロジェクト設定
→プレイヤー
→解像度と表示
→プレイヤーログを使用

プレイヤーログを開く

Unityでいつも使っているコンソールウインドウの右上の・が縦に3つ並んでいるボタンを押し、
「プレイヤーログを開く」を選択します。


するとPlayer.logという画面が出現します。
あとはMac向けのアプリを実行すればDebug.Log()の内容が表示されます。

おわりに

日本語のログ表示も可能なところは地味に嬉しい。

参考

note.com

【Unity】URPプロジェクトでシーンビューとゲームビューで色味が違う時の対策方法

要件

Unity 6000.0.26f1

はじめに

URPプロジェクトでシーンビューとゲームビューで色味が違うということがありました。
メモとして対策を載せておきます。

方法

Cameraオブジェクトのインスペクター
レンダリング>ポストプロセスの項目をオンにするだけです。

ポストプロセスを自分でかけた認識はなかったのですが
URPプロジェクトではデフォルトでかかるんですかねー??

ちなみにポストプロセスの設定はこちら

プロジェクト設定>グラフィックス
の一番上に設定されているファイルで調整できます。
今回の場合は「PC_RPAsset」


「PC_RPAsset」ファイルをクリックして
インスペクター上の「ボリューム」で調整可能です。

【Unity】macOS、Windows向けにビルドすると全画面表示になってしまう問題への対策方法

要件

Unity 6000.0.26f1

はじめに

macOSWindows向けにビルドすると全画面表示になってしまったので
ウインドウ化の設定を行います。

手順

→編集
→プロジェクト設定


→プレイヤー
→「解像度と表示」のタブを開く


全画面モードをウインドウ化に設定します。


あとはデフォルトの画面幅、画面高さを設定し、
必要であればリサイズ可能なウインドウにチェックを入れます。

【Unity】UniTaskとUniRxをOpenUPMを利用して簡単に導入する

はじめに

UniTaskとUniRxの導入を毎度忘れるのでメモ

事前設定

→編集
→プロジェクト設定



パッケージマネージャーの項目から下図の内容で入力していきます。

・名前
 OpenUPM(なんでもよい)

・URL

http://package.openupm.com


・Scope
 UniTask用

com.cysharp.unitask

 UniRx用

com.neuecc.unirx


→保存

インストール

パッケージマネージャーへ移動してインストールします。
→ウインドウ
→パッケージマネージャー

→マイレジストリ
→OpenUPM

UniTaskとUniRxをインストール

【Unity】使用していないファイルを確認できるパッケージ Search Extensions

要件

・Unity 2021.3.27f1
・Search Extensions 1.0.1

はじめに

無料で使用していないファイルを確認できるパッケージがあるということで

Search Extensionsを試してみました。

そのメモです。

github.com

導入手順

→ウインドウ
→パッケージマネージャー


→「+」ボタン
→GIT URLからパッケージを加える


→以下のURLを入力

https://github.com/Unity-Technologies/com.unity.search.extensions.git?path=package

→「追加」ボタンを押す


設定方法

→ウインドウ
→検索
Dependency Viewer


Dependency Viewerのウインドウが開きます。


→「選択」ボタン
→「Used By」を選択


→ウインドウ
→検索
→Rebuild dependency index


これで少し待つとファイルの右側に参照されている数が表示されるようになります。

上記の画像を見てみると、
「Test Animator Controller」の数字は0、
「Wait Animator Controller」の数字は2となっています。

そのため、「Test Animator Controller」はどこにも使用されていないこと、
「Wait Animator Controller」はどこか2箇所で使用されていることがわかります。


指定したファイルがどこで使われているのかも分かる

ちなみに先ほど表示した「Dependency Viewer」を確認することで
指定したファイルが、どこで使われているのかも分かってしまいます!

前述の「Wait Animator Controller」はどこか2箇所で使用されているとのことでした。

「Wait Animator Controller」のファイルをクリックしてから
Dependency Viewer」のウインドウを見てみましょう。


すると、以下のように参照関係が表示されます。
(さきほどUsed Byと選択した箇所をSelectionにする必要があります。)
左側(Uses) に「Wait Animator Controller」使用しているファイル
右側(Used By)に「Wait Animator Controller」使用しているファイル


今回の場合、
「Wait Animator Controller」のファイルは
以下の2つのファイルで使用されることがわかりました。


そして、「Dependency Graph Viewer」を使用すれば
関係性の可視化もできてしまうようです。 www.hanachiru-blog.com

おわりに

ファイルの使用数がわかるだけでも便利なのに
どこで使われているかも簡単に分かるので必須のパッケージではないでしょうか。

注意点としては実験版で正式版ではないので使用は自己責任というところです。

なにか参考になりましたら幸いです。


追記
表示される参照数はRebuild dependency indexを選択した時点での数です。
リアルタイムでは更新されないため、
参照数を確認する際は Rebuild dependency index 毎回押す必要があります。

参考

baba-s.hatenablog.com

Steam開発者登録 Steamworksへ登録する方法

はじめに

Steamにアプリケーションをリリースしたい!
と思い立ったので2024年10月19日現在の環境で登録していきましたので残します。

Steamアカウントを持っている前提で書きます。

Steamworksに開発者登録

1.Steamworksにアクセス

partner.steamgames.com

Steamアカウントを持っている場合はサインインから登録します。


サインイン後、以下の画面になり登録理由を聞かれます。
「自分自身が開発者またはパブリッシャーであるため。」を選択します。


確認事項が表示されます。
以下のリリースまでの時間制約は頭に入れておく必要がありますね。

最初の数タイトルを Steam でリリースできるようになるまでに、いくつかの追加の時間的要件があります:

1.アプリ料金を支払ってから、ゲームをリリースできるようになるまで30日間お待ちいただきます。Valve はこの期間を、取引相手の情報確認に使用します。

2.ストアページを準備して、最低2週間『近日登場』ページを公開します。購入に興味を持つ潜在顧客を作り出す他、ゲームはウィッシュリストに追加可能になり、ユーザーは掲示板での話題に参加できるようになります。製品について説明する練習もできますので、 『リリース』ボタンを押す準備が整った頃には、最高のプレゼンができるようになっているはずです。


一読して画面下の「続ける」ボタンを押します。



2.名前と住所の入力

必要事項の入力画面に遷移します。

項目「FAX番号」以外の項目を入力します。
入力は全て英語です。
Taro Yamadaのように名前も英字で入力します。

住所は英語にしてくれるサイトを使うと良いです。

kimini.jp

 

入力後、画面下の「続ける」ボタンを押します。

 

3.秘密保持契約(NDA)に署名

秘密保持契約の内容が表示されます。
チェックボックスにチェックを入れ「続ける」ボタンを押します。


4.配信契約(SDA)に署名

入力内容は以下です。
・署名者の氏名:英語で入力
・署名者の肩書き:個人の場合はOwnerと記入
・署名者の電話番号:日本で通常使用する電話番号を記入(+81は使いません)
チェックボックスにチェック
・表示された画像の文字を入力

入力後、「続ける」ボタンを押します。

5.100ドルの支払い

このタイミングで100ドルを支払う必要があります。
※1000ドルの売り上げを達成すれば返却されます。

「続ける」ボタンを押下します。


支払い情報を入力します。
支払い情報は英語で入力しました。
入力後、「続ける」ボタンを押します。

   

確認画面に遷移します。
利用規約の合意にチェックして「購入」を押します。
日本円では15,000円でした。

 
 
支払い後、先ほどの画面に戻ります。
「続ける」ボタンを押します。

その後、別ウインドウでSteamにログインする画面が現れ、
再度購入画面に移動しました。

元のウインドウでは下記の「支払いの受け取り情報入力」画面に進んでいたため
元のウインドウの方で進めています。

 

6.支払いの受け取り情報入力

売上げの振込先と税金情報を入力します。
売上げはドルで入金されるため、
外貨受け取りができる口座でなければいけないようです。
(登録できたとしても送金エラーになるとの情報あり。)

今回はWiseのUSD建ての口座を登録しました。

Wiseとは・・・
格安の海外送金サービスです。

私はUnityAdsのアプリ広告収益を別の海外送金サービスであるPaypalで受け取っています。
PayPal(ドル)→日本の銀行(円)
ですと送金手数料が高すぎるので
PayPal(ドル)→Wise(ドル)→日本の銀行(円)
で受け取っています。

UnityAdsのアプリ広告収益を直接銀行へ送金する場合も手数料が高いので
Steam(ドル)→日本の銀行(円)
よりも
Steam(ドル)→Wise(ドル)→日本の銀行(円)
の方が手数料が安く済むはずです。
(好きな時にドルを円に変えられるのも嬉しい)

Wiseで75,000円までの送金手数料が無料になる紹介リンクを置いときます。
Wiseの登録ページ

6.1 支払い情報入力

「お支払い詳細の入力」ボタンを押して進みます。


口座開設国の確認画面が出ます。
WiseのUSD口座(ドル建て口座)の口座開設国はアメリカのため
「United States」を選択します。

必要事項を入力します。

以下、4項目はWiseのUSD口座情報の内容を転記します。
・受取人名
・受取人の口座番号
・ABA/ルーティングナンバー
・銀行名

「口座の種類」についてはUSD口座情報の口座種別が"チェッキング"であれば
"当座預金口座"を選択します。

「保存」ボタンを押します。

6.2 税金情報の入力

「税金情報の変更」ボタンを押して進みます。

「続く」を押します。


6.2.1 プロフィール:出生情報

最初の項目を「個人」と選択した場合です。
・名前:自動入力されるため確認
・出生時の氏名:結婚して名字が変わった場合は入力
・ビジネス、貿易、DBA、またはシングル・メンバーLLC名:未入力でOK
・出生地—町/市:都道府県、市までを英語で記入
・出生国家:該当する国を選択 ・国籍:該当する国を選択 ・主な連絡先:電話番号を入力
 例:090-1234-5678なら
 先頭に+81
 090の先頭0を抜いた
 +81-90-1234-5678を入力

・身分証明書:パスポート、運転免許証を選択
(メールで写真を送ることになります。)


6.2.2 プロフィール:本籍情報

本籍地を英字で入力します。


入力後、「続く」を押すと下記の住所エラーがでます。


住所が問題無ければ下記のチェックボックスにチェックして「続く」を押します。
「入力された住所が無効であるとのエラーメッセージを受信しましたが、私の住所が有効であることを確認しました。」

6.2.3 プロフィール:現在住所

現在の住所情報を英字で入力します。 先ほどと同じ要領で入力しました。


6.2.4 同意

2項目とも「はい」にチェックを入れ「続く」を押す。


6.2.5 状態:課税上の地位

米国市民、米国居住者に該当するかを聞かれるので「いいえ」を選択して「続く」を押す。


6.2.6 状態:受益者

個人の場合、自動で「Individual」と入力されているのでそのまま「続く」を押す。


6.2.7 状態:米国人のテスト

項目に該当しないか確認して「上記は適用されません」にチェックして「続く」を押す。


6.2.8 状態:条約のメリット

居住国を選択。
Japanが自動で選択されているはずなのでそのまま「続く」を押す。


6.2.9 状態:納税者番号

必要事項を入力

・TINをお持ちですか?:「はい」にチェック
・米国TIN:未入力
・外国TIN:マイナンバーを入力

チェックボックス
 所得税目的のために、提供された外国TINが正確であることを確認します。  ※自動でチェックされるが自分でチェックを入れないと「続く」ボタンが表示されませんでした。

「続く」ボタンを押す。


6.2.10 状態:条約目的による所得分類

源泉徴収税率が0%と表示されるはずです。
「続く」を押します。


6.2.11 状態:効率的に連続な収入

質問に該当する方を選択します。
私は「いいえ」にチェックして「続く」を押します。


6.2.12 レビュー

W-8BENが出来上がるので「続く」を押します。


6.2.13 署名および提出

必要事項を入力

チェックボックス全てにチェック
・受益者の名前:名前を英字で入力
・メールアドレス:Steamアカウントのメールアドレス
・事業能力:個人の場合「individual」と入力

入力後、「W 8BENを提出します。」ボタンを押します。

6.3 本人情報送付

税金情報の提出が終わると、税金情報欄に
「本人確認保留中」という枠が表示されます。

枠内に記載のとおり、追加情報が必要であればメールが送られてくるので対応します。

私の場合、すぐにメールが送られてきており、
メールには身分証明書類をアップロードする用のDropboxリンクがついていました。

メールに書いてあった提出が必要な画像は2つです。
・運転免許証
・運転免許証を手に持った自撮り写真
 ※税金情報の中で身分証明書は運転免許証を選択しているため

メール内に書かれていた注意点はまとめると4点でした。
・運転免許証の表面と裏面をアップロードすること
・自撮り写真は書類を手に持ち、自分の顔と書類がはっきりと映っていること
・カードの縁が見切れていないこと
・ファイル形式はPDFもしくはJPEGであること

画像の準備ができたらメールに記載されていた
Dropboxのリンク先にアップロードして完了です。

7.審査完了を待つ

審査完了まで2〜7日かかると書いてあります。

書類に不備、不足があるとメールが届きますので毎日メールをチェックした方が良いです。

提出書類の承認後、承認されましたメールが届きます。

8.ようやく登録完了!

最後はボタンをポチポチして完了です。


Steamworksにアクセス partner.steamgames.com


ダッシュボードを表示」


登録プロセスの「続行する」ボタンから進めていきます。


画面下部に"アカウント作成を完了"の項目が出現しているはずです。
「続ける」ボタンを押して進めます。


おめでとうございます!
これで登録完了です!

おわりに

開発者登録まで数時間あればできると勝手に想像していましたが
審査だけでもなかなか時間がかかりますね。

何か参考になりましたら幸いです。



marumaro7.hatenablog.com