我正在使用下面的代码创建贝塞尔曲线,我从here http://catlikecoding.com/unity/tutorials/curves-and-splines/。我也做了一个BezierPair
具有两条贝塞尔曲线作为子对象的游戏对象。
从下面的各个图像和 BezierPair 中,其中points[0]
...points[3]
表示为P0
...P3
:
- I want
P0
当移动一条贝塞尔曲线时,每条贝塞尔曲线的值始终保持不变。换句话说,我希望它们始终一起移动,并且可以选择关闭此移动。
- Say
P1
两条曲线是分开的。我怎样才能使P1
每条曲线沿相同方向移动相同距离?
- Say
P2
两条曲线是分开的。我怎样才能使P2
一个曲面镜的P2
沿着连接线的另一条曲线P0
and P3
?请注意,镜像线将从下例中的曲线 1 中获取,因为curve1
's P2
被感动了。如果curve2
's P2
移动,则镜像线将从curve2
's P0P3
.
我不想在运行时执行此操作。所以必须使用自定义编辑器。
我尝试在下面的代码中解决 1. 问题,但是如果不在层次结构窗口中选择 BezierPair,第二条曲线的位置就不会更新
Bezier:
public static class Bezier {
public static Vector3 GetPoint (Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t) {
t = Mathf.Clamp01(t);
float oneMinusT = 1f - t;
return
oneMinusT * oneMinusT * oneMinusT * p0 +
3f * oneMinusT * oneMinusT * t * p1 +
3f * oneMinusT * t * t * p2 +
t * t * t * p3;
}
public static Vector3 GetFirstDerivative (Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t) {
t = Mathf.Clamp01(t);
float oneMinusT = 1f - t;
return
3f * oneMinusT * oneMinusT * (p1 - p0) +
6f * oneMinusT * t * (p2 - p1) +
3f * t * t * (p3 - p2);
}
}
贝塞尔曲线:
[RequireComponent(typeof(LineRenderer))]
public class BezierCurve : MonoBehaviour {
public Vector3[] points;
LineRenderer lr;
public int numPoints = 49;
bool controlPointsChanged = false;
bool isMoving = false;
public void Reset () {
points = new Vector3[] {
new Vector3(1f, 0f, 0f),
new Vector3(2f, 0f, 0f),
new Vector3(3f, 0f, 0f),
new Vector3(4f, 0f, 0f)
};
}
void Start() {
lr = GetComponent<LineRenderer> ();
lr.positionCount = 0;
DrawBezierCurve ();
}
public Vector3 GetPoint (float t) {
return transform.TransformPoint(Bezier.GetPoint(points[0], points[1], points[2], points[3], t));
}
public void DrawBezierCurve () {
lr = GetComponent<LineRenderer> ();
lr.positionCount = 1;
lr.SetPosition(0, points[0]);
for (int i = 1; i < numPoints+1; i++) {
float t = i / (float)numPoints;
lr.positionCount = i+1;
lr.SetPosition(i, GetPoint(t));
}
}
public Vector3 GetVelocity (float t) {
return transform.TransformPoint(
Bezier.GetFirstDerivative(points[0], points[1], points[2], points[3], t)) - transform.position;
}
public Vector3 GetDirection (float t) {
return GetVelocity(t).normalized;
}
}
贝塞尔曲线编辑器:
[CustomEditor(typeof(BezierCurve))]
public class BezierCurveEditor : Editor {
private BezierCurve curve;
private Transform handleTransform;
private Quaternion handleRotation;
private const int lineSteps = 10;
private const float directionScale = 0.5f;
private void OnSceneGUI () {
curve = target as BezierCurve;
handleTransform = curve.transform;
handleRotation = Tools.pivotRotation == PivotRotation.Local ?
handleTransform.rotation : Quaternion.identity;
Vector3 p0 = ShowPoint(0);
Vector3 p1 = ShowPoint(1);
Vector3 p2 = ShowPoint(2);
Vector3 p3 = ShowPoint(3);
Handles.color = Color.gray;
Handles.DrawLine(p0, p1);
Handles.DrawLine(p2, p3);
Handles.DrawBezier(p0, p3, p1, p2, Color.white, null, 2f);
curve.DrawBezierCurve ();
if (GUI.changed) {
curve.DrawBezierCurve ();
EditorUtility.SetDirty( curve );
Repaint();
}
}
private void ShowDirections () {
Handles.color = Color.green;
Vector3 point = curve.GetPoint(0f);
Handles.DrawLine(point, point + curve.GetDirection(0f) * directionScale);
for (int i = 1; i <= lineSteps; i++) {
point = curve.GetPoint(i / (float)lineSteps);
Handles.DrawLine(point, point + curve.GetDirection(i / (float)lineSteps) * directionScale);
}
}
private Vector3 ShowPoint (int index) {
Vector3 point = handleTransform.TransformPoint(curve.points[index]);
EditorGUI.BeginChangeCheck();
point = Handles.DoPositionHandle(point, handleRotation);
if (EditorGUI.EndChangeCheck()) {
Undo.RecordObject(curve, "Move Point");
EditorUtility.SetDirty(curve);
curve.points[index] = handleTransform.InverseTransformPoint(point);
}
return point;
}
}
贝塞尔曲线对:
public class BezierPair : MonoBehaviour {
public GameObject bez1;
public GameObject bez2;
public void setupCurves() {
bez1 = GameObject.Find("Bez1");
bez2 = GameObject.Find("Bez2");
}
}
贝塞尔曲线对编辑器:
[CustomEditor(typeof(BezierPair))]
public class BezierPairEditor : Editor {
private BezierPair bezPair;
public override void OnInspectorGUI()
{
bezPair = target as BezierPair;
if (bezPair.bez1.GetComponent<BezierCurve>().points[0] != bezPair.bez2.GetComponent<BezierCurve>().points[0])
{
Vector3 assignPoint0 = bezPair.bez1.GetComponent<BezierCurve>().points[0];
bezPair.bez2.GetComponent<BezierCurve>().points[0] = assignPoint0;
}
if (GUI.changed)
{
EditorUtility.SetDirty(bezPair.bez1);
EditorUtility.SetDirty(bezPair.bez2);
Repaint();
}
}