- 2023/03/09 【Unity】エディタ上(Visual Studio等)のスクリプトをUTF8に固定する
- 2022/11/30 【Unity】マテリアルで使用しているシェーダを調べる
- 2022/10/30 【Unity】Standard Assets の Flare (レンズフレア) は Gamma 用だった?
- 2022/10/01 【Unity】【エディタ拡張】フィールドの値などをインスペクタで横に並べて表示する
- 2022/09/01 【Unity】【C#】3DText(TextMesh) を半透明より手前に表示する
【Unity】エディタ上(Visual Studio等)のスクリプトをUTF8に固定する 
2023/03/09 Thu [edit]
トラブルシューティングっぽいのが続いてるので、ついでに Unity エディタ上の問題もメモを残しておこう。
Unity2019(?) くらいからだろうか?エディタ上で作ったスクリプトをインスペクタ上で見ると、文字化けするようになったんだよね。

テキストエディタ上(Visual Studio等)では問題なく日本語表示されているので、気が付かなかったりするけど、どうやら Windows 上(?)ではデフォルトで Shift-JIS で保存されているらしい…。
Visual Studio上の設定では UTF-8 になってても、なぜか Unityエディタでは Shift-JIS になってしまう…。対処法をググってみたらやはり同じ問題に出くわした人も多いみたいで、アセットをインポート(更新)する際のイベントハンドラを使って、スクリプトで解決する方法があった。それを試してみたら上手く行ったので、Unity初心者でもわかるように手順を書いておこう。
(※) Unity 2021.3.18f1 / Visual Studio 2019 / Windows11(x64) で確認
1. まずは「新規スクリプト生成時にテキストエンコードをUTF-8に変換する」スクリプトを以下の github からコピーしよう。
・新規スクリプト生成時にテキストエンコードをUTF-8に変換する (github)

2. Unity エディタ上でプロジェクトビューから「Editor」フォルダを作り(場所は任意)、「右クリック>Create>C# Script」で新規スクリプトが作れるので、「AssetPostprocessUTF8Encode.cs」などにして作成する。ダブルクリックでテキストエディタ(Visual Studio等)を開いたら、github でコピーしたスクリプトをまるごと貼り付けて保存しよう。

3.「AssetPostprocessUTF8Encode.cs」の保存が完了したら、文字化けしているスクリプトを一旦編集などして保存し直す。すると UTF-8 になっているハズだ。インスペクタで確認しよう(インスペクタが更新されないなら、一旦フォーカスを外し、再度クリックする等)。

