2013-02-16 3 views
2

나는 노력하고있는 기술에 대한 명확한 설명이 필요합니다. 엔터티를 A 지점에서 B 지점으로 이동하려고 시도하지만 엔티티가 직선으로 이동하지 못하게해야합니다.XNA CatmullRom Curves

예를 들어, 엔티티가 x : 0, y : 0에 배치되어 있고 x : 50, y : 0을 가리 키기를 원한다면 엔티티가 목표로 곡선을 따라 이동하기를 원합니다. 멀리있을 최대 거리는 x : 25 y : 25이므로 X를 대상쪽으로 이동했지만 y의 대상에서 멀리 이동했습니다.

나는 스플라인, 커브 등 몇 가지 옵션을 조사했지만, 그 일을 할 것이라고 생각한 것은 CatmullRom 커브입니다. 나는 그것을 사용하는 방법을 약간 혼란 스럽습니까? 함수가 반환하는 보간법이 아닌 각 프레임에서 엔티티를 이동할 위치를 알고 싶습니다. 나는 그것을 사용하는 방법에 관해서는 불쾌감을 느낄 것입니다.

내가 놓친 것이 더 쉬운 대체 방법이 있다면, 또한 듣는 것에 감사 드리겠습니다.

편집 :

내가 곡선을 얻고있다 방법을 보여줍니다 :

아이디어는 결국 나는 즉석에서 이러한 점을 생성하지만, 난 그냥 그것을 해결하는 것을 시도하고있다

Vector2 blah = Vector2.CatmullRom(
    StartPosition, 
    new Vector2(StartPosition.X + 5, StartPosition.Y + 5), 
    new Vector2(StartPosition.X + 10, StartPosition.Y + 5), 
    /*This is the end position*/ 
    new Vector2(StartPosition.X + 15, StartPosition.Y), 0.25f); 
순간.

+0

그래서 스플라인 곡선이 생성되었지만이를 따라 일정한 속도로 움직여야합니까? – Corey

+0

@Corey 내 생각 엔 ... 내가 지금까지 한 일을 대략 보여주기 위해 질문을 편집하겠다. – Bushes

+0

@ Corey question edited – Bushes

답변

5

여러분도 알다시피, 스플라인은 길이가 다른 선분을 생성합니다. 곡선이 가늘수록 세그먼트가 짧아집니다. 이것은 디스플레이 목적으로 좋으며, 모바일을위한 경로 생성에는 그리 유용하지 않습니다.

스플라인 경로의 일정 속도 탐색에 대한 합리적인 근사값을 얻으려면 커브의 세그먼트를 따라 보간을 수행해야합니다. 이미 라인 세그먼트 집합 (Vector2.CatmullRom()에 의해 반환 된 점 쌍 사이)이 있으므로이 세그먼트를 일정한 속도로 걷는 방법이 필요합니다.

이러한 점 사이의 선으로 정의 된 경로를 따라 이동하는 점 집합과 총 거리가 주어지면 다음 (더 많거나 적은 의사 코드)은 경로를 따라 특정 거리에있는 점을 찾습니다.

