エディタ拡張でDecal Projectorを簡単に配置するツールを作るのスクリプトを修正して、アイコンでプレハブを選択できるようにしてみました。
テクスチャのアスペクト比やタイリング、オフセットを適用して、ボタン上にテクスチャを表示します。
元のテクスチャには、複数の画像がまとめられたものがあります。アスペクト比にも違いがあります。
デカールを配置
画像をクリックすると、配置するDecalProjectorプレハブが切り替わります。
DecalProjectorのタイリングやオフセットを変更すると、画像の表示も変わります。
ScriptableObject
DecalProjectorのプレハブやスケール角度などのデータを保存するScriptableObjectを作りました。
このデータのリストを持つScriptableObjectも用意し、エディタウィンドウにアタッチします。
スクリプト
EditorWindowのOnGUIメソッドで、フィールドやボタンなどを表示します。まずDecalProjectorのリストを持つScriptableObjectをアタッチするフィールドを表示しています。
// public class DecalProjectorPlacer : EditorWindow
void OnGUI()
{
// フィールドを表示
decalProjectorCollection = (DecalProjectorCollection)EditorGUILayout.ObjectField("Collection ", decalProjectorCollection, typeof(DecalProjectorCollection), false);
アタッチされている場合、リスト内のデータを一つずつ処理します。
if (decalProjectorCollection != null)
{
using (var horizontalScope = new EditorGUILayout.HorizontalScope("box"))
{
for (int i = 0; i < decalProjectorCollection.List.Count; i++)
{
var data = decalProjectorCollection.List[i];
AssetPreview.GetMiniThumbnailメソッドで、オブジェクトのサムネイルを取得できます。プレハブのDecalProjectorコンポーネントに設定されているマテリアルのメインテクスチャを渡しています。
var previewImage = AssetPreview.GetMiniThumbnail(data.Prefab.material.mainTexture);
ボタンを表示します。ボタンを押すとインデックスが保存されます。
if (GUILayout.Button("", GUILayout.Width(60), GUILayout.Height(60)))
{
// ボタンがクリックされたらインデックスを更新
index = i;
}
GUILayoutUtility.GetLastRectメソッドでボタンのRectを取得します。
var rect = GUILayoutUtility.GetLastRect();
選択されている場合はボタンのRectを使ってハイライトします。
if (i == index)
{
var color = Color.black;
color.a = 0.2f;
EditorGUI.DrawRect(rect, color);
}
DecalProjectorのプレハブから、オフセットとタイリングを取得します。
if (previewImage == null) continue;
// プレハブからタイリングとオフセットを取得
var offset = data.Prefab.uvBias;
var tiling = data.Prefab.uvScale;
サムネイルのテクスチャサイズにタイリングをかけます。
var scaledTextureWidth = previewImage.width * tiling.x;
var scaledTextureHeight = previewImage.height * tiling.y;
アスペクト比を計算します。
var aspectRatio = (float)scaledTextureWidth / (float)scaledTextureHeight;
サムネイルの幅をRectの幅に合わせた場合の、アスペクト比を適用した高さを計算します。
float adjustedHeight = rect.width / aspectRatio;
求めた高さがRect高さを上回る場合は、サムネイル高さをRect高さに合わせて、サムネイルの幅を短くします。
if (adjustedHeight > rect.height)
{
// 縦に収まらない場合、幅を調整
var adjustedWidth = rect.height * aspectRatio;
rect.x += (rect.width - adjustedWidth) / 2f;
rect.width = adjustedWidth;
}
サムネイルをセンタリングするために、Rectの幅から縮小した幅を引いて余白を求め、その半分だけRectを横方向に移動しています。
rect.x += (rect.width - adjustedWidth) / 2f;
調整した高さがRectに収まる場合は、上下中央揃えとRect高さの調整をします。
else
{
// 縦に収まる場合、高さを調整
rect.y += (rect.height - adjustedHeight) / 2f;
rect.height = adjustedHeight;
}
GUI.DrawTextureWithTexCoordsメソッドでRectにテクスチャを描画します。タイリングとクリッピングができます。
GUI.DrawTextureWithTexCoords(rect, previewImage, new Rect(offset, tiling));
}
}
}
ボタンの下には、選択されたDecalProjectorのデータが表示されます。
var data = decalProjectorCollection.List[index];
EditorGUI.BeginChangeCheck();
EditorGUILayout.ObjectField(data.Prefab.name, data.Prefab,typeof(DecalProjector),false);
// ...
これでエディタウィンドウにアイコンを表示して、DecalProjectorを簡単に切り替えられました。
参考:https://docs.unity3d.com/ja/2019.4/ScriptReference/AssetPreview.GetMiniThumbnail.html
https://docs.unity3d.com/ScriptReference/AssetPreview.html
https://docs.unity3d.com/ja/2021.1/ScriptReference/GUILayoutUtility.GetLastRect.html
https://docs.unity3d.com/ja/2019.4/ScriptReference/Rect.html
https://docs.unity3d.com/ja/2019.4/ScriptReference/GUI.DrawTextureWithTexCoords.html