Files
XCEngine/参考/TransformGizmo/Scripts/SelectDetector.cs

328 lines
10 KiB
C#
Raw Normal View History

2026-03-29 01:36:53 +08:00
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Security.Cryptography;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.Rendering;
public class SelectDetector
{
//GameObject
public GameObject detectedObject;
private List<GameObject> objects;
private List<int> objectIds;
private Shader objectEncodeShader;
private Material objectEncodeMaterial;
private Dictionary<int, Material> objectEncodeMaterials;
//Gizmo
public GameObject detectedGizmo;
private List<GameObject> gizmos;
private List<int> gizmoIds;
private Shader gizmoEncodeShader;
private Material gizmoEncodeMaterial;
private Dictionary<int,Material> gizmoEncodeMaterials;
private CommandBuffer encodeCmdBuffer;
private Camera selectCamera;
private GameObject cameraObject;
private Texture2D encodeTexture2d;
private RenderTexture encodeTexture;
private bool isCursorOnPanels = false;
public void Initialize()
{
//Encode CommandBuffer Initialize
encodeCmdBuffer = new CommandBuffer();
//Object Encode Material Initialize
objectEncodeShader = Shader.Find("Custom/ObjectSelectEncode");
objectEncodeMaterial = new Material(objectEncodeShader);
objectEncodeMaterial.SetColor("_ID", IntToRGBA(-1));
//Gizmo Encode Material Initialize
gizmoEncodeShader = Shader.Find("Custom/GizmoSelectEncode");
gizmoEncodeMaterial = new Material(gizmoEncodeShader);
gizmoEncodeMaterial.SetColor("_ID", IntToRGBA(-1));
//Encode Texture Initialize
encodeTexture = new RenderTexture(Screen.width, Screen.height, 24);
encodeTexture2d = new Texture2D(1, 1, TextureFormat.ARGB32, false);
//Camera Initialize
cameraObject = new GameObject();
cameraObject.name = "SelectDetector";
cameraObject.GetComponent<Transform>().parent = GameObject.Find("Main Camera").GetComponent<Transform>();
cameraObject.GetComponent<Transform>().localPosition = Vector3.zero;
cameraObject.GetComponent<Transform>().rotation = Quaternion.identity;
selectCamera = cameraObject.AddComponent<Camera>();
selectCamera.targetTexture = encodeTexture;
selectCamera.GetComponent<Transform>().position = Camera.main.transform.position;
selectCamera.GetComponent<Transform>().rotation = Camera.main.transform.rotation;
//List Initialize
objects = new List<GameObject>();
objectIds = new List<int>();
objectEncodeMaterials = new Dictionary<int, Material>();
gizmos = new List<GameObject>();
gizmoIds = new List<int>();
gizmoEncodeMaterials = new Dictionary<int, Material>();
}
public void InitializeScene()
{
//Original GameObjects Initialize
foreach (GameObject root in UnityEngine.SceneManagement.SceneManager.GetActiveScene().GetRootGameObjects())
{
foreach (Transform child_transform in root.GetComponentsInChildren<Transform>(true))
{
GameObject child = child_transform.gameObject;
objects.Add(child);
objectIds.Add(child.GetInstanceID());
}
}
}
public void Update()
{
if (isCursorOnPanels) { return; }
//Select Camera Update
//selectCamera.GetComponent<Transform>().position = Camera.main.transform.position;
//selectCamera.GetComponent<Transform>().rotation = Camera.main.transform.rotation;
selectCamera.RemoveAllCommandBuffers();
//Encode CommandBuffer Update
encodeCmdBuffer.Clear();
encodeCmdBuffer.ClearRenderTarget(true, true, Color.white);
//Add Object Render Command
for (int i = 0; i < objects.Count; i++)
{
GameObject tmpObject = objects[i];
if (tmpObject == null) { continue; }
if (tmpObject.activeSelf == false) { continue; }
MeshRenderer tmpRenderer = tmpObject.GetComponent<MeshRenderer>();
if (tmpRenderer != null)
{
int tmpId = tmpObject.GetInstanceID();
Material tempMaterial = objectEncodeMaterials[tmpId];
encodeCmdBuffer.DrawRenderer(tmpRenderer, tempMaterial);
}
}
//Add Gizmo Render Command
for (int i = 0; i < gizmos.Count; i++)
{
GameObject tmpGizmo = gizmos[i];
MeshRenderer tmpRenderer = tmpGizmo.GetComponent<MeshRenderer>();
if (tmpRenderer != null)
{
int tmpId = tmpGizmo.GetInstanceID();
Material tmpMaterial = gizmoEncodeMaterials[tmpId];
encodeCmdBuffer.DrawRenderer(tmpRenderer, tmpMaterial);
}
}
selectCamera.AddCommandBuffer(CameraEvent.AfterEverything, encodeCmdBuffer);
//Detected Object&Gizmo Update
Vector2 input = Input.mousePosition;
int inputX = (int)input.x;
int inputY = (int)input.y;
int clampInputX = Mathf.Clamp(inputX, 0, encodeTexture.width - 1);
int clampInputY = Mathf.Clamp(inputY, 0, encodeTexture.height - 1);
RenderTexture.active = encodeTexture;
encodeTexture2d.ReadPixels(new Rect(clampInputX, clampInputY, 1, 1), 0, 0);
encodeTexture2d.Apply();
Color color = encodeTexture2d.GetPixel(0, 0);
int id = RGBAToInt(color);
detectedObject = FindObjectByID(id);
detectedGizmo = FindGizmoByID(id);
}
//Object Add&Remove&Find
public void AddObjects(GameObject root_object)
{
foreach (Transform child_transform in root_object.GetComponentsInChildren<Transform>(true))
{
GameObject child = child_transform.gameObject;
AddObject(child);
}
}
public void RemoveObjects(GameObject root_object)
{
foreach (Transform child_transform in root_object.GetComponentsInChildren<Transform>(true))
{
GameObject child = child_transform.gameObject;
RemoveObject(child);
}
}
public void AddObjects(List<GameObject> objects)
{
foreach(GameObject obj in objects)
{
AddObject(obj);
}
}
public void RemoveObjects(List<GameObject> objects)
{
foreach(GameObject obj in objects)
{
RemoveObject(obj);
}
}
public void AddObject(GameObject p_object)
{
if(p_object == null) { return; }
objects.Add(p_object);
int id = p_object.GetInstanceID();
objectIds.Add(id);
//Encode Material
Material encodeMaterial = new Material(objectEncodeMaterial);
encodeMaterial.SetColor("_ID", IntToRGBA(id));
objectEncodeMaterials.Add(id, encodeMaterial);
}
public void RemoveObject(GameObject p_object)
{
if (p_object == null) { return; }
if (!objects.Contains(p_object)) { return; }
objects.Remove(p_object);
int id = p_object.GetInstanceID();
objectIds.Remove(id);
objectEncodeMaterials.Remove(id);
}
private GameObject FindObjectByID(int id)
{
for (int i = 0; i < objects.Count; i++)
{
if (objectIds[i] == id)
{
return objects[i];
}
}
return null;
}
//Gizmo Add&Remove&Find
public void AddGizmos(GameObject root_object)
{
foreach (Transform child_transform in root_object.GetComponentsInChildren<Transform>(true))
{
GameObject child = child_transform.gameObject;
AddGizmo(child);
}
}
public void RemoveGizmos(GameObject root_object)
{
foreach (Transform child_transform in root_object.GetComponentsInChildren<Transform>(true))
{
GameObject child = child_transform.gameObject;
RemoveGizmo(child);
}
}
public void AddGizmos(List<GameObject> objects)
{
foreach(GameObject gameObject in objects)
{
AddGizmo(gameObject);
}
}
public void RemoveGizmos(List<GameObject> objects)
{
foreach(GameObject gameObject in objects)
{
RemoveGizmo(gameObject);
}
}
public void AddGizmo(GameObject p_gizmo)
{
if (p_gizmo == null) { return; }
gizmos.Add(p_gizmo);
int id = p_gizmo.GetInstanceID();
gizmoIds.Add(id);
//Encode Material
Material encodeMaterial = new Material(gizmoEncodeMaterial);
encodeMaterial.SetColor("_ID", IntToRGBA(id));
gizmoEncodeMaterials.Add(id, encodeMaterial);
}
public void RemoveGizmo(GameObject p_gizmo)
{
if (p_gizmo == null) { return; }
if (!gizmos.Contains(p_gizmo)) { return; }
gizmos.Remove(p_gizmo);
int id = p_gizmo.GetInstanceID();
gizmoIds.Remove(id);
gizmoEncodeMaterials.Remove(id);
}
private GameObject FindGizmoByID(int id)
{
for (int i = 0; i < gizmos.Count; i++)
{
if (gizmoIds[i] == id)
{
return gizmos[i];
}
}
return null;
}
//Tool
private Color IntToRGBA(int value)
{
byte red = (byte)((value >> 24) & 0xFF);
byte green = (byte)((value >> 16) & 0xFF);
byte blue = (byte)((value >> 8) & 0xFF);
byte alpha = (byte)(value & 0xFF);
return new Color32(red, green, blue, alpha);
}
private int RGBAToInt(Color32 color)
{
int result = (color.r << 24) |
(color.g << 16) |
(color.b << 8) |
color.a;
return result;
}
private int RGBAToInt(Color color)
{
Color32 color32 = new Color32((byte)(color.r * 255),
(byte)(color.g * 255),
(byte)(color.b * 255),
(byte)(color.a * 255));
return RGBAToInt(color32);
}
}