<3>Debugを使った視覚的なデバッグ:Debug.DrawRay()
Unityでは、ベクトルの向きやオブジェクトの位置を確認したいことが良くありますが、Debug.Log()でベクトルの要素を数字で表示しても直感的にはなかなか理解できません。そのようなときにベクトルを視覚的に表示させることができます。基本的には次の3つの方法があります。
・Gizmosを使う方法
・Debugクラスの3D表示機能を使う方法
・GLを使う方法
下記のGif画像において、青線はGizmos.DrawRay()、緑線はDebug.DrawRay()、赤線はGLで描画を行なっています。左が、Sceneビュー、右がGameビューの表示です。
これを見るとまったく同じように見えるのですが、Gizmos、Debug、OpenGLでそれぞれ表示できるタイミングが決まっています。
●Gizmos
Gizmos.DrawRay()は、Editor画面上でGizmosが有効になっていると表示されます。Gizmosはライトやカメラなどのアイコンと同じ扱いです。
Unityエディタで常に表示されているため、使いやすい方法です。以下のスクリプトでオブジェクト座標の前方向(forward)に長さ5の線分を青色で表示させることができます。
void OnDrawGizmos()
{
Gizmos.color = Color.blue;
Gizmos.DrawRay(transform.localPosition, transform.forward * 5);
}
●Debug
Debug.DrawRay()はGizmosが有効になっているときに、Playすると表示されます。レイキャストの方向など、エディタで常に表示させる必要のない情報を確認するときに便利です。コードは以下のようになります。オブジェクト座標の上方向(up)に長さ5の線分を緑色で描いています。
Debug.DrawRay(transform.localPosition, transform.up * 5, Color.green)
●GL
GLはGizmosが無効でもPlayすると表示されます。使いどころはDebug.DrawRay()と同じでコード量も多く面倒ですが、UnityPlayerで表示できるのが最大の利点です。こんな感じのコードになります。
// ライン用のマテリアルを作成
static Material lineMaterial;
static void CreateLineMaterial()
{
if (!lineMaterial)
{
Shader shader = Shader.Find("Hidden/Internal-Colored");
lineMaterial = new Material(shader);
lineMaterial.hideFlags = HideFlags.HideAndDontSave;
lineMaterial.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
lineMaterial.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
lineMaterial.SetInt("_Cull", (int)UnityEngine.Rendering.CullMode.Off);
lineMaterial.SetInt("_ZWrite", 0);
}
}
// GLを使ってラインを描く
public void OnRenderObject()
{
var o = transform.position;
var p = o + transform.up;
CreateLineMaterial();
lineMaterial.SetPass(0);
GL.PushMatrix();
GL.Color(new Color(1, 0, 0));
GL.Begin(GL.LINES);
GL.Vertex3(o.x, o.y, o.z);
GL.Vertex3(p.x, p.y, p.z);
GL.End();
GL.PopMatrix();
}
<4>外部設定ファイル
ここでデバッグとは直接関係がない話題になりますが、展示コンテンツは、その展示場所の運営スタッフにパラメータを編集してもらう余地を残すことが多くあります。Unityで直接扱えるのはJSON形式ですが、展示用コンテンツでよく使われるのは昔ながらのiniファイル形式です。iniファイルを使う利点は理解が簡単なことと、使い慣れたメモ帳で編集できることに尽きます。タイムアウトの秒数や画像ファイルのパスなどの情報を保持するためにJSONを使うと、コンピュータの操作に詳しい人が少ない運営スタッフに説明する手間が大きくなってしまいます。
例えば、以下のようなJSONの記述があるとします。待機画面に戻る秒数を90秒、センサの最大値、最小値をそれぞれ1と100にしてあります。
{
"Timeout": 90,
"Sensor" : [1, 100]
}
このようなシンプルな記述でも、JSONを知らない人に説明するのは少し大変です。90の次のカンマを消してしまってデータが読み込まれなくなっても原因が分からず、動かなくなってしまうといったことがあるからです。さらにJSONはコメントアウトするのが面倒です。
iniであれば以下のように書けます。プログラムに慣れていない人でも簡単に理解ができると思います。
iniファイルでの記述例
; タイムアウト秒数
Timeout=90
; センサーの最大、最小値
Sensor_min=1
Sensor_max=100
ただ、iniは構造化することができずパラメータの記述が冗長になりがちなので、筆者は「TOML」という言語を使うようにしています。
TOMLでの記述例
# タイムアウト秒数
Timeout = 90
# センサーの最大、最小値
Sensor = [1, 100]
基本的にはiniのように書け、JSONのように配列を使えるのが利点です。UnityでTOMLを使うためには、ここの実装をNuGetでインストールするのが簡単だと思います。Visual StudioからPackage Manager Consoleを開きます。
Consoleが開いたら、
Install-Package Nett -Version 0.13.0
と入力してインストールします。
ファイルはプロジェクトのPackageフォルダにインストールされますが、このままだとUnityエディタは認識してくれません。インストールされた、Packages¥Nett.0.13.0¥net40フォルダの名前をtomlに変更し、Assetフォルダ以下にコピーします。
前述のTOMLファイルを読み込むには、次のようにします。前述のTOMLをconfig.tomlとして保存します。config.tomlはAssetsと同じ階層にある前提です。これでTimeoutには90が、Sensorには配列として1と100が読み込まれます。
public class Param
{
public int Timeout { get; set; }
public int[] Sensor { get; set; }
}
public class TomlSample: MonoBehaviour
{
void Start()
{
var toml_file = string.Format("{0}/../config.toml", Application.dataPath);
var p = Nett.Toml.ReadFile(toml_file);
}
}
このように、できるだけ設定を外部で変更できるようにしておくとメンテナンス性が上がり、バグが入る可能性を減らすこともできます。
Profile.
高田稔則/Toshinori Takata(Codelight)Codelight株式会社 代表取締役・インタラクションエンジニア
フリーランス、株式会社TBSテレビ等で映画CG制作、株式会社ソニー・コンピュータエンタテインメント(現 ソニー・インタラクティブエンタテインメント)でPS4のOSD開発などを経て2006年にCodelight株式会社を設立。インタラクティブコンテンツの制作を中核として、製造業向けのプロトタイプ開発なども行う
www.codelight.co.jp