3

I created a bezier curve that is drawn with handles. When I rotate the container game object the curve rotates but the anchor point and control point handles don't rotate. I suspect the problem is coming from the following lines of code in my PathEditor class. How can I fix this rotation issue?

If needed, please check here for the other classes linked to the PathEditor, I decided not to put them here to keep the question tidy.

Suspected lines within PathEditor Draw() method:

for (int i = 0; i < path.NumPoints; i++)
    {
        Vector2 newPos = Handles.FreeMoveHandle(path[i], Quaternion.identity, .1f, Vector2.zero, Handles.CylinderHandleCap);
        if (path[i] != newPos)
        {
            Undo.RecordObject(creator, "Move point");
            path.MovePoint(i, newPos);
        }
    }

PathEditor:

[CustomEditor(typeof(PathCreator))]
public class PathEditor : Editor {

PathCreator creator;
Path path;

public override void OnInspectorGUI()
{
    base.OnInspectorGUI();
    EditorGUI.BeginChangeCheck();

    bool continuousControlPoints = GUILayout.Toggle(path.isContinuous, "Set Continuous Control Points");
    if (continuousControlPoints != path.isContinuous)
    {
        Undo.RecordObject(creator, "Toggle set continuous controls");
        path.isContinuous = continuousControlPoints;
    }

    if (EditorGUI.EndChangeCheck())
    {
        SceneView.RepaintAll();
    }
}

void OnSceneGUI()
{
    Input();
    Draw();
}

void Input()
 {
    Event guiEvent = Event.current;
    Vector2 mousePos = HandleUtility.GUIPointToWorldRay(guiEvent.mousePosition).origin;

    if (guiEvent.type == EventType.MouseDown && guiEvent.button == 0 && guiEvent.shift)
    {
        Undo.RecordObject(creator, "Add segment");
        path.AddSegment(mousePos);
    }
}

void Draw()
{

     Transform handleTransform = creator.transform;
    Quaternion handleRotation = Tools.pivotRotation == PivotRotation.Local ?
        handleTransform.rotation : Quaternion.identity;

    for (int i = 0; i < path.NumSegments; i++)
    {
        Vector2[] points = path.GetPointsInSegment(i);
        Handles.color = Color.black;

        Vector2 p0 = handleTransform.TransformPoint(points[0]);
        Vector2 p1 = handleTransform.TransformPoint(points[1]);
        Vector2 p2 = handleTransform.TransformPoint(points[2]);
        Vector2 p3 = handleTransform.TransformPoint(points[3]);

        Handles.DrawLine(p1, p0);
        Handles.DrawLine(p2, p3);
        Handles.DrawBezier(p0, p3, p1, p2, Color.green, null, 2);

    }


    Handles.color = Color.red;
    for (int i = 0; i < path.NumPoints; i++)
    {
        Vector2 newPos = Handles.FreeMoveHandle(path[i], Quaternion.identity, .1f, Vector2.zero, Handles.CylinderHandleCap);
        if (path[i] != newPos)
        {
            Undo.RecordObject(creator, "Move point");
            path.MovePoint(i, newPos);
        }
    }
}

void OnEnable()
{
    creator = (PathCreator)target;
    if (creator.path == null)
    {
        creator.CreatePath();
    }
    path = creator.path;
}
}

1 Answers1

2

It looks like you are storing the points values in world coordinates. When you transform your object, those points are not aware of that and keep drawing on the same places.

Instead, store points in local coordinates and apply matrix transformation each time you draw.

EDIT do the following steps to get it working:

  1. Treat all points in Path as local coordinates (i.e. relative to the gameObject itself)
  2. In PathEditor, you should use the target's transform component to apply a transformation anytime you want to set values from path to the scene. For example, in the Input method, you should correct the mouse position like that:

    mousePos = creator.transform.InverseTransformPoint(mousePos);

In your Draw method, you are actualy calculating the correct handleTrasform matrix and the quaternion handleRotation, but you are not applying the them:

Vector2 newPos = Handles.FreeMoveHandle(path[i], Quaternion.identity, .1f, Vector2.zero, Handles.CylinderHandleCap);

Should be:

var pos = handleTransform.InverseTransformPoint(path[i]);
Vector2 newPos = Handles.FreeMoveHandle(pos, handleRotation, .1f, Vector2.zero, Handles.CylinderHandleCap);

You also could, instead, set the Handles.matrix at the start of the method and the scales will be handled automatically.

Handles.matrix = creator.transform.localToWorldMatrix;
Rodrigo Rodrigues
  • 7,545
  • 1
  • 24
  • 36