如何创建一个像戊醇一样的插画师/photoshop,用于在Unity中创建贝塞尔曲线



我需要创建复杂的分段贝塞尔曲线,所以我想更新代码来创建类似插图画家/photoshop的笔工具贝塞尔曲线。这个视频展示了戊醇的行为。

请注意,与其创建带有前两个锚点的二次贝塞尔曲线(如视频所示(,我更喜欢三次贝塞尔曲线。

以下是我已经意识到的插图画家/photoshop笔工具的功能,这些功能是在Unity中复制所必需的。

  • 第一次点击时,所有锚点/控制点都在同一鼠标点创建(第一次点击即创建对象(

  • 当鼠标点从第一次点击(未按下(开始移动时,控制点与两个锚点重合,以创建一条直线(三次曲线(

  • 当鼠标被点击和拖动(距离第一次点击任意距离(时,控制点会远离直线,根据拖动的方向形成曲线,它们的长度也会随着拖动距离第二次点击的增加而增加。

  • 当在曲线创建期间重新选择第一个锚点时,路径应该关闭

我也不确定如何解决上述问题,但以下是我迄今为止编写的代码:

B路径:

[System.Serializable]
public class BPath
{
[SerializeField, HideInInspector]
List<Vector2> points;
[SerializeField, HideInInspector]
public bool isContinuous;
public BPath(Vector2 centre)
{
points = new List<Vector2>
{
centre+Vector2.left,
centre+Vector2.left,
centre+Vector2.left,
centre+Vector2.left
};
}
public Vector2 this[int i]
{
get
{
return points[i];
}
}
public int NumPoints
{
get
{
return points.Count;
}
}
public int NumSegments
{
get
{
return (points.Count - 4) / 3 + 1;
}
}
public void AddSegment(Vector2 anchorPos)
{
points.Add(points[points.Count - 1] * 2 - points[points.Count - 2]);
points.Add((points[points.Count - 1] + anchorPos) * .5f);
points.Add(anchorPos);
}
public Vector2[] GetPointsInSegment(int i)
{
return new Vector2[] { points[i * 3], points[i * 3 + 1], points[i * 3 + 2], points[i * 3 + 3] };
}
public void MovePoint(int i, Vector2 pos)
{
if (isContinuous)
{
Vector2 deltaMove = pos - points[i];
points[i] = pos;
if (i % 3 == 0)
{
if (i + 1 < points.Count)
{
points[i + 1] += deltaMove;
}
if (i - 1 >= 0)
{
points[i - 1] += deltaMove;
}
}
else
{
bool nextPointIsAnchor = (i + 1) % 3 == 0;
int correspondingControlIndex = (nextPointIsAnchor) ? i + 2 : i - 2;
int anchorIndex = (nextPointIsAnchor) ? i + 1 : i - 1;
if (correspondingControlIndex >= 0 && correspondingControlIndex < points.Count)
{
float dst = (points[anchorIndex] - points[correspondingControlIndex]).magnitude;
Vector2 dir = (points[anchorIndex] - pos).normalized;
points[correspondingControlIndex] = points[anchorIndex] + dir * dst;
}
}
}

else {
points[i] = pos;
}
}
}

BPathCreator:

public class BPathCreator : MonoBehaviour
{
[HideInInspector]
public BPath path;

public void CreatePath()
{
path = new BPath(transform.position);
}
}

BPathEditor:

[CustomEditor(typeof(BPathCreator))]
public class BPathEditor : Editor
{
BPathCreator creator;
BPath 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()
{
for (int i = 0; i < path.NumSegments; i++)
{
Vector2[] points = path.GetPointsInSegment(i);
Handles.color = Color.black;
Handles.DrawLine(points[1], points[0]);
Handles.DrawLine(points[2], points[3]);
Handles.DrawBezier(points[0], points[3], points[1], points[2], 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 = (BPathCreator)target;
if (creator.path == null)
{
creator.CreatePath();
}
path = creator.path;
}
}

你问了很多问题。如果不全面实施,就很难回答这个问题。但那可能就不是你想要的了。

你提到的一些点(以及你播放的视频(表明,埃尔米特样条线可能更合适。这就是我用来创造像视频中那样的行为。

使用Unity的官方插件SpriteShape。它是开源的,支持在运行时进行修改。这将对切线(锚点(使用Photoshop行为。

最新更新