【发布时间】:2018-11-01 08:00:20
【问题描述】:
我正在使用从here 获得的以下代码创建贝塞尔曲线。我还制作了一个BezierPair 游戏对象,它有两条贝塞尔曲线作为子对象。
从下面的相应图像和 BezierPair 中,points[0]...points[3] 表示为 P0...P3:
- 我希望每条贝塞尔曲线的
P0在移动一条时始终保持不变。换句话说,我希望它们始终一起移动,并且可以选择关闭此移动。
- 说
P1两条曲线是分开的。如何使每条曲线的P1沿相同方向移动相同距离?
- 说
P2两条曲线是分开的。如何沿着连接P0和P3的线制作一条曲线的P2P2的另一条曲线?请注意,镜像线将取自下例中的曲线 1,因为curve1的P2已移动。如果curve2的P2被移动,那么镜像线将从curve2的P0P3中取出。
我不想在运行时这样做。所以必须使用自定义编辑器。 我尝试在下面的代码中解决 1. 但如果没有在层次结构窗口中选择 BezierPair,第二条曲线的位置不会更新
贝塞尔曲线:
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");
}
}
BezierPairEditor:
[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();
}
}
【问题讨论】:
-
3d 还是 2d 需要它?
-
@RodrigoRodrigues 我在 2d 中需要它
-
@Bane,有什么适合你的答案吗?
-
@RodrigoRodrigues 我刚刚更新了问题