Point2D WalkPath(Point2D[] path, double distance) 
{ 
    Point curr = path[0]; 
    for (int i = 1; i < path.Length; ++i) 
    { 
     double dist = Distance(curr, path[i]); 
     if (dist < distance) 
      return Interpolate(curr, path[i], distance/dist; 

     distance -= dist; 
     curr = path[i]; 
    } 
    return curr; 
} 

는 쉽게 산책 작업 중 조회 할 수 있도록 경로의 각 지점과 경로 거리를 저장 등이 속도를 위해 할 수있는 다양한 최적화가 있습니다. 이것은 경로가 복잡 해짐에 따라 더 중요 해지지만 경로가 적은 세그먼트로 인해 과도하게 발생할 가능성이 있습니다.

편집 :Here's an example 나는이 방법으로 JavaScript에서 잠시 동안했다. 그것은 개념 증명, 그래서 코드에서 너무 비판적으로 보지 않는다 : P 편집

'매듭'의 집합을 감안할 때 스플라인 생성
에 대한 자세한 내용은 포인트 - 인 점 곡선은 반드시 그 순서대로 통과하십시오 - 곡선 알고리즘에 가장 잘 맞는 것은 Catmull-Rom입니다. 단점은 C-R이 자동으로 생성하기에는 어색한 두 개의 추가 제어 지점이 필요하다는 것입니다.

나는 올바른 길잡이를 찾을 수없는 온라인 유용한 문서를 발견했다.이 문서는 경로 내의 점 집합의 위치를 ​​기반으로 일련의 제어점을 계산했다.여기 내 C# 코드는 제어 포인트를 계산하는 방법에 대해 다음과 같습니다

// Calculate control points for Point 'p1' using neighbour points 
public static Point2D[] GetControlsPoints(Point2D p0, Point2D p1, Point2D p2, double tension = 0.5) 
{ 
    // get length of lines [p0-p1] and [p1-p2] 
    double d01 = Distance(p0, p1); 
    double d12 = Distance(p1, p2); 
    // calculate scaling factors as fractions of total 
    double sa = tension * d01/(d01 + d12); 
    double sb = tension * d12/(d01 + d12); 
    // left control point 
    double c1x = p1.X - sa * (p2.X - p0.X); 
    double c1y = p1.Y - sa * (p2.Y - p0.Y); 
    // right control point 
    double c2x = p1.X + sb * (p2.X - p0.X); 
    double c2y = p1.Y + sb * (p2.Y - p0.Y); 
    // return control points 
    return new Point2D[] { new Point2D(c1x, c1y), new Point2D(c2x, c2y) }; 
} 

tension 파라미터는 곡선의 견고성을 변경하는 제어 포인트 생성을 조절한다. 값이 높을수록 커브가 커지고, 커브가 작을수록 값이 낮아집니다. 그것을 가지고 놀고 어떤 가치가 당신에게 가장 잘 맞는지보십시오.

, 우리가 노트의 쌍 사이의 곡선을 생성하는 데 사용되는 제어 점 세트 생성 할 수있는 'N'노트 (곡선상의 점)의 집합을 감안할 때 : 그래서 지금

// Generate all control points for a set of knots 
public static List<Point2D> GenerateControlPoints(List<Point2D> knots) 
{ 
    if (knots == null || knots.Count < 3) 
     return null; 
    List<Point2D> res = new List<Point2D>(); 
    // First control point is same as first knot 
    res.Add(knots.First()); 
    // generate control point pairs for each non-end knot 
    for (int i = 1; i < knots.Count - 1; ++i) 
    { 
     Point2D[] cps = GetControlsPoints(knots[i - 1], knots[i], knots[i+1]); 
     res.AddRange(cps); 
    } 
    // Last control points is same as last knot 
    res.Add(knots.Last()); 
    return res; 
} 

당신 2*(n-1) 개의 제어점 배열을 가지며,이를 사용하여 매듭 점 사이의 실제 커브 세그먼트를 생성 할 수 있습니다. 당신이 당신의 노트를 통해이 작업을 실행하면

public static Point2D LinearInterp(Point2D p0, Point2D p1, double fraction) 
{ 
    double ix = p0.X + (p1.X - p0.X) * fraction; 
    double iy = p0.Y + (p1.Y - p0.Y) * fraction; 
    return new Point2D(ix, iy); 
} 

public static Point2D BezierInterp(Point2D p0, Point2D p1, Point2D c0, Point2D c1, double fraction) 
{ 
    // calculate first-derivative, lines containing end-points for 2nd derivative 
    var t00 = LinearInterp(p0, c0, fraction); 
    var t01 = LinearInterp(c0, c1, fraction); 
    var t02 = LinearInterp(c1, p1, fraction); 
    // calculate second-derivate, line tangent to curve 
    var t10 = LinearInterp(t00, t01, fraction); 
    var t11 = LinearInterp(t01, t02, fraction); 
    // return third-derivate, point on curve 
    return LinearInterp(t10, t11, fraction); 
} 

// generate multiple points per curve segment for entire path 
public static List<Point2D> GenerateCurvePoints(List<Point2D> knots, List<Point2D> controls) 
{ 
    List<Point2D> res = new List<Point2D>(); 
    // start curve at first knot 
    res.Add(knots[0]); 
    // process each curve segment 
    for (int i = 0; i < knots.Count - 1; ++i) 
    { 
     // get knot points for this curve segment 
     Point2D p0 = knots[i]; 
     Point2D p1 = knots[i + 1]; 
     // get control points for this curve segment 
     Point2D c0 = controls[i * 2]; 
     Point2D c1 = controls[i * 2 + 1]; 
     // calculate 20 points along curve segment 
     int steps = 20; 
     for (int s = 1; s < steps; ++s) 
     { 
      double fraction = (double)s/steps; 
      res.Add(BezierInterp(p0, p1, c0, c1, fraction)); 
     } 
    } 
    return res; 
} 

당신은 지금 거리가 라인의 굴곡에 따라 따로 따로 변수 거리입니다 보간 점 세트가 있습니다. 여기에서 원래 WalkPath 방법을 반복적으로 실행하여 일정한 거리만큼 떨어져있는 점 집합을 생성합니다.이 점 집합은 일정한 속도로 곡선을 따라 휴대 전화의 진행을 정의합니다.

경로의 어느 지점에서든 휴대 기기의 제목은 어느 한 쪽의 점 사이의 각도 (대략)입니다. 경로의 모든 점 n에 대해 p[n-1]p[n+1] 사이의 각도가 머리글 각도입니다. 소수점 연산, 보간 등 - - 나는 기능을 많이 가지고 내가 나이 전에 쓴 Point2D를 클래스 사용하기 때문에

// get angle (in Radians) from p0 to p1 
public static double AngleBetween(Point2D p0, Point2D p1) 
{ 
    return Math.Atan2(p1.X - p0.X, p1.Y - p0.Y); 
} 

나는, 내 코드에서 위를 채택했습니다. 내장을 좀을 추가했을 수 버그는 번역 중에 있지만 잘하면 그들이 놀 때 쉽게 발견 할 수 있습니다.

어떻게 진행되는지 알려주세요. 어떤 어려움에 처했을 때 나는 내가 도울 수있는 것을 보게 될 것이다.

+0

좋아, 나는 일반적인 요지를 얻는다. 커브 자체의 점을 생성하는 데 다소 어려움이 있습니다. 제가 포함시킨 것들이 하나의 예입니다. 나를 가장 많이 던지고있는 것은 여행해야하는 축에 관계없이 커브를 생성하는 방법입니다. 이것을 얻기 위해 몇 가지 수학을 사용해야합니까? 내 생각 중 하나는 엔터티의 x 축을 이동하는 방향으로 회전시킨 다음 y 값을 변경하여 커브를 만드는 것입니다. 이것이 옳다면 어떻게해야합니까? – Bushes

+0

답변이 업데이트되었습니다. 매우 상세한 답변에 – Corey

+0

가 환호합니다. 나는 기회를 잡을 때 그것을 줄 것이다! – Bushes