using System.Collections; using System.Collections.Generic; using TMPro; using UnityEngine; using UnityEngine.UIElements; public class RuntimeRotateGizmo : RuntimeTransformGizmo { private string prefabPath = "Prefabs/RotateGizmo"; private GameObject rotatePlane; private GameObject rotatePlaneHandle; private GameObject rotateXYZ; private GameObject rotateX; private GameObject rotateY; private GameObject rotateZ; private GameObject rotateSphere; enum RotateSelectState { X, Y, Z, Plane, Sphere, UnSelected } RotateSelectState rotateSelectState; //Offset private float XYZOffsetOnSelect; private Vector2 sphereOffsetOnSelect; //Rate private float XYZRotateRate = 0.1f; private float planeRotateRate = 0.1f; private float sphereRotateRate = 0.1f; private Quaternion rotationOnSelect; private Vector3 viewLocalDirectionX; private Vector3 viewLocalDirectionY; private Vector3 viewLocalDirectionZ; private Quaternion lastTargetRotation; public override void Initialize() { //Base Initialize base.Initialize(); //Material Initialize redMaterial = Resources.Load("Materials/RotateRed"); greenMaterial = Resources.Load("Materials/RotateGreen"); blueMaterial = Resources.Load("Materials/RotateBlue"); ////Prefab Initialize prefab = Resources.Load(prefabPath); if (prefab != null) { gizmo = Object.Instantiate(prefab) as GameObject; } HideBeindCamera(); //Component Initialize rotatePlane = gizmo.GetComponent().Find("RotatePlane").gameObject; rotatePlaneHandle = rotatePlane.GetComponent().Find("RotatePlaneHandle").gameObject; rotateXYZ = gizmo.GetComponent().Find("RotateXYZ").gameObject; rotateX = rotateXYZ.GetComponent().Find("RotateX").gameObject; rotateY = rotateXYZ.GetComponent().Find("RotateY").gameObject; rotateZ = rotateXYZ.GetComponent().Find("RotateZ").gameObject; rotateSphere = gizmo.GetComponent().Find("RotateSphere").gameObject; //Other Initialzie rotateSelectState = RotateSelectState.UnSelected; rotateSphere.GetComponent().material.SetFloat("_AlphaScale", 0.2f); scaleRate = 160.0f; handleNames = new List { "RotatePlaneHandle", "RotatePlaneDetect", "RotateXDetect", "RotateX", "RotateYDetect", "RotateY", "RotateZDetect", "RotateZ", "RotateSphere" }; } public override void Update() { //hide if(enabled) { //Render Update RenderUpdate(); //Follow Update FollowUpdate(); //Interaction Update if (rotateSelectState != RotateSelectState.UnSelected) { OnSelecting(); } } else { HideBeindCamera(); } } protected override void RenderUpdate() { //Base Update base.RenderUpdate(); gizmo.GetComponent().localScale /= scaleRate; //Rotate Plane Update Vector3 viewDirection = -Camera.main.transform.forward; Quaternion rotatePlaneRotation = Quaternion.LookRotation(viewDirection, Vector3.up); rotatePlane.GetComponent().rotation = rotatePlaneRotation; //Clip Plane Update Vector3 normalizedNormal = viewDirection.normalized; Vector3 targetPosition = gizmo.GetComponent().position; float D = -Vector3.Dot(targetPosition, normalizedNormal); Vector4 clipPlane = new Vector4(normalizedNormal.x, normalizedNormal.y, normalizedNormal.z, D); redMaterial.SetVector("_ClipPlane", clipPlane); greenMaterial.SetVector("_ClipPlane", clipPlane); blueMaterial.SetVector("_ClipPlane", clipPlane); } public override void EnableGizmo(GameObject target) { base.EnableGizmo(target); lastTargetRotation = target.GetComponent().rotation; } protected override void FollowUpdate() { if (target == null) { return; } //Position Follow gizmo.GetComponent().position = target.GetComponent().position; target.GetComponent().rotation = gizmo.GetComponent().rotation; //Rotation Follow Quaternion targetRotation = target.GetComponent().rotation; if (targetRotation != lastTargetRotation) { gizmo.GetComponent().rotation = targetRotation; } else { target.GetComponent().rotation = gizmo.GetComponent().rotation; } lastTargetRotation = targetRotation; } public override void OnSelect(string handleName) { if (!handleNames.Contains(handleName)) { return; } rotationOnSelect = gizmo.GetComponent().rotation; Vector3 gizmoPosition = gizmo.GetComponent().position; Vector2 mousePositionOnSelect = Input.mousePosition; gizmoXYZScreenStart = Camera.main.WorldToScreenPoint(gizmoPosition); if (handleName.Contains("X") || handleName.Contains("Y") || handleName.Contains("Z")) //RotateX RotateY RotateZ { Vector3 gizmoEndPosition = new Vector3(); switch (handleName) { case "RotateX": case "RotateXDetect": rotateSelectState = RotateSelectState.X; gizmoEndPosition = gizmoPosition + gizmo.GetComponent().right; break; case "RotateY": case "RotateYDetect": rotateSelectState = RotateSelectState.Y; gizmoEndPosition = gizmoPosition + gizmo.GetComponent().up; break; case "RotateZ": case "RotateZDetect": rotateSelectState = RotateSelectState.Z; gizmoEndPosition = gizmoPosition + gizmo.GetComponent().forward; break; } Vector2 gizmoXYZScreenEnd = Camera.main.WorldToScreenPoint(gizmoEndPosition); gizmoXYZScreenDirection = (gizmoXYZScreenEnd - gizmoXYZScreenStart).normalized; Vector2 gizmoXYZXcreenVerticalDirection = new Vector2(gizmoXYZScreenDirection.y, -gizmoXYZScreenDirection.x); Vector2 mouseVector = mousePositionOnSelect - gizmoXYZScreenStart; XYZOffsetOnSelect = Vector2.Dot(mouseVector, gizmoXYZXcreenVerticalDirection); } else if (handleName == "RotatePlaneDetect" || handleName == "RotatePlaneHandle") { rotateSelectState = RotateSelectState.Plane; gizmoXYZScreenDirection = (mousePositionOnSelect - gizmoXYZScreenStart).normalized; XYZOffsetOnSelect = 0.0f; Vector3 viewDirectionZ = Camera.main.transform.forward; viewLocalDirectionZ = (gizmo.GetComponent().worldToLocalMatrix * viewDirectionZ).normalized; } else if(handleName == "RotateSphere") { rotateSelectState = RotateSelectState.Sphere; sphereOffsetOnSelect = mousePositionOnSelect - gizmoXYZScreenStart; Vector3 viewDirectionX = Camera.main.transform.right; viewLocalDirectionX = (gizmo.GetComponent().worldToLocalMatrix * viewDirectionX).normalized; Vector3 viewDirectionY = Camera.main.transform.up; viewLocalDirectionY = (gizmo.GetComponent().worldToLocalMatrix * viewDirectionY).normalized; } ChangeRenderOnSelect(); } public override void OnUnSelect() { if (rotateSelectState == RotateSelectState.UnSelected) { return; } rotateSelectState = RotateSelectState.UnSelected; //Render ChangeRenderOnUnSelect(); } protected override void OnSelecting() { Vector3 gizmoPosition = gizmo.GetComponent().position; Vector2 mousePosition = Input.mousePosition; Vector2 mouseVector = mousePosition - gizmoXYZScreenStart; if (rotateSelectState <= RotateSelectState.Plane) { //Rotate 90 degrees clockwise Vector2 gizmoXYZScreenVerticalDirection = new Vector2(gizmoXYZScreenDirection.y, -gizmoXYZScreenDirection.x); float dragDistance = Vector2.Dot(mouseVector, gizmoXYZScreenVerticalDirection) - XYZOffsetOnSelect; switch (rotateSelectState) { case RotateSelectState.X: gizmo.GetComponent().rotation = rotationOnSelect * Quaternion.Euler(-Vector3.right * dragDistance * XYZRotateRate); break; case RotateSelectState.Y: gizmo.GetComponent().rotation = rotationOnSelect * Quaternion.Euler(-Vector3.up * dragDistance * XYZRotateRate); break; case RotateSelectState.Z: gizmo.GetComponent().rotation = rotationOnSelect * Quaternion.Euler(-Vector3.forward * dragDistance * XYZRotateRate); break; case RotateSelectState.Plane: gizmo.GetComponent().rotation = rotationOnSelect * Quaternion.Euler(-viewLocalDirectionZ * dragDistance * planeRotateRate); break; } } else if (rotateSelectState == RotateSelectState.Sphere) { Vector2 dragVector = mouseVector - sphereOffsetOnSelect; gizmo.GetComponent().rotation = rotationOnSelect * Quaternion.Euler(-viewLocalDirectionY * dragVector.x * sphereRotateRate); gizmo.GetComponent().rotation = gizmo.transform.rotation * Quaternion.Euler(viewLocalDirectionX * dragVector.y * sphereRotateRate); } } protected override void ChangeRenderOnSelect() { switch (rotateSelectState) { case RotateSelectState.X: rotatePlaneHandle.SetActive(false); rotateX.GetComponent().material = yellowMaterial; break; case RotateSelectState.Y: rotatePlaneHandle.SetActive(false); rotateY.GetComponent().material = yellowMaterial; break; case RotateSelectState.Z: rotatePlaneHandle.SetActive(false); rotateZ.GetComponent().material = yellowMaterial; break; case RotateSelectState.Plane: rotateX.GetComponent().material = whiteMaterial; rotateY.GetComponent().material = whiteMaterial; rotateZ.GetComponent().material = whiteMaterial; rotatePlaneHandle.GetComponent().material = yellowMaterial; break; case RotateSelectState.Sphere: rotateSphere.GetComponent().material.SetFloat("_AlphaScale", 0.4f); rotateSphere.SetActive(true); rotatePlaneHandle.GetComponent().material = whiteMaterial; break; } } protected override void ChangeRenderOnUnSelect() { rotatePlaneHandle.SetActive(true); rotateX.SetActive(true); rotateY.SetActive(true); rotateZ.SetActive(true); rotatePlaneHandle.GetComponent().material = whiteMaterial; rotateX.GetComponent().material = redMaterial; rotateY.GetComponent().material = greenMaterial; rotateZ.GetComponent().material = blueMaterial; rotateSphere.GetComponent().material.SetFloat("_AlphaScale", 0.2f); } public void SphereRenderUpdate(string handleName) { if (rotateSelectState != RotateSelectState.UnSelected) { return; } rotateSphere.SetActive(handleName.Equals("RotateSphere")); } }