//Assumes the point is already on the line somewhere public static Vector3 ClampToSegment(Vector3 point, Vector3 linePoint1, Vector3 linePoint2) { Vector3 lineDirection = linePoint2 - linePoint1; if (!GeometryUtil.IsInDirection(point - linePoint1, lineDirection)) { point = linePoint1; } else if (GeometryUtil.IsInDirection(point - linePoint2, lineDirection)) { point = linePoint2; } return(point); }
float ClosestDistanceFromMouseToLines(List <Vector3> lines) { Ray mouseRay = myCamera.ScreenPointToRay(Input.mousePosition); float closestDistance = float.MaxValue; for (int i = 0; i < lines.Count; i += 2) { IntersectPoints points = GeometryUtil.ClosestPointsOnSegmentToLine(lines[i], lines[i + 1], mouseRay.origin, mouseRay.direction); float distance = Vector3.Distance(points.first, points.second); if (distance < closestDistance) { closestDistance = distance; } } return(closestDistance); }
void SelectAxis() { if (!Input.GetMouseButtonDown(0)) { return; } selectedAxis = Axis.None; float xClosestDistance = float.MaxValue; float yClosestDistance = float.MaxValue; float zClosestDistance = float.MaxValue; float allClosestDistance = float.MaxValue; float minSelectedDistanceCheck = this.minSelectedDistanceCheck * GetDistanceMultiplier(); if (type == TransformType.Move || type == TransformType.Scale) { selectedLinesBuffer.Clear(); selectedLinesBuffer.Add(handleLines); if (type == TransformType.Move) { selectedLinesBuffer.Add(handleTriangles); } else if (type == TransformType.Scale) { selectedLinesBuffer.Add(handleSquares); } xClosestDistance = ClosestDistanceFromMouseToLines(selectedLinesBuffer.x); yClosestDistance = ClosestDistanceFromMouseToLines(selectedLinesBuffer.y); zClosestDistance = ClosestDistanceFromMouseToLines(selectedLinesBuffer.z); allClosestDistance = ClosestDistanceFromMouseToLines(selectedLinesBuffer.all); } else if (type == TransformType.Rotate) { xClosestDistance = ClosestDistanceFromMouseToLines(circlesLines.x); yClosestDistance = ClosestDistanceFromMouseToLines(circlesLines.y); zClosestDistance = ClosestDistanceFromMouseToLines(circlesLines.z); allClosestDistance = ClosestDistanceFromMouseToLines(circlesLines.all); } if (type == TransformType.Scale && allClosestDistance <= minSelectedDistanceCheck) { selectedAxis = Axis.Any; } else if (xClosestDistance <= minSelectedDistanceCheck && xClosestDistance <= yClosestDistance && xClosestDistance <= zClosestDistance) { selectedAxis = Axis.X; } else if (yClosestDistance <= minSelectedDistanceCheck && yClosestDistance <= xClosestDistance && yClosestDistance <= zClosestDistance) { selectedAxis = Axis.Y; } else if (zClosestDistance <= minSelectedDistanceCheck && zClosestDistance <= xClosestDistance && zClosestDistance <= yClosestDistance) { selectedAxis = Axis.Z; } else if (type == TransformType.Rotate && target != null) { Ray mouseRay = myCamera.ScreenPointToRay(Input.mousePosition); Vector3 mousePlaneHit = GeometryUtil.LinePlaneIntersect(mouseRay.origin, mouseRay.direction, target.position, (transform.position - target.position).normalized); if ((target.position - mousePlaneHit).sqrMagnitude <= Mathf.Pow((handleLength * GetDistanceMultiplier()), 2)) { selectedAxis = Axis.Any; } } }
IEnumerator TransformSelected(TransformType type) { isTransforming = true; totalScaleAmount = 0; totalRotationAmount = Quaternion.identity; Vector3 originalTargetPosition = target.position; Vector3 planeNormal = (transform.position - target.position).normalized; Vector3 axis = GetSelectedAxisDirection(); Vector3 projectedAxis = Vector3.ProjectOnPlane(axis, planeNormal).normalized; Vector3 previousMousePosition = Vector3.zero; while (!Input.GetMouseButtonUp(0)) { Ray mouseRay = myCamera.ScreenPointToRay(Input.mousePosition); Vector3 mousePosition = GeometryUtil.LinePlaneIntersect(mouseRay.origin, mouseRay.direction, originalTargetPosition, planeNormal); if (previousMousePosition != Vector3.zero && mousePosition != Vector3.zero) { if (type == TransformType.Move) { float moveAmount = GeometryUtil.MagnitudeInDirection(mousePosition - previousMousePosition, projectedAxis) * moveSpeedMultiplier; target.Translate(axis * moveAmount, Space.World); } if (type == TransformType.Scale) { Vector3 projected = (selectedAxis == Axis.Any) ? transform.right : projectedAxis; float scaleAmount = GeometryUtil.MagnitudeInDirection(mousePosition - previousMousePosition, projected) * scaleSpeedMultiplier; //WARNING - There is a bug in unity 5.4 and 5.5 that causes InverseTransformDirection to be affected by scale which will break negative scaling. Not tested, but updating to 5.4.2 should fix it - https://issuetracker.unity3d.com/issues/transformdirection-and-inversetransformdirection-operations-are-affected-by-scale Vector3 localAxis = (space == TransformSpace.Local && selectedAxis != Axis.Any) ? target.InverseTransformDirection(axis) : axis; if (selectedAxis == Axis.Any) { target.localScale += (GeometryUtil.Abs(target.localScale.normalized) * scaleAmount); } else { target.localScale += (localAxis * scaleAmount); } totalScaleAmount += scaleAmount; } if (type == TransformType.Rotate) { if (selectedAxis == Axis.Any) { Vector3 rotation = transform.TransformDirection(new Vector3(Input.GetAxis("Mouse Y"), -Input.GetAxis("Mouse X"), 0)); target.Rotate(rotation * allRotateSpeedMultiplier, Space.World); totalRotationAmount *= Quaternion.Euler(rotation * allRotateSpeedMultiplier); } else { Vector3 projected = (selectedAxis == Axis.Any || GeometryUtil.IsParallel(axis, planeNormal)) ? planeNormal : Vector3.Cross(axis, planeNormal); float rotateAmount = (GeometryUtil.MagnitudeInDirection(mousePosition - previousMousePosition, projected) * rotateSpeedMultiplier) / GetDistanceMultiplier(); target.Rotate(axis, rotateAmount, Space.World); totalRotationAmount *= Quaternion.Euler(axis * rotateAmount); } } } previousMousePosition = mousePosition; yield return(null); } totalRotationAmount = Quaternion.identity; totalScaleAmount = 0; isTransforming = false; }