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

337 lines
15 KiB
C#
Raw Normal View History

2026-03-29 01:36:53 +08:00
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RuntimeTranslateGizmo : RuntimeTransformGizmo
{
private string prefabPath = "Prefabs/TranslateGizmo";
private GameObject translateX;
private GameObject translateY;
private GameObject translateZ;
private GameObject translatePlaneX;
private GameObject translatePlaneY;
private GameObject translatePlaneZ;
private float translatePlaneOffset = 0.15f;
private Vector3 screenCenterPosition;
enum TranslateSelectState { X, Y, Z, PlaneX, PlaneY, PlaneZ, UnSelected }
TranslateSelectState translateSelectState;
private float XYZOffsetOnSelect;
private Vector2 gizmoPlaneOffset;
private Vector3 lastTargetPosition;
public override void Initialize()
{
//Base Initialize
base.Initialize();
//Material Initialize
redMaterial = Resources.Load<Material>("Materials/Red");
greenMaterial = Resources.Load<Material>("Materials/Green");
blueMaterial = Resources.Load<Material>("Materials/Blue");
//Prefab Initialize
prefab = Resources.Load<GameObject>(prefabPath);
if (prefab != null)
{
gizmo = Object.Instantiate(prefab) as GameObject;
}
HideBeindCamera();
//Component Initialize
translateX = gizmo.GetComponent<Transform>().Find("TranslateX").gameObject;
translateY = gizmo.GetComponent<Transform>().Find("TranslateY").gameObject;
translateZ = gizmo.GetComponent<Transform>().Find("TranslateZ").gameObject;
translatePlaneX = gizmo.GetComponent<Transform>().Find("TranslatePlaneX").gameObject;
translatePlaneY = gizmo.GetComponent<Transform>().Find("TranslatePlaneY").gameObject;
translatePlaneZ = gizmo.GetComponent<Transform>().Find("TranslatePlaneZ").gameObject;
//Other Initialzie
translateSelectState = TranslateSelectState.UnSelected;
screenCenterPosition = new Vector3(Screen.width * 0.5f, Screen.height * 0.5f, 0);
scaleRate = 6.0f;
handleNames = new List<string> { "TranslateX", "TranslateY", "TranslateZ", "TranslatePlaneX", "TranslatePlaneY", "TranslatePlaneZ" };
}
public override void Update()
{
//hide
if (enabled && target)
{
//Render Update
RenderUpdate();
//Follow Update
FollowUpdate();
//Interaction Update
if (translateSelectState != TranslateSelectState.UnSelected)
{
OnSelecting();
}
}
else
{
HideBeindCamera();
}
}
protected override void RenderUpdate()
{
//Base Update
base.RenderUpdate();
gizmo.GetComponent<Transform>().localScale /= scaleRate;
//Translate Plane Update
Vector3 viewPosition = Camera.main.ScreenToWorldPoint(screenCenterPosition);
Vector3 viewDirection = viewPosition - gizmo.GetComponent<Transform>().position;
Vector3 viewLocalDirection = gizmo.GetComponent<Transform>().worldToLocalMatrix.MultiplyVector(viewDirection);
int directionX = viewLocalDirection.x > 0 ? 1 : -1;
int directionY = viewLocalDirection.y > 0 ? 1 : -1;
int directionZ = viewLocalDirection.z > 0 ? 1 : -1;
translatePlaneX.GetComponent<Transform>().localPosition = Vector3.zero;
translatePlaneX.GetComponent<Transform>().localPosition += directionY * Vector3.up * translatePlaneOffset;
translatePlaneX.GetComponent<Transform>().localPosition += directionZ * Vector3.forward * translatePlaneOffset;
translatePlaneY.GetComponent<Transform>().localPosition = Vector3.zero;
translatePlaneY.GetComponent<Transform>().localPosition += directionX * Vector3.right * translatePlaneOffset;
translatePlaneY.GetComponent<Transform>().localPosition += directionZ * Vector3.forward * translatePlaneOffset;
translatePlaneZ.GetComponent<Transform>().localPosition = Vector3.zero;
translatePlaneZ.GetComponent<Transform>().localPosition += directionX * Vector3.right * translatePlaneOffset;
translatePlaneZ.GetComponent<Transform>().localPosition += directionY * Vector3.up * translatePlaneOffset;
}
protected override void FollowUpdate()
{
if (target == null) { return; }
//Rotation Follow
Vector3 targetPosition = target.GetComponent<Transform>().position;
if (targetPosition != lastTargetPosition)
{
gizmo.GetComponent<Transform>().position = targetPosition;
}
else
{
target.GetComponent<Transform>().position = gizmo.GetComponent<Transform>().position;
}
lastTargetPosition = targetPosition;
//Rotation Follow
gizmo.GetComponent<Transform>().rotation = target.GetComponent<Transform>().rotation;
}
public override void EnableGizmo(GameObject target)
{
base.EnableGizmo(target);
lastTargetPosition = target.GetComponent<Transform>().position;
}
public override void OnSelect(string handleName)
{
if (!handleNames.Contains(handleName)) { return; }
Vector3 gizmoPosition = gizmo.GetComponent<Transform>().position;
Vector2 mousePositionOnSelect = Input.mousePosition;
gizmoXYZScreenStart = Camera.main.WorldToScreenPoint(gizmoPosition);
if (!handleName.Contains("Plane"))
{
Vector3 gizmoEndPosition = new Vector3();
switch (handleName)
{
case "TranslateX":
translateSelectState = TranslateSelectState.X;
gizmoEndPosition = gizmoPosition + 10 * gizmo.GetComponent<Transform>().right;
break;
case "TranslateY":
translateSelectState = TranslateSelectState.Y;
gizmoEndPosition = gizmoPosition + 10 * gizmo.GetComponent<Transform>().up;
break;
case "TranslateZ":
translateSelectState = TranslateSelectState.Z;
gizmoEndPosition = gizmoPosition + 10 * gizmo.GetComponent<Transform>().forward;
break;
}
Vector2 gizmoXYZScreenEnd = Camera.main.WorldToScreenPoint(gizmoEndPosition);
gizmoXYZScreenDirection = (gizmoXYZScreenEnd - gizmoXYZScreenStart).normalized;
XYZOffsetOnSelect = Vector2.Dot(mousePositionOnSelect - gizmoXYZScreenStart, gizmoXYZScreenDirection);
}
else
{
switch (handleName)
{
case "TranslatePlaneX":
translateSelectState = TranslateSelectState.PlaneX;
break;
case "TranslatePlaneY":
translateSelectState = TranslateSelectState.PlaneY;
break;
case "TranslatePlaneZ":
translateSelectState = TranslateSelectState.PlaneZ;
break;
}
gizmoPlaneOffset = new Vector2(mousePositionOnSelect.x - gizmoXYZScreenStart.x, mousePositionOnSelect.y - gizmoXYZScreenStart.y);
}
ChangeRenderOnSelect();
}
public override void OnUnSelect()
{
if (translateSelectState == TranslateSelectState.UnSelected) { return; }
translateSelectState = TranslateSelectState.UnSelected;
//Render
ChangeRenderOnUnSelect();
}
protected override void OnSelecting()
{
Vector2 mousePosition = Input.mousePosition;
Vector3 targetPosition = new Vector3();
Vector3 gizmoPosition = gizmo.GetComponent<Transform>().position;
Vector3 viewPosition = Camera.main.ScreenToWorldPoint(screenCenterPosition);
//Translate XYZ Axis
if (translateSelectState <= TranslateSelectState.Z)
{
float dragDistance = Vector2.Dot(mousePosition - gizmoXYZScreenStart, gizmoXYZScreenDirection) - XYZOffsetOnSelect;
Vector2 dragScreenPosition = gizmoXYZScreenStart + gizmoXYZScreenDirection * dragDistance;
Vector3 dragRayDirection = Camera.main.ScreenPointToRay(dragScreenPosition).direction;
switch (translateSelectState)
{
case TranslateSelectState.X:
Vector3? intersectionXY = GetIntersectionPlaneAndLine(Axis.Y, viewPosition, dragRayDirection);
Vector3? intersectionXZ = GetIntersectionPlaneAndLine(Axis.Z, viewPosition, dragRayDirection);
targetPosition = GetMediaPoint(intersectionXY, intersectionXZ).Value;
gizmo.GetComponent<Transform>().position = targetPosition;
break;
case TranslateSelectState.Y:
Vector3? intersectionYX = GetIntersectionPlaneAndLine(Axis.X, viewPosition, dragRayDirection);
Vector3? intersectionYZ = GetIntersectionPlaneAndLine(Axis.Z, viewPosition, dragRayDirection);
targetPosition = GetMediaPoint(intersectionYX, intersectionYZ).Value;
gizmo.GetComponent<Transform>().position = targetPosition;
break;
case TranslateSelectState.Z:
Vector3? intersectionZX = GetIntersectionPlaneAndLine(Axis.X, viewPosition, dragRayDirection);
Vector3? intersectionZY = GetIntersectionPlaneAndLine(Axis.Y, viewPosition, dragRayDirection);
targetPosition = GetMediaPoint(intersectionZX, intersectionZY).Value;
gizmo.GetComponent<Transform>().position = targetPosition;
break;
}
}
//Translate XYZ Plane
else
{
Vector2 dragScreenPosition = mousePosition - gizmoPlaneOffset;
Vector3 dragRayDirection = Camera.main.ScreenPointToRay(dragScreenPosition).direction;
switch (translateSelectState)
{
case TranslateSelectState.PlaneX:
targetPosition = GetIntersectionPlaneAndLine(Axis.X, viewPosition, dragRayDirection).Value;
gizmo.GetComponent<Transform>().position = targetPosition;
break;
case TranslateSelectState.PlaneY:
targetPosition = GetIntersectionPlaneAndLine(Axis.Y, viewPosition, dragRayDirection).Value;
gizmo.GetComponent<Transform>().position = targetPosition;
break;
case TranslateSelectState.PlaneZ:
targetPosition = GetIntersectionPlaneAndLine(Axis.Z, viewPosition, dragRayDirection).Value;
gizmo.GetComponent<Transform>().position = targetPosition;
break;
}
}
}
protected override void ChangeRenderOnSelect()
{
switch(translateSelectState)
{
case TranslateSelectState.X:
translateX.GetComponent<MeshRenderer>().material = yellowMaterial;
translateY.GetComponent<MeshRenderer>().material = whiteMaterial;
translateZ.GetComponent<MeshRenderer>().material = whiteMaterial;
translatePlaneX.SetActive(false);
translatePlaneY.SetActive(false);
translatePlaneZ.SetActive(false);
break;
case TranslateSelectState.Y:
translateX.GetComponent<MeshRenderer>().material = whiteMaterial;
translateY.GetComponent<MeshRenderer>().material = yellowMaterial;
translateZ.GetComponent<MeshRenderer>().material = whiteMaterial;
translatePlaneX.SetActive(false);
translatePlaneY.SetActive(false);
translatePlaneZ.SetActive(false);
break;
case TranslateSelectState.Z:
translateX.GetComponent<MeshRenderer>().material = whiteMaterial;
translateY.GetComponent<MeshRenderer>().material = whiteMaterial;
translateZ.GetComponent<MeshRenderer>().material = yellowMaterial;
translatePlaneX.SetActive(false);
translatePlaneY.SetActive(false);
translatePlaneZ.SetActive(false);
break;
case TranslateSelectState.PlaneX:
translateX.GetComponent<MeshRenderer>().material = whiteMaterial;
translateY.GetComponent<MeshRenderer>().material = yellowMaterial;
translateZ.GetComponent<MeshRenderer>().material = yellowMaterial;
translatePlaneX.GetComponent<MeshRenderer>().material = yellowMaterial;
translatePlaneY.SetActive(false);
translatePlaneZ.SetActive(false);
break;
case TranslateSelectState.PlaneY:
translateX.GetComponent<MeshRenderer>().material = yellowMaterial;
translateY.GetComponent<MeshRenderer>().material = whiteMaterial;
translateZ.GetComponent<MeshRenderer>().material = yellowMaterial;
translatePlaneX.SetActive(false);
translatePlaneY.GetComponent<MeshRenderer>().material = yellowMaterial;
translatePlaneZ.SetActive(false);
break;
case TranslateSelectState.PlaneZ:
translateX.GetComponent<MeshRenderer>().material = yellowMaterial;
translateY.GetComponent<MeshRenderer>().material = yellowMaterial;
translateZ.GetComponent<MeshRenderer>().material = whiteMaterial;
translatePlaneX.SetActive(false);
translatePlaneY.SetActive(false);
translatePlaneZ.GetComponent<MeshRenderer>().material = yellowMaterial;
break;
}
}
protected override void ChangeRenderOnUnSelect()
{
translateX.SetActive(true);
translateY.SetActive(true);
translateZ.SetActive(true);
translatePlaneX.SetActive(true);
translatePlaneY.SetActive(true);
translatePlaneZ.SetActive(true);
translateX.GetComponent<MeshRenderer>().material = redMaterial;
translateY.GetComponent<MeshRenderer>().material = greenMaterial;
translateZ.GetComponent<MeshRenderer>().material = blueMaterial;
translatePlaneX.GetComponent<MeshRenderer>().material = redMaterial;
translatePlaneY.GetComponent<MeshRenderer>().material = greenMaterial;
translatePlaneZ.GetComponent<MeshRenderer>().material = blueMaterial;
}
private Vector3? GetMediaPoint(Vector3? point1, Vector3? point2)
{
if (point1 != null && point2 != null)
{
return (point1 + point2) / 2;
}
else if (point1 != null && point2 == null)
{
return point1;
}
else if (point2 != null && point1 == null)
{
return point2;
}
return null;
}
}