private void VisualizeTrackers() { for (int i = 0; i < trackers.RequiredTrackers.Length; i++) { // Spawn new visual if there are not enough if (trackerVisuals.Count < i + 1) { trackerVisuals.Add(Instantiate(trackerModel, transform)); } VRTrackerType trackerType = trackers.RequiredTrackers[i]; // Hide tracker when there is no tracker data TransformValues?trackerTransform = trackers.GetTracker(trackerType); if (trackerTransform == null) { if (trackerVisuals[i].activeSelf) { trackerVisuals[i].SetActive(false); } continue; } // Position tracker model to the right position if (!trackerVisuals[i].activeSelf) { trackerVisuals[i].SetActive(true); } trackerVisuals[i]?.transform.SetPositionAndRotation( trackerTransform.Value.position, trackerTransform.Value.rotation); } }
public static OffsetsToTrackers?GetMatchingTrackerOffsetForTracker(VRTrackerType trackerType) { switch (trackerType) { case VRTrackerType.Head: return(OffsetsToTrackers.HeadTrackerToHead); case VRTrackerType.LeftHand: return(OffsetsToTrackers.LeftHandTrackerToWrist); case VRTrackerType.RightHand: return(OffsetsToTrackers.RightHandTrackerToWrist); case VRTrackerType.Waist: return(OffsetsToTrackers.HipTrackerToHip); case VRTrackerType.LeftFoot: return(OffsetsToTrackers.LeftFootTrackerToAnkle); case VRTrackerType.RightFoot: return(OffsetsToTrackers.RightFootTrackerToAnkle); default: Debug.LogError($"Tracking type: {trackerType} is currently not supported, please add this"); return(null); } }
// Tracker Direction public void AddTrackerDirection(VRTrackerType type, Axis axis, Vector3 direction) { Debug.LogWarning($"Add tracker direction: {type} - {axis}"); if (!trackerDirections.ContainsKey(type)) { trackerDirections.Add(type, new TrackerDirection(axis, direction.normalized)); } else { trackerDirections[type].SetAxis(axis, direction.normalized); } if (trackerDirections?[type].GetAxis(Axis.Z) != null && trackerDirections?[type].GetAxis(Axis.Y) != null) { AddTrackerOffset((OffsetsToTrackers)GetMatchingTrackerOffsetForTracker(type), Quaternion.LookRotation(trackerDirections[type].Z, trackerDirections[type].Y)); } }
public TransformValues?GetTrackerWithOffset(VRTrackerType type, Vector3 localPosition, Quaternion localRotation) { if (trackers.ContainsKey(type)) { TransformValues?trackerTransform = GetTracker(type); if (trackerTransform == null) { return(null); } Matrix4x4 trackerMatrix = Matrix4x4.TRS(trackerTransform.Value.position, trackerTransform.Value.rotation, addToLocal ? transform.lossyScale : Vector3.one); Vector3 pos = trackerMatrix.MultiplyPoint3x4(localPosition); Quaternion rot = trackerMatrix.rotation * localRotation; return(new TransformValues(pos, rot)); } return(null); }
public static Vector3 GetDirection(Direction settings, TrackerReference trackers, CalibrationProfile profile) { switch (settings.type) { case DirectionType.WorldDirection: return(settings.worldDirection); case DirectionType.TrackerDirection: TransformValues?trackerFrom = trackers.GetTracker(settings.trackerFrom); if (settings.trackerFromLocal) { if (profile.trackerOffsets.ContainsKey(settings.trackerFromLocalOffset) && profile.trackerOffsets[settings.trackerFromLocalOffset].position != null) { trackerFrom = trackers.GetTrackerWithOffset(settings.trackerFrom, profile.trackerOffsets[settings.trackerFromLocalOffset].Position, Quaternion.identity); } } TransformValues?trackerTo = trackers.GetTracker(settings.trackerTo); if (settings.trackerToLocal) { if (profile.trackerOffsets.ContainsKey(settings.trackerToLocalOffset) && profile.trackerOffsets[settings.trackerToLocalOffset].position != null) { trackerTo = trackers.GetTrackerWithOffset(settings.trackerTo, profile.trackerOffsets[settings.trackerToLocalOffset].Position, Quaternion.identity); } } if (trackerFrom == null || trackerTo == null) { Debug.LogError("Not all trackers are connected"); break; } return(trackerTo.Value.position - trackerFrom.Value.position); } return(Vector3.zero); }
private void VisualizeTrackerOffsets() { for (int i = 0; i < profile.trackerOffsets.Keys.Count; i++) { if (trackerOffsetVisuals.Count < i + 1) { trackerOffsetVisuals.Add(GameObject.CreatePrimitive(PrimitiveType.Sphere)); trackerOffsetVisuals[i].GetComponent <MeshRenderer>().material.color = Color.black; trackerOffsetVisuals[i].transform.localScale = new Vector3(0.05f, 0.05f, 0.05f); trackerOffsetVisuals[i].transform.SetParent(transform); } OffsetsToTrackers offsetType = profile.trackerOffsets.Keys.ToArray()[i]; VRTrackerType type = CalibrationProfile.GetMatchingTrackerFromOffset(offsetType) ?? VRTrackerType.Other; TrackerOffset offset = profile.trackerOffsets[offsetType]; TransformValues?trackerWithOffset = trackers.GetTrackerWithOffset(type, offset.Position, Quaternion.identity); if (trackerWithOffset == null) { if (trackerOffsetVisuals[i].activeSelf) { trackerOffsetVisuals[i].SetActive(false); } continue; } if (!trackerOffsetVisuals[i].activeSelf) { trackerOffsetVisuals[i].SetActive(true); } trackerOffsetVisuals[i]?.transform.SetPositionAndRotation( trackerWithOffset.Value.position, trackerWithOffset.Value.rotation); } }
private void VisualizeBodyPart(ref GameObject obj, GameObject objModel, VRTrackerType trackerType, OffsetsToTrackers offset) { if (obj == null) { obj = Instantiate(objModel, transform); obj.SetActive(false); } TransformValues?handTransform = trackers.GetTracker(trackerType); if (profile.trackerOffsets.ContainsKey(offset) && profile.trackerOffsets[offset].position != null) { handTransform = trackers.GetTrackerWithOffset(trackerType, profile.trackerOffsets[offset].Position, Quaternion.identity); } if (handTransform == null || !profile.trackerDirections.ContainsKey(trackerType) || profile.trackerDirections[trackerType].GetAxis(Axis.Z) == null || profile.trackerDirections[trackerType].GetAxis(Axis.Y) == null) { if (obj.activeSelf) { obj.SetActive(false); } return; } if (!obj.activeSelf) { obj.SetActive(true); } Matrix4x4 trackerMatrix = Matrix4x4.TRS(handTransform.Value.position, handTransform.Value.rotation, Vector3.one); Quaternion rotation = Quaternion.LookRotation( trackerMatrix.MultiplyVector(profile.trackerDirections[trackerType].Z), trackerMatrix.MultiplyVector(profile.trackerDirections[trackerType].Y)); obj.transform.SetPositionAndRotation(handTransform.Value.position, rotation); }
public TransformValues?GetTracker(VRTrackerType type) // TODO: clean up with out variables { if (trackers == null) { return(null); } if (trackers.ContainsKey(type)) { if (addToLocal) { Matrix4x4 parentMatrix = Matrix4x4.TRS(transform.position, transform.rotation, transform.lossyScale); Vector3 trackerLocalPosition = parentMatrix.MultiplyPoint3x4(trackers[type].position); Quaternion trackerLocalRotation = parentMatrix.rotation * trackers[type].rotation; return(new TransformValues(trackerLocalPosition, trackerLocalRotation)); } return(new TransformValues(trackers[type].position, trackers[type].rotation)); } return(null); }
public void RemoveTrackerDirection(VRTrackerType trackerType, Axis type) { Debug.LogWarning($"Remove tracker direction: {trackerType} - {type}"); }
public Arc(TrackerReference trackers, VRTrackerType parentTrackerType) // TODO: add local offset { this.arcPoints = new List <ArcPoint>(); this.trackers = trackers; this.parentTracker = parentTrackerType; }
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { // Using BeginProperty / EndProperty on the parent property means that // __prefab__ override logic works on the entire property. EditorGUI.BeginProperty(position, label, property); // Get variables var localOffset = property.FindPropertyRelative("useTrackerLocal"); var parent = property.FindPropertyRelative("useParentTracker"); // Draw label string arrayIndex = Regex.Replace(property.displayName, "[^0-9]", string.Empty); VRTrackerType trackerName = (VRTrackerType)property.FindPropertyRelative("tracker").intValue; OffsetsToTrackers offsetName = (OffsetsToTrackers)property.FindPropertyRelative("localOffset").intValue; VRTrackerType parentName = (VRTrackerType)property.FindPropertyRelative("parentTracker").intValue; label.text = (arrayIndex.Length > 0 ? $"{arrayIndex} - " : string.Empty) + $"{trackerName} Tracker" + (localOffset.boolValue ? $" - (Local: {offsetName})" : string.Empty) + (parent.boolValue ? $" - (Parent: {parentName})" : string.Empty); // Foldout group var expendRect = new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight); property.isExpanded = EditorGUI.Foldout(expendRect, property.isExpanded, label); // Don't make child fields be indented var indent = EditorGUI.indentLevel; EditorGUI.indentLevel += 2; // Calculate rects var trackerRect = new Rect(position.x, position.y + EditorGUIUtility.singleLineHeight + lineHeight, position.width, EditorGUIUtility.singleLineHeight); var useLocalRect = new Rect(position.x, position.y + (EditorGUIUtility.singleLineHeight + lineHeight) * 2, position.width * .45f, EditorGUIUtility.singleLineHeight); var useLocalEnumRect = new Rect(position.x + position.width * .45f, position.y + (EditorGUIUtility.singleLineHeight + lineHeight) * 2, position.width * .55f, EditorGUIUtility.singleLineHeight); var useParentRect = new Rect(position.x, position.y + (EditorGUIUtility.singleLineHeight + lineHeight) * 3, position.width * .45f, EditorGUIUtility.singleLineHeight); var useParentEnumRect = new Rect(position.x + position.width * .45f, position.y + (EditorGUIUtility.singleLineHeight + lineHeight) * 3, position.width * .55f, EditorGUIUtility.singleLineHeight); // Draw fields if (property.isExpanded) { EditorGUI.PropertyField(trackerRect, property.FindPropertyRelative("tracker"), new GUIContent("Tracker")); EditorGUI.PropertyField(useLocalRect, property.FindPropertyRelative("useTrackerLocal"), new GUIContent("Use tracker local")); if (localOffset.boolValue) { EditorGUI.PropertyField(useLocalEnumRect, property.FindPropertyRelative("localOffset"), GUIContent.none); } EditorGUI.PropertyField(useParentRect, property.FindPropertyRelative("useParentTracker"), new GUIContent("Use parent")); if (parent.boolValue) { EditorGUI.PropertyField(useParentEnumRect, property.FindPropertyRelative("parentTracker"), GUIContent.none); } } // Set indent back to what it was EditorGUI.indentLevel = indent; EditorGUI.EndProperty(); }
private void VisualizeDirection() { for (int i = 0; i < profile.trackerDirections.Keys.Count; i++) { if (trackerDirectionVisuals.Count < i + 1) { trackerDirectionVisuals.Add( new[] { GameObject.CreatePrimitive(PrimitiveType.Cube), GameObject.CreatePrimitive(PrimitiveType.Cube), GameObject.CreatePrimitive(PrimitiveType.Cube) }); trackerDirectionVisuals[i][0].GetComponent <MeshRenderer>().material.color = Color.red; trackerDirectionVisuals[i][1].GetComponent <MeshRenderer>().material.color = Color.green; trackerDirectionVisuals[i][2].GetComponent <MeshRenderer>().material.color = Color.blue; foreach (GameObject obj in trackerDirectionVisuals[i]) { obj.transform.localScale = new Vector3(0.02f, 0.02f, 0.02f); obj.transform.SetParent(transform); } } VRTrackerType trackerType = profile.trackerDirections.Keys.ToArray()[i]; if (alsoHead == false && trackerType == VRTrackerType.Head) { continue; } OffsetsToTrackers?offsetType = CalibrationProfile.GetMatchingTrackerOffsetForTracker(trackerType); if (offsetType == null) { continue; } Matrix4x4 trackerMatrix; if (profile.trackerOffsets.ContainsKey((OffsetsToTrackers)offsetType)) { TrackerOffset trackerOffset = profile.trackerOffsets[(OffsetsToTrackers)offsetType]; TransformValues trackerTransform = trackers.GetTrackerWithOffset(trackerType, trackerOffset.Position, Quaternion.identity) ?? new TransformValues(Vector3.zero, Quaternion.identity); trackerMatrix = Matrix4x4.TRS(trackerTransform.position, trackerTransform.rotation, Vector3.one); } else { TransformValues trackerTransform = trackers.GetTracker(trackerType) ?? new TransformValues(Vector3.zero, Quaternion.identity); trackerMatrix = Matrix4x4.TRS(trackerTransform.position, trackerTransform.rotation, Vector3.one); } TrackerDirection trackerDirection = profile.trackerDirections[trackerType]; if (trackerDirection.X != Vector3.zero) { trackerDirectionVisuals[i][0].transform.localScale = new Vector3(0.02f, 0.02f, 0.02f); trackerDirectionVisuals[i][0].transform.position = trackerMatrix.GetPosition() + trackerMatrix.MultiplyVector(trackerDirection.X) * 0.1f; } else { trackerDirectionVisuals[i][0].transform.localScale = Vector3.zero; } if (trackerDirection.Y != Vector3.zero) { trackerDirectionVisuals[i][1].transform.localScale = new Vector3(0.02f, 0.02f, 0.02f); trackerDirectionVisuals[i][1].transform.position = trackerMatrix.GetPosition() + trackerMatrix.MultiplyVector(trackerDirection.Y) * 0.1f; } else { trackerDirectionVisuals[i][1].transform.localScale = Vector3.zero; } if (trackerDirection.Z != Vector3.zero) { trackerDirectionVisuals[i][2].transform.localScale = new Vector3(0.02f, 0.02f, 0.02f); trackerDirectionVisuals[i][2].transform.position = trackerMatrix.GetPosition() + trackerMatrix.MultiplyVector(trackerDirection.Z) * 0.1f; } else { trackerDirectionVisuals[i][2].transform.localScale = Vector3.zero; } } }
private void ProcessData(Data[] arcData) { foreach (Data data in arcData) { switch (data.dataType) { case DataType.OffsetToTracker: // Add offset on local plane if (data.onLocalPlane) { // if profile doesn't contain a offset yet, just add it normally if (profile.trackerOffsets.ContainsKey(data.trackerOffset) && profile.trackerOffsets[data.trackerOffset].position != null) { TrackerOffset offset = profile.trackerOffsets[data.trackerOffset]; VRTrackerType trackerType = (VRTrackerType)CalibrationProfile.GetMatchingTrackerFromOffset(data.trackerOffset); // if profile doesn't contain the required axis ignore if (profile.trackerDirections.ContainsKey(trackerType) && profile.trackerDirections[trackerType].GetAxis(data.localPlane) != null) { TransformValues trackerTransform = (TransformValues)trackers.GetTracker(trackerType); Matrix4x4 trackerMatrix = Matrix4x4.TRS(trackerTransform.position, trackerTransform.rotation, Vector3.one); Matrix4x4 inverseTrackerMatrix = trackerMatrix.inverse; Vector3 localAxis = trackerMatrix.MultiplyVector(profile.trackerDirections[trackerType].GetAxis(data.localPlane) ?? Vector3.zero); Vector3 newPositionDirection = trackerMatrix.MultiplyPoint3x4(arcArray[data.arcPositionIndex].GetOffsetToTracker()) - trackerMatrix.MultiplyPoint3x4((Vector3)offset.position); Vector3 newPosition = trackerMatrix.MultiplyPoint3x4((Vector3)offset.position) + Vector3.ProjectOnPlane(newPositionDirection, localAxis); newPosition = inverseTrackerMatrix.MultiplyPoint3x4(newPosition); // Debug.Log(newPosition.magnitude); // Debug.DrawLine(trackerMatrix.MultiplyPoint3x4(arcArray[data.arcPositionIndex].GetOffsetToTracker()), trackerMatrix.MultiplyPoint3x4(arcArray[data.arcPositionIndex].GetOffsetToTracker()), Color.blue, 10f); // Debug.DrawRay(trackerMatrix.MultiplyPoint3x4(arcArray[data.arcPositionIndex].GetOffsetToTracker()), localAxis, Color.red, 10f); arcArray[data.arcPositionIndex].GetOffsetToTracker(); profile.AddTrackerOffset(data.trackerOffset, newPosition); continue; } Debug.LogError($"Could not apply local offset to {trackerType}, plane axis is not applied"); } } profile.AddTrackerOffset(data.trackerOffset, arcArray[data.arcPositionIndex].GetOffsetToTracker()); break; case DataType.Length: // TODO: TMP foreach (int index in data.arcMeasurementIndices) { GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere); sphere.transform.position = arcArray[index].IntersectionPoint; sphere.transform.localScale = new Vector3(.05f, .05f, .05f); } float value = data.arcMeasurementIndices.Sum(arc => arcArray[arc].GetArcRadius()) / data.arcMeasurementIndices.Length; profile.AddBodyMeasurement(data.measurement, value); break; case DataType.Distance: Vector3 point1 = Vector3.zero; Vector3 point2 = Vector3.zero; // TODO: make this a function switch (data.point1.pointType) { case PointType.ArcPoint: point1 = arcArray[data.point1.arcIndex].IntersectionPoint; break; case PointType.Tracker: point1 = Vector3.zero; // TODO: calculate local offset to tracker break; } switch (data.point2.pointType) { case PointType.ArcPoint: point2 = arcArray[data.point2.arcIndex].IntersectionPoint; break; case PointType.Tracker: point2 = Vector3.zero; // TODO: calculate local offset to tracker break; } float distance = Vector3.Distance(point1, point2); profile.AddBodyMeasurement(data.distanceMeasurement, distance); break; case DataType.Direction: Vector3 normal = arcArray[data.arcDirectionIndex].GetArcNormalFromTracker(); VRTrackerType trackerDirectionType = settings[data.arcDirectionIndex].parentTracker; TransformValues?trackerDirectionTransform = trackers.GetTracker(trackerDirectionType); if (trackerDirectionTransform == null) { Debug.Log("Not all trackers are assigned"); return; } Matrix4x4 trackerDirectionMatrix = Matrix4x4.TRS(trackerDirectionTransform.Value.position, trackerDirectionTransform.Value.rotation, Vector3.one); Vector3 worldNormal = trackerDirectionMatrix.MultiplyVector(normal); switch (data.directionClosest.type) { case DirectionClosestType.SingleDirection: Vector3 dir = Vector3.zero; // TODO: make this a function switch (data.directionClosest.singleDirection.type) { case DirectionType.WorldDirection: dir = data.directionClosest.singleDirection.worldDirection; dir = dir.normalized; break; case DirectionType.TrackerDirection: TransformValues?trackerFrom = trackers.GetTracker(data.directionClosest.singleDirection.trackerFrom); TransformValues?trackerTo = trackers.GetTracker(data.directionClosest.singleDirection.trackerTo); if (trackerFrom == null || trackerTo == null) { Debug.LogError("Not all trackers are connected"); return; } dir = trackerTo.Value.position - trackerFrom.Value.position; dir = dir.normalized; break; } Debug.DrawRay(trackers.GetTracker(VRTrackerType.LeftHand).Value.position, worldNormal, Color.magenta, 10f); Debug.DrawRay(trackers.GetTracker(VRTrackerType.LeftHand).Value.position, dir, Color.cyan, 10f); if (Vector3.Distance(dir, worldNormal) > Vector3.Distance(dir, worldNormal * -1)) { normal *= -1f; } break; case DirectionClosestType.Cross: Vector3 crossDir1 = Vector3.zero; Vector3 crossDir2 = Vector3.zero; // TODO: make this a function switch (data.directionClosest.crossDirection1.type) { case DirectionType.WorldDirection: crossDir1 = data.directionClosest.crossDirection1.worldDirection; break; case DirectionType.TrackerDirection: TransformValues?trackerFrom = trackers.GetTracker(data.directionClosest.crossDirection1.trackerFrom); TransformValues?trackerTo = trackers.GetTracker(data.directionClosest.crossDirection1.trackerTo); if (trackerFrom == null || trackerTo == null) { Debug.LogError("Not all trackers are connected"); return; } crossDir1 = trackerTo.Value.position - trackerFrom.Value.position; break; } switch (data.directionClosest.crossDirection2.type) { case DirectionType.WorldDirection: crossDir2 = data.directionClosest.crossDirection2.worldDirection; break; case DirectionType.TrackerDirection: TransformValues?trackerFrom = trackers.GetTracker(data.directionClosest.crossDirection2.trackerFrom); TransformValues?trackerTo = trackers.GetTracker(data.directionClosest.crossDirection2.trackerTo); if (trackerFrom == null || trackerTo == null) { Debug.LogError("Not all trackers are connected"); return; } crossDir2 = trackerTo.Value.position - trackerFrom.Value.position; break; } Vector3 cross = Vector3.Cross(crossDir1, crossDir2); if (Vector3.Distance(cross, worldNormal) > Vector3.Distance(cross, worldNormal * -1)) { normal *= -1f; } Debug.DrawRay(trackers.GetTracker(VRTrackerType.LeftHand).Value.position, worldNormal, Color.magenta, 10f); Debug.DrawRay(trackers.GetTracker(VRTrackerType.LeftHand).Value.position, cross, Color.cyan, 10f); break; default: Debug.LogError("Implement your shit"); break; } profile.AddTrackerDirection(trackerDirectionType, data.directionAxis, normal); break; } } }
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { EditorGUI.BeginProperty(position, label, property); // Get variables var currentType = (ArcCalibrationStep.DataType)property.FindPropertyRelative("dataType").intValue; SerializedProperty onLocalPlane = property.FindPropertyRelative("onLocalPlane"); // Draw label ArcCalibrationStep.DataType dataType = (ArcCalibrationStep.DataType)property.FindPropertyRelative("dataType").intValue; string dataName = string.Empty; switch (dataType) { case ArcCalibrationStep.DataType.OffsetToTracker: OffsetsToTrackers trackerOffsetType = (OffsetsToTrackers)property.FindPropertyRelative("trackerOffset").intValue; Axis localPlane = (Axis)property.FindPropertyRelative("localPlane").intValue; string localPlaneName = onLocalPlane.boolValue ? $"Local {localPlane.ToString()} " : string.Empty; dataName = $"{localPlaneName}{trackerOffsetType} ({property.FindPropertyRelative("arcPositionIndex").intValue})"; break; case ArcCalibrationStep.DataType.Length: BodyMeasurements lengthBodyMeasurementType = (BodyMeasurements)property.FindPropertyRelative("measurement").intValue; SerializedProperty indices = property.FindPropertyRelative("arcMeasurementIndices"); string index = string.Empty; for (int i = 0; i < indices.arraySize; i++) { if (i != 0) { index += ", "; } index += indices.GetArrayElementAtIndex(i).intValue.ToString(); } dataName = $"{lengthBodyMeasurementType} ({index})"; break; case ArcCalibrationStep.DataType.Distance: BodyMeasurements distanceBodyMeasurementType = (BodyMeasurements)property.FindPropertyRelative("distanceMeasurement").intValue; string distanceIndex = string.Empty; ArcCalibrationStep.PointType point1Type = (ArcCalibrationStep.PointType)property.FindPropertyRelative("point1").FindPropertyRelative("pointType").intValue; switch (point1Type) { case ArcCalibrationStep.PointType.ArcPoint: distanceIndex += property.FindPropertyRelative("point1").FindPropertyRelative("arcIndex").intValue; break; case ArcCalibrationStep.PointType.Tracker: VRTrackerType trackerTypePoint1 = (VRTrackerType)property.FindPropertyRelative("point1").FindPropertyRelative("tracker").intValue; distanceIndex += trackerTypePoint1; if (property.FindPropertyRelative("point2").FindPropertyRelative("useLocalOffset").boolValue) { distanceIndex += " (Local)"; } break; } distanceIndex += ", "; ArcCalibrationStep.PointType point2Type = (ArcCalibrationStep.PointType)property.FindPropertyRelative("point2").FindPropertyRelative("pointType").intValue; switch (point2Type) { case ArcCalibrationStep.PointType.ArcPoint: distanceIndex += property.FindPropertyRelative("point2").FindPropertyRelative("arcIndex").intValue; break; case ArcCalibrationStep.PointType.Tracker: VRTrackerType trackerTypePoint2 = (VRTrackerType)property.FindPropertyRelative("point2").FindPropertyRelative("tracker").intValue; distanceIndex += trackerTypePoint2; if (property.FindPropertyRelative("point2").FindPropertyRelative("useLocalOffset").boolValue) { distanceIndex += " (Local)"; } break; } dataName = $"{distanceBodyMeasurementType} ({distanceIndex})"; break; case ArcCalibrationStep.DataType.Direction: Axis directionAxis = (Axis)property.FindPropertyRelative("directionAxis").intValue; dataName = $"{directionAxis} ({property.FindPropertyRelative("arcDirectionIndex").intValue})"; break; } label.text = $"{dataType}: {dataName}"; // Foldout group var expendRect = new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight); property.isExpanded = EditorGUI.Foldout(expendRect, property.isExpanded, label); // Don't make child fields be indented var indent = EditorGUI.indentLevel; EditorGUI.indentLevel += 2; // Calculate rects var dataTypeRect = new Rect(position.x, position.y + EditorGUIUtility.singleLineHeight + lineHeight, position.width, EditorGUIUtility.singleLineHeight); // Tracker offset var trackerOffsetEnumRect = new Rect(position.x, position.y + (EditorGUIUtility.singleLineHeight + lineHeight) * 2, position.width, EditorGUIUtility.singleLineHeight); var trackerOffetArcIndexRect = new Rect(position.x, position.y + (EditorGUIUtility.singleLineHeight + lineHeight) * 3, position.width, EditorGUIUtility.singleLineHeight); var trackerOffetOnLocalPlaneRect = new Rect(position.x, position.y + (EditorGUIUtility.singleLineHeight + lineHeight) * 4, position.width * .45f, EditorGUIUtility.singleLineHeight); var trackerOffetLocalPlaneRect = new Rect(position.x + position.width * .45f, position.y + (EditorGUIUtility.singleLineHeight + lineHeight) * 4, position.width * .55f, EditorGUIUtility.singleLineHeight); // Length SerializedProperty lengthIndicesProperty = property.FindPropertyRelative("arcMeasurementIndices"); var lengthMeasurementTypeRect = new Rect(position.x, position.y + (EditorGUIUtility.singleLineHeight + lineHeight) * 2, position.width, EditorGUIUtility.singleLineHeight); var lengthIndicesRect = new Rect(position.x, position.y + (EditorGUIUtility.singleLineHeight + lineHeight) * 3, position.width, EditorGUI.GetPropertyHeight(lengthIndicesProperty)); // Distance SerializedProperty distancePoint1 = property.FindPropertyRelative("point1"); SerializedProperty distancePoint2 = property.FindPropertyRelative("point2"); var distanceEnumRect = new Rect(position.x, position.y + (EditorGUIUtility.singleLineHeight + lineHeight) * 2, position.width, EditorGUIUtility.singleLineHeight); var distancePoint1Rect = new Rect(position.x, position.y + (EditorGUIUtility.singleLineHeight + lineHeight) * 3, position.width, EditorGUI.GetPropertyHeight(distancePoint1)); var distancePoint2Rect = new Rect(position.x, position.y + EditorGUI.GetPropertyHeight(distancePoint1) + lineHeight + (EditorGUIUtility.singleLineHeight + lineHeight) * 3, position.width, EditorGUI.GetPropertyHeight(distancePoint2)); // Direction SerializedProperty closestDirection = property.FindPropertyRelative("directionClosest"); var directionAxisRect = new Rect(position.x, position.y + (EditorGUIUtility.singleLineHeight + lineHeight) * 2, position.width, EditorGUIUtility.singleLineHeight); var arcDirectionIndexRect = new Rect(position.x, position.y + (EditorGUIUtility.singleLineHeight + lineHeight) * 3, position.width, EditorGUIUtility.singleLineHeight); var closestDirectionRect = new Rect(position.x, position.y + (EditorGUIUtility.singleLineHeight + lineHeight) * 4, position.width, EditorGUI.GetPropertyHeight(closestDirection)); // Draw fields if (property.isExpanded) { EditorGUI.PropertyField(dataTypeRect, property.FindPropertyRelative("dataType"), new GUIContent("Data type")); switch (currentType) { case ArcCalibrationStep.DataType.OffsetToTracker: EditorGUI.PropertyField(trackerOffsetEnumRect, property.FindPropertyRelative("trackerOffset"), new GUIContent("Tracker offset")); EditorGUI.PropertyField(trackerOffetArcIndexRect, property.FindPropertyRelative("arcPositionIndex"), new GUIContent("Arc index")); EditorGUI.PropertyField(trackerOffetOnLocalPlaneRect, property.FindPropertyRelative("onLocalPlane"), new GUIContent("On local plane")); if (onLocalPlane.boolValue) { EditorGUI.PropertyField(trackerOffetLocalPlaneRect, property.FindPropertyRelative("localPlane"), GUIContent.none); } break; case ArcCalibrationStep.DataType.Length: EditorGUI.PropertyField(lengthMeasurementTypeRect, property.FindPropertyRelative("measurement"), new GUIContent("Measurement")); EditorGUI.PropertyField(lengthIndicesRect, lengthIndicesProperty, new GUIContent("Arc indices"), true); break; case ArcCalibrationStep.DataType.Distance: EditorGUI.PropertyField(distanceEnumRect, property.FindPropertyRelative("distanceMeasurement"), new GUIContent("Measurement")); EditorGUI.PropertyField(distancePoint1Rect, distancePoint1, new GUIContent("Point 1"), true); EditorGUI.PropertyField(distancePoint2Rect, distancePoint2, new GUIContent("Point 2"), true); break; case ArcCalibrationStep.DataType.Direction: EditorGUI.PropertyField(directionAxisRect, property.FindPropertyRelative("directionAxis"), new GUIContent("Axis")); EditorGUI.PropertyField(arcDirectionIndexRect, property.FindPropertyRelative("arcDirectionIndex"), new GUIContent("Arc index")); EditorGUI.PropertyField(closestDirectionRect, closestDirection, new GUIContent("Direction Closest To"), true); break; } } // Set indent back to what it was EditorGUI.indentLevel = indent; EditorGUI.EndProperty(); }