IEnumerator TransformSelected(TransformType type) { isTransforming = true; totalScaleAmount = 0; totalRotationAmount = Quaternion.identity; Vector3 originalPivot = pivotPoint; Vector3 planeNormal = (transform.position - originalPivot).normalized; Vector3 axis = GetNearAxisDirection(); Vector3 projectedAxis = Vector3.ProjectOnPlane(axis, planeNormal).normalized; Vector3 previousMousePosition = Vector3.zero; List <ICommand> transformCommands = new List <ICommand>(); for (int i = 0; i < targetRootsOrdered.Count; i++) { transformCommands.Add(new TransformCommand(this, targetRootsOrdered[i])); } while (!Input.GetMouseButtonUp(0)) { Ray mouseRay = myCamera.ScreenPointToRay(Input.mousePosition); Vector3 mousePosition = Geometry.LinePlaneIntersect(mouseRay.origin, mouseRay.direction, originalPivot, planeNormal); if (previousMousePosition != Vector3.zero && mousePosition != Vector3.zero) { if (type == TransformType.Move) { float moveAmount = ExtVector3.MagnitudeInDirection(mousePosition - previousMousePosition, projectedAxis) * moveSpeedMultiplier; Vector3 movement = axis * moveAmount; for (int i = 0; i < targetRootsOrdered.Count; i++) { Transform target = targetRootsOrdered[i]; target.Translate(movement, Space.World); } SetPivotPointOffset(movement); } else if (type == TransformType.Scale) { Vector3 projected = (nearAxis == Axis.Any) ? transform.right : projectedAxis; float scaleAmount = ExtVector3.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 && nearAxis != Axis.Any) ? mainTargetRoot.InverseTransformDirection(axis) : axis; Vector3 targetScaleAmount = Vector3.one; if (nearAxis == Axis.Any) { targetScaleAmount = (ExtVector3.Abs(mainTargetRoot.localScale.normalized) * scaleAmount); } else { targetScaleAmount = localAxis * scaleAmount; } for (int i = 0; i < targetRootsOrdered.Count; i++) { Transform target = targetRootsOrdered[i]; Vector3 targetScale = target.localScale + targetScaleAmount; if (pivot == TransformPivot.Pivot) { target.localScale = targetScale; } else if (pivot == TransformPivot.Center) { if (scaleType == ScaleType.FromPoint) { target.SetScaleFrom(originalPivot, targetScale); } else if (scaleType == ScaleType.FromPointOffset) { target.SetScaleFromOffset(originalPivot, targetScale); } } } totalScaleAmount += scaleAmount; } else if (type == TransformType.Rotate) { float rotateAmount = 0; Vector3 rotationAxis = axis; if (nearAxis == Axis.Any) { Vector3 rotation = transform.TransformDirection(new Vector3(Input.GetAxis("Mouse Y"), -Input.GetAxis("Mouse X"), 0)); Quaternion.Euler(rotation).ToAngleAxis(out rotateAmount, out rotationAxis); rotateAmount *= allRotateSpeedMultiplier; } else { Vector3 projected = (nearAxis == Axis.Any || ExtVector3.IsParallel(axis, planeNormal)) ? planeNormal : Vector3.Cross(axis, planeNormal); rotateAmount = (ExtVector3.MagnitudeInDirection(mousePosition - previousMousePosition, projected) * rotateSpeedMultiplier) / GetDistanceMultiplier(); } for (int i = 0; i < targetRootsOrdered.Count; i++) { Transform target = targetRootsOrdered[i]; if (pivot == TransformPivot.Pivot) { target.Rotate(rotationAxis, rotateAmount, Space.World); } else if (pivot == TransformPivot.Center) { target.RotateAround(originalPivot, rotationAxis, rotateAmount); } } totalRotationAmount *= Quaternion.Euler(rotationAxis * rotateAmount); } } previousMousePosition = mousePosition; yield return(null); } for (int i = 0; i < transformCommands.Count; i++) { ((TransformCommand)transformCommands[i]).StoreNewTransformValues(); } CommandGroup commandGroup = new CommandGroup(); commandGroup.Set(transformCommands); UndoRedoManager.Insert(commandGroup); totalRotationAmount = Quaternion.identity; totalScaleAmount = 0; isTransforming = false; SetPivotPoint(); }
IEnumerator TransformSelected(TransformType transType) { isTransforming = true; totalScaleAmount = 0; totalRotationAmount = Quaternion.identity; Vector3 originalPivot = pivotPoint; Vector3 otherAxis1, otherAxis2; Vector3 axis = GetNearAxisDirection(out otherAxis1, out otherAxis2); Vector3 planeNormal = hasTranslatingAxisPlane ? axis : (transform.position - originalPivot).normalized; Vector3 projectedAxis = Vector3.ProjectOnPlane(axis, planeNormal).normalized; Vector3 previousMousePosition = Vector3.zero; Vector3 currentSnapMovementAmount = Vector3.zero; float currentSnapRotationAmount = 0; float currentSnapScaleAmount = 0; List <ICommand> transformCommands = new List <ICommand>(); for (int i = 0; i < targetRootsOrdered.Count; i++) { transformCommands.Add(new TransformCommand(this, targetRootsOrdered[i])); } while (!Input.GetMouseButtonUp(0)) { var mouseRay = myCamera.ScreenPointToRay(Input.mousePosition); var mousePosition = Geometry.LinePlaneIntersect(mouseRay.origin, mouseRay.direction, originalPivot, planeNormal); var isSnapping = Input.GetKey(translationSnapping); if (previousMousePosition != Vector3.zero && mousePosition != Vector3.zero) { if (transType == TransformType.Move) { Vector3 movement = Vector3.zero; if (hasTranslatingAxisPlane) { movement = mousePosition - previousMousePosition; } else { float moveAmount = ExtVector3.MagnitudeInDirection(mousePosition - previousMousePosition, projectedAxis) * moveSpeedMultiplier; movement = axis * moveAmount; } if (isSnapping && movementSnap > 0) { currentSnapMovementAmount += movement; movement = Vector3.zero; if (hasTranslatingAxisPlane) { float amountInAxis1 = ExtVector3.MagnitudeInDirection(currentSnapMovementAmount, otherAxis1); float amountInAxis2 = ExtVector3.MagnitudeInDirection(currentSnapMovementAmount, otherAxis2); float snapAmount1 = CalculateSnapAmount(movementSnap, amountInAxis1, out var remainder1); float snapAmount2 = CalculateSnapAmount(movementSnap, amountInAxis2, out var remainder2); if (snapAmount1 != 0) { var snapMove = (otherAxis1 * snapAmount1); movement += snapMove; currentSnapMovementAmount -= snapMove; } if (snapAmount2 != 0) { var snapMove = (otherAxis2 * snapAmount2); movement += snapMove; currentSnapMovementAmount -= snapMove; } } else { float snapAmount = CalculateSnapAmount(movementSnap, currentSnapMovementAmount.magnitude, out var remainder); if (snapAmount != 0) { movement = currentSnapMovementAmount.normalized * snapAmount; currentSnapMovementAmount = currentSnapMovementAmount.normalized * remainder; } } } for (int i = 0; i < targetRootsOrdered.Count; i++) { Transform target = targetRootsOrdered[i]; target.Translate(movement, Space.World); } SetPivotPointOffset(movement); } else if (transType == TransformType.Scale) { Vector3 projected = (nearAxis == Axis.Any)? transform.right : projectedAxis; float scaleAmount = ExtVector3.MagnitudeInDirection(mousePosition - previousMousePosition, projected) * scaleSpeedMultiplier; if (isSnapping && scaleSnap > 0) { currentSnapScaleAmount += scaleAmount; scaleAmount = 0; float snapAmount = CalculateSnapAmount(scaleSnap, currentSnapScaleAmount, out var remainder); if (snapAmount != 0) { scaleAmount = snapAmount; currentSnapScaleAmount = remainder; } } //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 = (GetProperTransformSpace() == TransformSpace.Local && nearAxis != Axis.Any)? mainTargetRoot.InverseTransformDirection(axis) : axis; Vector3 targetScaleAmount = Vector3.one; if (nearAxis == Axis.Any) { targetScaleAmount = (ExtVector3.Abs(mainTargetRoot.localScale.normalized) * scaleAmount); } else { targetScaleAmount = localAxis * scaleAmount; } for (int i = 0; i < targetRootsOrdered.Count; i++) { Transform target = targetRootsOrdered[i]; Vector3 targetScale = target.localScale + targetScaleAmount; if (pivot == TransformPivot.Pivot) { target.localScale = targetScale; } else if (pivot == TransformPivot.Center) { if (scaleType == ScaleType.FromPoint) { target.SetScaleFrom(originalPivot, targetScale); } else if (scaleType == ScaleType.FromPointOffset) { target.SetScaleFromOffset(originalPivot, targetScale); } } } totalScaleAmount += scaleAmount; } else if (transType == TransformType.Rotate) { float rotateAmount = 0; Vector3 rotationAxis = axis; if (nearAxis == Axis.Any) { Vector3 rotation = transform.TransformDirection(new Vector3(Input.GetAxis("Mouse Y"), -Input.GetAxis("Mouse X"), 0)); Quaternion.Euler(rotation).ToAngleAxis(out rotateAmount, out rotationAxis); rotateAmount *= allRotateSpeedMultiplier; } else { if (circularRotationMethod) { float angle = Vector3.SignedAngle(previousMousePosition - originalPivot, mousePosition - originalPivot, axis); rotateAmount = angle * rotateSpeedMultiplier; } else { Vector3 projected = (nearAxis == Axis.Any || ExtVector3.IsParallel(axis, planeNormal))? planeNormal : Vector3.Cross(axis, planeNormal); rotateAmount = (ExtVector3.MagnitudeInDirection(mousePosition - previousMousePosition, projected) * (rotateSpeedMultiplier * 100f)) / GetDistanceMultiplier(); } } if (isSnapping && rotationSnap > 0) { currentSnapRotationAmount += rotateAmount; rotateAmount = 0; float snapAmount = CalculateSnapAmount(rotationSnap, currentSnapRotationAmount, out var remainder); if (snapAmount != 0) { rotateAmount = snapAmount; currentSnapRotationAmount = remainder; } } for (int i = 0; i < targetRootsOrdered.Count; i++) { Transform target = targetRootsOrdered[i]; if (pivot == TransformPivot.Pivot) { target.Rotate(rotationAxis, rotateAmount, Space.World); } else if (pivot == TransformPivot.Center) { target.RotateAround(originalPivot, rotationAxis, rotateAmount); } } totalRotationAmount *= Quaternion.Euler(rotationAxis * rotateAmount); } } previousMousePosition = mousePosition; yield return(null); } for (int i = 0; i < transformCommands.Count; i++) { ((TransformCommand)transformCommands[i]).StoreNewTransformValues(); } CommandGroup commandGroup = new CommandGroup(); commandGroup.Set(transformCommands); UndoRedoManager.Insert(commandGroup); totalRotationAmount = Quaternion.identity; totalScaleAmount = 0; isTransforming = false; SetTranslatingAxis(transformType, Axis.None); SetPivotPoint(); }