robotArm
This commit is contained in:
@@ -0,0 +1,325 @@
|
||||
#if UNITY_EDITOR
|
||||
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
namespace AshqarApps.DynamicJoint
|
||||
{
|
||||
[CustomEditor(typeof(DynamicJointLimitHinge))]
|
||||
[CanEditMultipleObjects]
|
||||
public class DynamicJointLimitHingeInspector : Editor
|
||||
{
|
||||
private DynamicJointLimitHinge script { get { return target as DynamicJointLimitHinge; } }
|
||||
private Vector3 lastPoint, zeroPoint;
|
||||
|
||||
float lastHingeOffset = 0;
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
GUI.changed = false;
|
||||
|
||||
base.OnInspectorGUI();
|
||||
//DrawDefaultInspector();
|
||||
|
||||
int childCount = script.transform.childCount;
|
||||
GameObject childGO = null;
|
||||
for (int i = 0; i < script.transform.childCount; ++i)
|
||||
{
|
||||
if (!script.transform.GetChild(i).tag.Contains("ExcludeFromDynamics"))
|
||||
{
|
||||
childGO = script.transform.GetChild(i).gameObject;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (childGO != null)
|
||||
{
|
||||
if (GUILayout.Button("Align To Child Twist"))
|
||||
{
|
||||
Vector3 toChild = childGO.transform.position - script.transform.position;
|
||||
script.mainAxis = script.transform.InverseTransformDirection(toChild.normalized);
|
||||
Vector3 secondaryAxis = new Vector3(script.mainAxis.y, script.mainAxis.z, script.mainAxis.x);
|
||||
script.cross = Direction(Vector3.Cross(script.mainAxis, secondaryAxis));
|
||||
}
|
||||
else if (GUILayout.Button("Align To Child X"))
|
||||
{
|
||||
Vector3 toChild = (childGO.transform.position - script.transform.position).normalized;
|
||||
script.cross = script.transform.InverseTransformDirection(toChild);
|
||||
//Vector3 secondaryAxis = new Vector3(script.cross.y, script.cross.z, script.cross.x);
|
||||
Vector3 secondaryAxis = script.transform.InverseTransformDirection(script.transform.right);
|
||||
Vector3.OrthoNormalize(ref secondaryAxis, ref script.cross);
|
||||
//Vector3 cross = Direction(Vector3.Cross(script.cross, secondaryAxis));
|
||||
script.mainAxis = secondaryAxis;
|
||||
}
|
||||
else if (GUILayout.Button("Align To Child Y"))
|
||||
{
|
||||
Vector3 toChild = (childGO.transform.position - script.transform.position).normalized;
|
||||
script.cross = script.transform.InverseTransformDirection(toChild);
|
||||
Vector3 secondaryAxis = script.transform.InverseTransformDirection(script.transform.up);
|
||||
Vector3.OrthoNormalize(ref secondaryAxis, ref script.cross);
|
||||
script.mainAxis = secondaryAxis;
|
||||
}
|
||||
else if (GUILayout.Button("Align To Child Z"))
|
||||
{
|
||||
Vector3 toChild = (childGO.transform.position - script.transform.position).normalized;
|
||||
script.cross = script.transform.InverseTransformDirection(toChild);
|
||||
Vector3 secondaryAxis = script.transform.InverseTransformDirection(script.transform.forward);
|
||||
Vector3.OrthoNormalize(ref secondaryAxis, ref script.cross);
|
||||
script.mainAxis = secondaryAxis;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GUILayout.Button("Align To X"))
|
||||
{
|
||||
Vector3 toChild = script.transform.right;
|
||||
script.mainAxis = script.transform.InverseTransformDirection(toChild.normalized);
|
||||
Vector3 secondaryAxis = new Vector3(script.mainAxis.y, script.mainAxis.z, script.mainAxis.x);
|
||||
script.cross = Vector3.Cross(script.mainAxis, secondaryAxis);
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Align To Y"))
|
||||
{
|
||||
Vector3 toChild = script.transform.up;
|
||||
script.mainAxis = script.transform.InverseTransformDirection(toChild.normalized);
|
||||
Vector3 secondaryAxis = new Vector3(script.mainAxis.y, script.mainAxis.z, script.mainAxis.x);
|
||||
script.cross = Vector3.Cross(script.mainAxis, secondaryAxis);
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Align To Z"))
|
||||
{
|
||||
Vector3 toChild = script.transform.forward;
|
||||
script.mainAxis = script.transform.InverseTransformDirection(toChild.normalized);
|
||||
Vector3 secondaryAxis = new Vector3(script.mainAxis.y, script.mainAxis.z, script.mainAxis.x);
|
||||
script.cross = Vector3.Cross(script.mainAxis, secondaryAxis);
|
||||
}
|
||||
}
|
||||
|
||||
if (GUI.changed) EditorUtility.SetDirty(script);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void UpdateZeroTransform()
|
||||
{
|
||||
if (lastHingeOffset != script.hingeAngleOffset)
|
||||
{
|
||||
lastHingeOffset = script.hingeAngleOffset;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void OnSceneGUI()
|
||||
{
|
||||
if (!Application.isPlaying && !script.zeroRotationOverride) script.zeroRotation = script.transform.localRotation;
|
||||
if (script.mainAxis == Vector3.zero || script.cross == Vector3.zero) return;
|
||||
|
||||
float minBoneLength = 0.15f;
|
||||
float boneLength = minBoneLength;
|
||||
if (script.transform.childCount > 0)
|
||||
{
|
||||
boneLength = Vector3.Distance(script.transform.position, script.transform.GetChild(0).position) / 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (script.transform.parent != null)
|
||||
{
|
||||
boneLength = Vector3.Distance(script.transform.position, script.transform.parent.position) / 4;
|
||||
}
|
||||
}
|
||||
|
||||
boneLength = Mathf.Max(boneLength, minBoneLength);
|
||||
|
||||
|
||||
// Display the main axis
|
||||
DrawArrow(script.transform.position, Direction(script.mainAxis), colorDefault, "Axis", 0.02f);
|
||||
|
||||
Handles.color = Color.white;
|
||||
GUI.color = Color.white;
|
||||
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
|
||||
// Selecting points
|
||||
Handles.color = colorHandles;
|
||||
Handles.Button(script.transform.position + Direction(script.mainAxis), script.transform.rotation, 0.02f, 0.02f, Handles.DotHandleCap);
|
||||
|
||||
Vector3 selectedPoint = script.mainAxis;
|
||||
|
||||
// Store point for undo
|
||||
Vector3 oldPoint = selectedPoint;
|
||||
|
||||
// Manual input for the point position
|
||||
AddVector3(ref selectedPoint, "Point", script, GUILayout.Width(210));
|
||||
|
||||
// Moving Points
|
||||
Vector3 pointWorld = Handles.PositionHandle(script.transform.position + Direction(selectedPoint), Quaternion.identity);
|
||||
Vector3 newPoint = InverseDirection(pointWorld - script.transform.position);
|
||||
if (newPoint != selectedPoint)
|
||||
{
|
||||
if (!Application.isPlaying) Undo.RecordObject(script, "Move Limit Point");
|
||||
script.mainAxis = newPoint.normalized;
|
||||
}
|
||||
}
|
||||
|
||||
DrawHingeLimits(boneLength);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void DrawHingeLimits(float boneLength)
|
||||
{
|
||||
Quaternion offsetRot = Quaternion.Euler(script.limitsOffset);
|
||||
|
||||
Vector3 swing = Direction(offsetRot * script.mainAxis.normalized);
|
||||
|
||||
//Vector3 secondaryAxis = new Vector3(script.mainAxis.y, script.mainAxis.z, script.mainAxis.x);
|
||||
//Vector3 cross = Direction(Vector3.Cross(script.mainAxis, secondaryAxis));
|
||||
if (script.cross.magnitude == 0) return;
|
||||
Vector3 cross = Direction(offsetRot * script.cross);
|
||||
Vector3.OrthoNormalize(ref swing, ref cross);
|
||||
Vector3 secondaryAxis = Vector3.Cross(script.mainAxis, cross);
|
||||
|
||||
Handles.CircleHandleCap(0, script.transform.position, Quaternion.LookRotation(swing, cross), boneLength, EventType.Repaint);
|
||||
|
||||
//DrawArrow(script.transform.position, cross * boneLength, colorDefault, " 0", 0.02f);
|
||||
DrawArrow(script.transform.position, cross * boneLength, colorDefault, " 0", 0.02f);
|
||||
|
||||
Quaternion hingeOffset = Quaternion.AngleAxis(script.hingeAngleOffset, swing);
|
||||
|
||||
// Arcs for the rotation limit
|
||||
Handles.color = colorDefaultTransparent;
|
||||
Handles.DrawSolidArc(script.transform.position, swing, hingeOffset * cross, -script.limitAngle, boneLength);
|
||||
Handles.DrawSolidArc(script.transform.position, swing, hingeOffset * cross, script.limitAngle, boneLength);
|
||||
|
||||
Quaternion minRotation = Quaternion.AngleAxis(-script.limitAngle, swing);
|
||||
Vector3 minHandleDir = minRotation * (hingeOffset * cross);
|
||||
Handles.DrawLine(script.transform.position, script.transform.position + minHandleDir.normalized * boneLength);
|
||||
|
||||
Quaternion maxRotation = Quaternion.AngleAxis(script.limitAngle, swing);
|
||||
Vector3 maxHandleDir = maxRotation * (hingeOffset * cross);
|
||||
Handles.DrawLine(script.transform.position, script.transform.position + maxHandleDir.normalized * boneLength);
|
||||
|
||||
Handles.color = colorHandles;
|
||||
//Draw Editable Handles
|
||||
float originalLimit = script.limitAngle;
|
||||
float limitAngleMin = script.limitAngle;
|
||||
limitAngleMin = DrawLimitHandle(limitAngleMin, script.transform.position + (minHandleDir.normalized * boneLength * 1.25f), Quaternion.identity, 0.5f, "Limit", -10);
|
||||
if (limitAngleMin != script.limitAngle)
|
||||
{
|
||||
if (!Application.isPlaying) Undo.RecordObject(script, "Min Limit");
|
||||
script.limitAngle = limitAngleMin;
|
||||
script.hingeAngleOffset -= (limitAngleMin - originalLimit);
|
||||
}
|
||||
|
||||
originalLimit = script.limitAngle;
|
||||
//Draw Editable Handles
|
||||
float limitAngleMax = script.limitAngle;
|
||||
limitAngleMax = DrawLimitHandle(limitAngleMax, script.transform.position + (maxHandleDir.normalized * boneLength * 1.25f), Quaternion.identity, 0.5f, "Limit", 10);
|
||||
if (limitAngleMax != script.limitAngle)
|
||||
{
|
||||
if (!Application.isPlaying) Undo.RecordObject(script, "Max Limit");
|
||||
script.limitAngle = limitAngleMax;
|
||||
script.hingeAngleOffset += (limitAngleMax - originalLimit);
|
||||
}
|
||||
|
||||
// clamp limits
|
||||
script.limitAngle = Mathf.Clamp(script.limitAngle, 0, 180f);
|
||||
if (script.hingeAngleOffset < 0) script.hingeAngleOffset += 360;
|
||||
if (script.hingeAngleOffset > 360) script.hingeAngleOffset -= 360;
|
||||
|
||||
}
|
||||
|
||||
private Vector3 Direction(Vector3 v)
|
||||
{
|
||||
if (script.transform.parent == null) return script.zeroRotation * v;
|
||||
return script.transform.parent.rotation * (script.zeroRotation * v);
|
||||
}
|
||||
|
||||
private Vector3 InverseDirection(Vector3 v)
|
||||
{
|
||||
if (script.transform.parent == null) return Quaternion.Inverse(script.zeroRotation) * v;
|
||||
|
||||
return Quaternion.Inverse(script.zeroRotation) * Quaternion.Inverse(script.transform.parent.rotation) * v;
|
||||
}
|
||||
|
||||
// Universal color pallettes
|
||||
public static Color colorDefault { get { return new Color(0.0f, 0.0f, 1.0f, 1.0f); } }
|
||||
|
||||
public static Color colorDefaultTransparent
|
||||
{
|
||||
get
|
||||
{
|
||||
Color d = colorDefault;
|
||||
return new Color(d.r, d.g, d.b, 0.2f);
|
||||
}
|
||||
}
|
||||
|
||||
public static Color colorHandles { get { return new Color(1.0f, 0.5f, 0.25f, 1.0f); } }
|
||||
public static Color colorRotationSphere { get { return new Color(1.0f, 1.0f, 1.0f, 0.1f); } }
|
||||
public static Color colorInvalid { get { return new Color(1.0f, 0.3f, 0.3f, 1.0f); } }
|
||||
public static Color colorValid { get { return new Color(0.2f, 1.0f, 0.2f, 1.0f); } }
|
||||
|
||||
/*
|
||||
* Draws a custom arrow to the scene
|
||||
* */
|
||||
public static void DrawArrow(Vector3 position, Vector3 direction, Color color, string label = "", float size = 0.01f)
|
||||
{
|
||||
Handles.color = color;
|
||||
Handles.DrawLine(position, position + direction);
|
||||
Handles.SphereHandleCap(0, position + direction, Quaternion.identity, size, EventType.Repaint);
|
||||
Handles.color = Color.white;
|
||||
|
||||
if (label != "")
|
||||
{
|
||||
GUI.color = color;
|
||||
Handles.Label(position + direction, label);
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Draws a handle for adjusting rotation limits in the scene
|
||||
* */
|
||||
public static float DrawLimitHandle(float limit, Vector3 position, Quaternion rotation, float radius, string label, float openingValue, bool reverseScaleDirection = false)
|
||||
{
|
||||
float scaleFactor = reverseScaleDirection ? -1 : 1;
|
||||
|
||||
limit = scaleFactor * Handles.ScaleValueHandle(limit, position, rotation, radius, Handles.SphereHandleCap, 1);
|
||||
|
||||
string labelInfo = label + ": " + limit.ToString();
|
||||
|
||||
// If value is 0, draw a button to 'open' the value, because we cant scale 0
|
||||
if (limit == 0)
|
||||
{
|
||||
labelInfo = "Open " + label;
|
||||
|
||||
if (Handles.Button(position, rotation, radius * 0.2f, radius * 0.07f, Handles.SphereHandleCap))
|
||||
{
|
||||
limit = openingValue;
|
||||
}
|
||||
}
|
||||
|
||||
Handles.Label(position, labelInfo);
|
||||
|
||||
return limit;
|
||||
}
|
||||
|
||||
|
||||
public static void AddVector3(ref Vector3 input, string name, Object undoObject, params GUILayoutOption[] options)
|
||||
{
|
||||
Vector3 newValue = EditorGUILayout.Vector3Field(name, input, options);
|
||||
|
||||
if (newValue != input && !Application.isPlaying)
|
||||
{
|
||||
Undo.RecordObject(undoObject, name);
|
||||
}
|
||||
|
||||
input = newValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user