まぁ、どちらの文字コードでも実質問題は無いみたいなんだけどね。素早くインスペクタで中身を確認したいとき等は UTF-8 に統一しておいた方が良いだろう。また「AssetPostprocessUTF8Encode.cs」の 45行目には改行コードの変換も入っているようなので(CRLF→LF)、不要なら Replace() 以降を削除しても良いだろう。その辺りはご自由に。
●45行目に改行コード変換も入ってるので、無効化する場合。
// 改行コードの置き換え
//string contents = enc.GetString(bs).Replace("\r\n", "\n"); //元のコード(CRLF→LF変換)
string contents = enc.GetString(bs); //改行変換を取り除いたコード
(関連記事)
【Unity】Plugins フォルダのプラットフォーム別フォルダ名 メモ
【Unity】「Missing (Script)」を修復する
【Unity】Unity2019以降で新規作成したアセットは、Unity2018以前にインポートすると壊れる?
【Unity】タイトルバーの「PREVIEW PACKAGES IN USE」を消す
【Unity】【C#】インスペクタの値を保持したまま変数をリネームする
【Unity】マテリアルで使用しているシェーダを調べる 
2022/11/30 Wed [edit]
わりと何でもない事だけど、意外とググってもあまり出てこなかったので、メモ。
簡単に言うと、判別はシェーダの名前(文字列)で判別するのが簡単。名前はインスペクタで Material をクリックしたときに出る情報の一番上にある「Shader」の文字列だね。Standard シェーダを使っていれば「Standard」、MToon シェーダを使ってるなら「VRM/MToon」となってるあれだ。正確に判別するなら、スラッシュ('/')を含めたフルパスにすれば良いし、バリエーション[Standard (Specular setup) 等]を含めるなら一部を判別するのも良い。
(※) Unity 2020.3.34f1 / Windows11(x64) で確認
そう考えるとコードにするのは簡単だ。例えば以下のような感じで判別すれば良いだろう。
●マテリアルに Standard Shader が当てられていたら、メッセージを出す
Material material; //何かのマテリアルがセットされているとする
if (material.shader.name.Equals("Standard", StringComparison.Ordinal))
{
Debug.Log("This material uses Standard Shader.");
}
Eqauls に StringComparison.Ordinal オプションを付けてるのは、以前記事にした「StartsWith, EndsWith が遅いのなら、Equals も遅いのか?」のときの知見から。"==" 演算子でも良いが、参照比較と紛らわしいので(文字列の場合はおおよそ大丈夫だが)、最近は Ordinal オプション付きで比較することが多い(実行速度も速い)。Unity マニュアルにも文字列比較の遅さが指摘されているが、私が実験した所、Ordinal オプション(単純な文字列の並びだけで比較)さえ付けていれば、実行速度が極度に遅くなることは無かった(100文字程度なら全然変わらない)。C# のバージョンにもよるかもだが、覚えておくと役に立つこともあるだろう。
以上の事が理解できたなら、よく使うものは拡張メソッドにしておくのが簡単だ。例えば Stanard, MToon 判別なら、以下のように作るのも良い。
●Material に Standard Shader 系/MToon 系が使われているか?(バリエーションも含む)
using System;
using UnityEngine;
/// <summary>
/// Material に Standard Shader 系が使われているか?(バリエーションも含む)
/// 2022/11/30 Fantom
/// http://fantom1x.blog130.fc2.com/blog-entry-421.html
/// </summary>
/// <param name="material">調べる Material</param>
/// <returns>true のとき Standard (バリエーション含む)</returns>
public static bool IsAnyStandardShader(this Material material)
{
if (material == null)
return false;
return material.shader.name.StartsWith("Standard", StringComparison.Ordinal);
}
/// <summary>
/// Material に MToon Shader 系が使われているか?(バリエーションも含む)
/// ※"VRM/MToon" だが、UniVRM 0.89時点なので注意(1.0以降は"VRM10/MToon10")
/// 2022/11/30 Fantom
/// http://fantom1x.blog130.fc2.com/blog-entry-421.html
/// </summary>
/// <param name="material">調べる Material</param>
/// <returns>true のとき MTonn (MToon10 等含む)</returns>
public static bool IsAnyMToonShader(this Material material)
{
if (material == null)
return false;
return material.shader.name.Contains("MToon");
}
実際にはプロジェクトに何のシェーダが含まれているかで真になる範囲は異なってしまうので、厳密にしたければ、Equals(name, StringComparison.Ordinal) でフルパス完全一致にするのも良いだろう。その辺は好きにやって欲しい。
問題は文字列判別なので、「Autodesk Interactive」のように名前が変わったもの(Unity2017 以前は「Standard (Roughness setup)」となっていた)は注意が必要だけどね。厳密にするならプリプロセッサ(#if~)で Unity バージョン分けした方が良いかも知れない。
最近は VRM Live Viewer でもシェーダを使う機能が多くなってきた。実はなるべく Unity の標準機能で作った方が後バージョンの互換性が高いので、以前は避けていた感あるが、Unity は既にこれまでの Standard Shader 等を使う BRP(Built-in Render Pipeline) はレガシーとしているので、いずれ SRP(Scriptable Render Pipeline) に移行しなくてはならないのがわかってるんだよね。
問題はシェーダを使った機能は互換性が全く無くなってしまうこと。しかし現行の Unity製アプリやサービス(特に2020年以前からあるもの)は BRP を前提として作られているので、なかなか移行タイミングが難しい。全てを捨てて移行するならともかく、過去の大量の資産(対応素材)も捨てることになるからね。なので Asset Store でも「SRPとの互換性」が表示されていたり、BRP/SRP 両方の .unitypackage が含まれているものも出てきている。まぁ、有料アセットはサポートあるもの多いけど、無料アセットはほぼ絶望的だね。まず移行できるものは少ない。なので少し諦めがついたという所かな。こうなれば SRP に移行する直前まで、BRP でできることを何でも入れてしまえ、みたいな(笑)。まぁ、結果できることは増えているよ。しかし本当に SRP に移行するときには、ほぼ全て作り直し(内部的には別物)しなくちゃならないけどね。
実際、無料アプリって報酬0だから、システム的な仕様変更・移行はめちゃくちゃしんどい。それに現代は「アプリは無料で作って貰えるのが当たり前」って風潮が強いので「あれ欲しい・これ欲しい。次は〇〇あったらいいな」と延々と言われ続ける。企業なら先行投資としていずれ利益になるから良いかもだが、個人ではただ単に知らない人にタカられてるだけに過ぎないからね。超有名なソフトの開発者が通常表に出て来ず、雲隠れしてしまう気持ちが何となくわかる。無名な私ですら年間100件ほど来るのだ。有名なら1000件は下らないだろう(有名なクリエーターが年間700件[=1日2件]でも大量に時間を取られる事に気づき、仕方なく有料にした話もある)。
よく考えてみればわかるが、個人に対する要求はその人の貴重な活動時間を奪い、他人のために無償で時間を使え、と言われてるようなものだ。これはその人がやりたい活動や予定を阻害してるのと同義となる。逆に自分が何かやろうと思っていたときに、他人の都合で邪魔されたら嫌だろう?特に個人で活動・配布してくれてる人には気をつけて欲しいかな。要求だけ突きつけて、規約も守らず、いい加減に使われていたら、やる気を無くす人も多い(パッタリやめてしまう人も少なくない)。いつでも「自分が逆の立場だったらどう感じるか?」を考えて欲しいね。そういうお互いの理解が無いとずっとは続けられない(だいたい1~2年が最初の山、3年超えると安定し、5年で世の中の状況が変わり進退を決める時が来る。10年超えはもう活動もその人の一部となる。そこまで行ったら沢山の出会いと別れを経験する[=もう活動やめてしまった人の方が圧倒的に多くなる]。結局他人の思いつきでタダ働きさせられた事実だけが残る)。あと5年経ったら今活動している人どれくらい残ってるかな…?ちなみに私は20年はとっくに超えている(昔はSNS自体が存在しなかっただけ)。もうそうなると知識×経験の掛け合わせで、無限にアイデアは浮かぶようになる(現に VRM Live Viewer は4年を超えてるがアイデアは尽きたことなく、今なお増え続けている)。時間はいくらあっても足りないくらいにね(笑)。
(関連記事)
【Unity】【C#】StartsWith, EndsWith が遅いのなら、Equals も遅いのか?
【Unity】ガンマ(Gamma, sRGB) - リニア(Linear) 値の相互変換
【Unity】Quality (グラフィック品質) を文字列で取得/設定する
【Unity】Standard Assets の Flare (レンズフレア) は Gamma 用だった? 
2022/10/30 Sun [edit]
たぶん Unity2018.3 頃からだと思うけど、デフォルトのシーンに FlareLayer がアタッチされなくなったんだよね。Standard Assets も既にレガシーとなっているので、今更とは思うのだが、ググっても LensFlare 系のフリーアセットってあまり出てこないので、改めて Standard Assets を試してみた。
しかしう~ん…。なぜか私の記憶している感じと違う…。Unity5 の頃は Standard Assets は当たり前のように使ってたので、こんな感じの LensFlare じゃなかったような…。もっと綺麗に輝いていた気がするぞ…?
どうにもしっくり来ないので、古い Unity5 のプロジェクトを開いてみた。そして同じように Standard Assets の LensFlare を使ってみると見た目が全然違う!
比較してすぐに気づいたのは「Color Space の違い」なんだよね。Unity5 の頃は Gamma Color Space が普通に使われていたため、アセットも Gamma 用が普通だった。しかし Unity2018 以降は Linear Color Spane も Experiment(試験実装)的 ではなく、正式に採用されるようになっていったため、アセットも Linear 用(もしくは両対応)になっていった。以下の資料を見ても分かる通り、特に加算・合成といった処理では Color Space の違いがよく出るので、Standard Assets の LensFlare は Gamma 用だったと仮定すると説明がつく。
(参考) 分かる!リニアワークフローのコンポジット - 「加算が変わる」 参照
ならばテクスチャの「Import Settings の sRGB を外せば、リニアでも使える」みたいなことを VRMLiveViewer での Color Space 移行(v2.x→3.0α時代) で学んでいたので、試してみた。う~ん、それでも太陽以外はぼやけて見えない感じだな…。
そう言えば Flare asset 自体をあまり覗いたことなかったな~、と思って設定を見てみると Color プロパティがある。これも以前「ガンマ(Gamma, sRGB) - リニア(Linear) 値の相互変換」として記事を書いていたように既に学んでいたことなので、Linear 上で Gamma っぽい色にする:つまり Linear → Gamma の Color 変換 を試してみた。そしたら、Color Space の違いから色味が異なるのは仕方ないにしても、それなりに近い感じになった!
・Linear → Gamma の Color 変換

※全ての Element の Color プロパティを同様に Gamma 変換する
●Unity2020.3上(Linear Color Space)での Flare アセットの Color 設定を Linear → Gamma 変換してみる

最初の Unity5 の Gamma Color Space と比較してみると、やはり色の加算・合成的な部分で色味が異なるが(Gamma は色を重ねると輝きが強くなり、Linear は白っぽくなる傾向がある)、なるほど、Standard Assets の LensFlare は Gamma 用だったと言って間違いないようだ。
まとめると、
・テクスチャの Import Settings の sRGB のチェックを外す
・Flare asset の各 Element の Color プロパティを Gamma 変換する
で、それなりに近い感じにできる(※カラースペースによる差異はどうしてもあるが)
(関連記事)
【Unity】ガンマ(Gamma, sRGB) - リニア(Linear) 値の相互変換
【Unity】色形式:Unity の Color と Android の ARGB(int32) の相互変換をする
【Unity】Quality (グラフィック品質) を文字列で取得/設定する
【Unity】画面解像度とアクペクト比(整数)を求める
【HTML】HTMLカラー名・カラーコード表
【Unity】【エディタ拡張】フィールドの値などをインスペクタで横に並べて表示する 
2022/10/01 Sat [edit]
プロジェクトが大きくなってくるとデバッグが大変になってくるね。VRM Live Viewer は既に4周年を超えてしまったこともあって、とても巨大なシステムになってしまっている。Unity では Debug.Log を使うことも多いのだが、多くのオブジェクトがあると個々の状態が調べづらいので、最近はよくインスペクタをデバッグ代わりに使っている。
ただ独自クラス・構造体などを使うことも多いので、デフォルトだと全て縦に並んでしまうんだよね。なので Vector3 などの (x, y, z) のようにまとまってる要素は横に並べてすっきり表示したいことが多い。
そんな時は エディタ拡張の PropertyDrawer を使うと良い。簡単なものをメモとして載せておくので、色々応用すると良いだろう。

(※) Unity 2020.3.34f1 / Windows11(x64) で確認
●X, Y, Z 各軸の true / false 構造体の定義とインスペクタでの表示(PropertyDrawer)
using System;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace Example //※名前は任意
{
//定義クラス・構造体
/// <summary>
/// X, Y, Z 各軸の true / false 構造体
/// </summary>
[Serializable]
public struct AxisBool
{
public bool x;
public bool y;
public bool z;
public AxisBool(bool x, bool y, bool z)
{
this.x = x;
this.y = y;
this.z = z;
}
}
#if UNITY_EDITOR
//エディタ拡張(インスペクタ表示)
[CustomPropertyDrawer(typeof(AxisBool))]
public class AxisBoolDrawer : PropertyDrawer
{
static readonly GUIContent X_LABEL = new GUIContent("X");
static readonly GUIContent Y_LABEL = new GUIContent("Y");
static readonly GUIContent Z_LABEL = new GUIContent("Z");
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return EditorGUIUtility.singleLineHeight;
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
var xProperty = property.FindPropertyRelative("x");
var yProperty = property.FindPropertyRelative("y");
var zProperty = property.FindPropertyRelative("z");
//名前
label = EditorGUI.BeginProperty(position, label, property);
Rect contentPosition = EditorGUI.PrefixLabel(position, label);
//ラベル
contentPosition.width *= 1f / 3f; //3つ並べる場合 (n 個のとき、1 / n)
EditorGUI.indentLevel = 0;
EditorGUIUtility.labelWidth = 15f; //ラベル幅(適当)
//各要素
EditorGUI.PropertyField(contentPosition, xProperty, X_LABEL);
contentPosition.x += contentPosition.width;
EditorGUI.PropertyField(contentPosition, yProperty, Y_LABEL);
contentPosition.x += contentPosition.width;
EditorGUI.PropertyField(contentPosition, zProperty, Z_LABEL);
EditorGUI.EndProperty();
}
}
#endif
}
ポイントは定義クラス・構造体用の PropertyDrawer を継承したクラスを作ることで([CustomPropertyDrawer] 属性も付ける)、これは以前に書いた「インスペクタで入力不可(Disable)な属性を作る」と同じである。要するに表示位置を計算して描くだけなので、定型処理(文)のように考えた方が楽だろう。
テストは適当に GameObject にアタッチしたスクリプトに、フィールドとして追加すれば良い(public または [SerializeField] 属性を付ける)。
ついでにスクショのもう1つの方も書いておくと、以下のようになる。
●X, Y, Z 各軸の Min~Max 構造体の定義とインスペクタでの表示(PropertyDrawer)
using System;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace Example //※名前は任意
{
//定義クラス・構造体
/// <summary>
/// X, Y, Z 各軸の Min~Max 構造体
/// </summary>
[Serializable]
public struct RangeVector3
{
public float xMin;
public float xMax;
public float yMin;
public float yMax;
public float zMin;
public float zMax;
public RangeVector3(float xMin, float xMax, float yMin, float yMax, float zMin, float zMax)
{
this.xMin = xMin;
this.xMax = xMax;
this.yMin = yMin;
this.yMax = yMax;
this.zMin = zMin;
this.zMax = zMax;
}
}
#if UNITY_EDITOR
//エディタ拡張(インスペクタ表示)
[CustomPropertyDrawer(typeof(RangeVector3))]
public class RangeVector3Drawer : PropertyDrawer
{
static readonly GUIContent X_MIN_LABEL = new GUIContent("X Min");
static readonly GUIContent X_MAX_LABEL = new GUIContent("X Max");
static readonly GUIContent Y_MIN_LABEL = new GUIContent("Y Min");
static readonly GUIContent Y_MAX_LABEL = new GUIContent("Y Max");
static readonly GUIContent Z_MIN_LABEL = new GUIContent("Z Min");
static readonly GUIContent Z_MAX_LABEL = new GUIContent("Z Max");
const float lineSpace = 2f; //行間
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return EditorGUIUtility.singleLineHeight * 3 + lineSpace * 2;
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
var xMinProperty = property.FindPropertyRelative("xMin");
var xMaxProperty = property.FindPropertyRelative("xMax");
var yMinProperty = property.FindPropertyRelative("yMin");
var yMaxProperty = property.FindPropertyRelative("yMax");
var zMinProperty = property.FindPropertyRelative("zMin");
var zMaxProperty = property.FindPropertyRelative("zMax");
//名前
label = EditorGUI.BeginProperty(position, label, property);
Rect contentPosition = EditorGUI.PrefixLabel(position, label);
//ラベル
contentPosition.width *= 1f / 2f; //2つ並べる場合 (n 個のとき、1 / n)
EditorGUI.indentLevel = 0;
EditorGUIUtility.labelWidth = 40f; //ラベル幅(適当)
//各要素
contentPosition.height = EditorGUIUtility.singleLineHeight;
EditorGUI.PropertyField(contentPosition, xMinProperty, X_MIN_LABEL);
contentPosition.x += contentPosition.width;
EditorGUI.PropertyField(contentPosition, xMaxProperty, X_MAX_LABEL);
contentPosition.x -= contentPosition.width;;
contentPosition.y += EditorGUIUtility.singleLineHeight + lineSpace;
EditorGUI.PropertyField(contentPosition, yMinProperty, Y_MIN_LABEL);
contentPosition.x += contentPosition.width;
EditorGUI.PropertyField(contentPosition, yMaxProperty, Y_MAX_LABEL);
contentPosition.x -= contentPosition.width;;
contentPosition.y += EditorGUIUtility.singleLineHeight + lineSpace;
EditorGUI.PropertyField(contentPosition, zMinProperty, Z_MIN_LABEL);
contentPosition.x += contentPosition.width;
EditorGUI.PropertyField(contentPosition, zMaxProperty, Z_MAX_LABEL);
EditorGUI.EndProperty();
}
}
#endif
}
こちらも contentPosition を横・縦に移動して描いているだけと考えれば色々応用は利くだろう。日本語だとラベル幅からはみ出るかも知れないが(私は英語インターフェイスに慣れてしまってるので、日本語版は使ったことがない)、その辺はよしなに(笑)。
(参考)
・【Unity】最小と最大の値を管理する構造体を作りたいの
(関連記事)
【Unity】インスペクタで入力不可(Disable)な属性を作る
【Unity】インスペクタの表示項目を動的に変更する
【Unity】インスペクタの UnityEvent を並べ替え可能にする
【Unity】インスペクタの配列やリストを並べ替え可能にする
【Unity】インスペクタの値を保持したまま変数をリネームする
【Unity】独自のギズモ(Gizmo)を表示する
【Unity】【C#】3DText(TextMesh) を半透明より手前に表示する 
2022/09/01 Thu [edit]
VRM Live Viewer には 3D空間上に名前を表示する機能があるんだけど、それを実装したときの Tips の1つ。
Unity では 3D空間にテキストを表示する方法として 3DText (Text Mesh) というものがあり、常に最前面に表示されるので便利…と思ったら、半透明なものには後ろになってしまうんだよね。
VRM Live Viewer では自由にオブジェクトを配置できるので、最前面に出てくれないと、背景オブジェクトによっては後ろに回ってテキスト(名前)が見えなくなってしまう。
なので、ググってたら描画順を変更するために、シェーダを作ってる例があった。と言っても、これらは逆に後ろに回すためのものだけどね。
(3DText を後ろに周りこませる)
・3D Textの前後関係を正しく表示する
・3DTextの主張を止めたい
しかし、このためだけにシェーダ作るのも何だな~、と思ったので(シェーダはシステム依存が強いので、後々面倒になることが多い)、スクリプトで RenderQueue を変更してみたら、上手くいったので、その時のメモ。
(※) Unity 2020.3.34f1 / Windows11(x64) で確認
●3DText (Text Mesh) のRenderQueue を変更して、透明より手前に表示させる
using UnityEngine;
using UnityEngine.Rendering;
namespace Example
{
public class TextMeshRenderQueue : MonoBehaviour
{
public TextMesh textMesh; //描画順を変更する 3DText をアタッチ
public int renderQueue = (int)RenderQueue.Transparent + 1; //3001 (とりあえず、透過より大きくしておく)
private void Reset()
{
if (textMesh == null)
textMesh = GetComponent<TextMesh>();
}
// Use this for initialization
private void Start()
{
textMesh.font.material.renderQueue = renderQueue;
}
}
}
何らかの 3DText (Text Mesh) の1つにアタッチして、プレイするだけで、描画順が透明の RenderQueue + 1(Transparent+1 [=3000+1]) に変更されるので、常に最前面に表示されるようになる。3001 以上の描画順が他にあるなら、それより大きい値にすれば良い。
ただ欠点としては、TextMesh.font.material が sharedMaterial みたいなもの(?)だったので、3DText ごとに描画順を設定できないことかな。なので、全体で1つの描画順となる。試しに Material を複製して再設定してみたが、なぜか上手く行かなかった。まぁ、使い勝手は悪いが「全てにおいて最前面に表示」みたいな使い方なら、問題無く使える。
(関連記事)
【Unity】【C#】制限付きでテキストのサイズに合わせて他のオブジェクトのサイズも変化させる
【Unity】【C#】RectTransform の矩形の実座標を取得する(GetWorldCorners)
【Unity】【C#】uGUI ドロップダウンの要素をコードで設定と取得、外観のカスタマイズなど
【Unity】【C#】固定背景画像(2D)を表示する
【Unity】【C#】HDR Color を計算(変換)する
【Unity】【C#】ガンマ(Gamma, sRGB) - リニア(Linear) 値の相互変換