Decal Projectorを簡単に配置するエディタウィンドウを作ってみました。
概要
シーンビューを左クリックして、コライダーの面にDecal Projectorのプレハブを配置します。配置した後にドラッグするとインスタンスを移動できます。
アスペクト比を保ったスケーリングやランダムの回転もできるようにします。
プレハブ
Decal Projectorゲームオブジェクトを作って、マテリアルを設定します。
テクスチャ画像のアスペクト比が保たれるように、Decal Projectorコンポーネントでサイズを設定しています。
プレハブ化します。
スクリプト
EditorフォルダにC#スクリプトを作成します。
using UnityEngine;
using UnityEngine.Rendering.HighDefinition;
using UnityEditor;
public class DecalProjectorPlacer : EditorWindow
{
DecalProjector decalProjectorPrefab;
GameObject currentPrefabInstance;
Vector2 scaleMinMax = new Vector2(1f, 2f);
float fixedRotationAngle;
float randomRotationAngle;
private bool placingPrefab = false;
float distance;
bool applyRandomRotation;
[MenuItem("Window/Test/Decal Projector Placer")]
public static void ShowWindow()
{
GetWindow<DecalProjectorPlacer>("Decal Projector Placer");
}
private void OnEnable()
{
SceneView.duringSceneGui += OnSceneGUI;
}
void OnDisable()
{
SceneView.duringSceneGui -= OnSceneGUI;
}
void OnGUI()
{
EditorGUILayout.BeginVertical();
// 各フィールドを表示
decalProjectorPrefab = (DecalProjector)EditorGUILayout.ObjectField("Prefab ", decalProjectorPrefab, typeof(DecalProjector), false);
distance = EditorGUILayout.FloatField("Projection Distance", distance);
scaleMinMax = EditorGUILayout.Vector2Field("Scale Range (Min to Max) ", scaleMinMax, null);
applyRandomRotation = EditorGUILayout.Toggle("Apply Random Rotation ", applyRandomRotation);
fixedRotationAngle = EditorGUILayout.FloatField("Fixed Rotation Angle ", fixedRotationAngle);
// ボタンを表示
if (GUILayout.Button(placingPrefab ? "Stop Placing Decal Projector" : "Start Placing Decal Projector"))
{
if (!placingPrefab)
{
placingPrefab = true;
}
else
{
placingPrefab = false;
if (currentPrefabInstance != null)
{
currentPrefabInstance = null;
}
}
}
EditorGUILayout.EndVertical();
}
void OnInspectorUpdate()
{
Repaint();
}
void OnSceneGUI(SceneView sceneView)
{
if (placingPrefab)
{
HandleUtility.AddDefaultControl(GUIUtility.GetControlID(FocusType.Passive));
// 左クリックしたとき
if (Event.current.type == EventType.MouseDown && Event.current.button == 0)
{
Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
RaycastHit hit;
// レイを投げる
if (Physics.Raycast(ray, out hit))
{
// プレハブを配置
currentPrefabInstance = PrefabUtility.InstantiatePrefab(decalProjectorPrefab.gameObject) as GameObject;
Undo.RegisterCreatedObjectUndo(currentPrefabInstance, "create " + currentPrefabInstance.name);
if (currentPrefabInstance != null)
{
// 位置を設定
currentPrefabInstance.transform.position = hit.point + hit.normal * distance;
// 回転を設定
randomRotationAngle = Random.Range(0, 360f);
currentPrefabInstance.transform.rotation = CalculateDecalRotation(hit.normal);
var decalProjector = currentPrefabInstance.GetComponent<DecalProjector>();
// 元のサイズを取得
Vector3 originalSize = decalProjector.size;
// ランダムなスケールファクターを生成
float scaleFactor = Random.Range(scaleMinMax.x, scaleMinMax.y);
// 新しいサイズを設定(アスペクト比を保持)
decalProjector.size = new Vector3(originalSize.x * scaleFactor, originalSize.y * scaleFactor, originalSize.z);
}
}
Event.current.Use();
}
// ドラッグ
else if (Event.current.type == EventType.MouseDrag && Event.current.button == 0)
{
Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
RaycastHit hit;
// レイを投げる
if (Physics.Raycast(ray, out hit))
{
// 位置と回転を設定
currentPrefabInstance.transform.position = hit.point + hit.normal * distance;
currentPrefabInstance.transform.rotation = CalculateDecalRotation(hit.normal);
}
Event.current.Use();
}
}
}
Quaternion CalculateDecalRotation(Vector3 hitNormal)
{
// デカールプロジェクタのデフォルトの姿勢
Quaternion rot = Quaternion.Euler(90, 0, 0);
// デカールの絵を回転する
rot = Quaternion.AngleAxis(applyRandomRotation ? randomRotationAngle : fixedRotationAngle, Vector3.up) * rot;
// 法線とワールド上向きの外積から、デカールが向くべき右方向を計算する
Vector3 toRight = Vector3.Cross(hitNormal, Vector3.up);
Quaternion rightRotation = Quaternion.FromToRotation(Vector3.right, toRight);
// 面の法線がワールド上を向くようにデカールプロジェクタを回転する
Quaternion normalRotation = Quaternion.FromToRotation(Vector3.up, hitNormal);
// 全ての回転を組み合わせる
return normalRotation * rightRotation * rot;
}
}
使い方
メインメニューからエディタウィンドウを開けます。フィールドにDecal Projectorのプレハブをドラッグアンドドラップします。配置する面からの距離やスケール、角度などを設定できます。
ボタンを押すと、シーンビューで左クリックした位置にプレハブを配置できるようになります。他のゲームオブジェクトは操作できなくなります。
ドラッグで移動できます。面に合わせて自動でDecal Projectorの向きを変えます。
スケールと回転をランダムに設定できます。
ボタンをもう一度押すと終了し、通常の操作に戻ります。
これで、簡単にDecal Projectorを配置できました。