2014-06-26 97 views
2

我一直在尋找解決方案,現在已經有很多元素可以使用,但不是真的如何將它們拼湊在一起。繪製船的二維蹤跡。 XNA

目標:爲玩家的船舶畫一條小徑。

到目前爲止:由於船的方向是不可預測的,我只有玩家船的以前的位置才能使用。爲了繪製軌跡,我可以簡單地在播放器的前一個位置繪製一個像素(或紋理),但這是昂貴的內存,並且不繪製曲線,它不會達到令人滿意的眼睛彎曲效果。

我一直在尋找Beziers Paths和Cathmull Rom的解決方案。

現在我可以得到給定點的控制點,然後從2點和2個控制點計算出一條曲線,從這裏我用一個點之間的距離製作一個VertexPositionColor數組,從曲線中製作一條triangleStrip。

這些是主要的功能我到目前爲止:

 public Vector2[] GetControlPoints(Vector2 p0, Vector2 p1, Vector2 p2, float tension = 0.5f) 
     { 
      // get length of lines [p0-p1] and [p1-p2] 
      float d01 = Vector2.Distance(p0, p1); 
      float d12 = Vector2.Distance(p1, p2); 
      // calculate scaling factors as fractions of total 
      float sa = tension * d01/(d01 + d12); 
      float sb = tension * d12/(d01 + d12); 
      // left control point 
      float c1x = p1.X - sa * (p2.X - p0.X); 
      float c1y = p1.Y - sa * (p2.Y - p0.Y); 
      // right control point 
      float c2x = p1.X + sb * (p2.X - p0.X); 
      float c2y = p1.Y + sb * (p2.Y - p0.Y); 
      return new Vector2[] {new Vector2(c1x, c1y), new Vector2(c2x, c2y) }; 
     } 

     // Given 2 points and 2 control points 
     public static VertexPositionColor[] bezierCurve(Vector2 start, Vector2 end, Vector2 c1, Vector2 c2) 
     { 
      VertexPositionColor[] points = new VertexPositionColor[SUBDIVISIONS + 2]; 

      float fraction; 

      for (int i = 0; i < SUBDIVISIONS + 2; i++) 
      { 
       fraction = i * (1f/(float)SUBDIVISIONS); 
       points[i] = new VertexPositionColor(new Vector3((float)((start.X * Math.Pow((1 - fraction), 3)) 
        +(c1.X * 3 * fraction * Math.Pow(1-fraction, 2)) 
        +(c2.X * 3 * Math.Pow(fraction,2) * (1-fraction)) 
        +(end.X * Math.Pow(fraction,3))), 

        (float)((start.Y * Math.Pow((1 - fraction), 3)) 
        + (c1.Y * 3 * fraction * Math.Pow(1 - fraction, 2)) 
        + (c2.Y * 3 * Math.Pow(fraction, 2) * (1 - fraction)) 
        + (end.Y * Math.Pow(fraction, 3))), 0), UNLIT); 
      } 

      return points; 
     } 

     /* 
     * This function treats the curve as a series of straight lines and calculates points on a line perpendicular to each point, resulting in two points THICKNESS appart. 
     * Requires THICKNESS to be set 
     */ 
     public static VertexPositionColor[] curveToStrip(VertexPositionColor[] curve) 
     { 
      VertexPositionColor[] strip = new VertexPositionColor[curve.Length * 2]; 
      VertexPositionColor[] new1 = new VertexPositionColor[curve.Length]; 
      VertexPositionColor[] new2 = new VertexPositionColor[curve.Length]; 

      for (int i = 0; i < curve.Length; i++) 
      { 
       if (i < curve.Length-1) 
       { 
        Vector2 p1 = new Vector2(curve[i].Position.X, curve[i].Position.Y); 
        Vector2 p2 = new Vector2(curve[i + 1].Position.X, curve[i + 1].Position.Y); 
        Vector2 perpPoint = perpendicularPoint(p1, p2); 

        new1[i] = new VertexPositionColor(new Vector3(distanceToPoint(p1, perpPoint, THICKNESS/2), 0), UNLIT); 
        new2[i] = new VertexPositionColor(new Vector3(distanceToPoint(p1, perpPoint, -1 * THICKNESS/2), 0), UNLIT); 
       } 
       else 
       { 
        Vector2 p1 = new Vector2(curve[i].Position.X, curve[i].Position.Y); 
        Vector2 p2 = new Vector2(curve[i - 1].Position.X, curve[i - 1].Position.Y); 
        Vector2 perpPoint = perpendicularPoint(p1, p2); 

        new1[i] = new VertexPositionColor(new Vector3(distanceToPoint(p1, perpPoint, -1 * THICKNESS/2), 0), UNLIT); 
        new2[i] = new VertexPositionColor(new Vector3(distanceToPoint(p1, perpPoint, THICKNESS/2), 0), UNLIT); 
       } 
      } 

我想過呼籲牌階段的功能,但是這似乎非常昂貴只是爲了一個小曲線,畫一個更大的貝濟耶路我想象它更糟。由於我在每一幀都會得到一個點,每個函數都會被調用來計算點之間的曲線,以繪製3個像素(或更少)的1條曲線。

我該怎麼辦?有什麼建議麼?

我還是這種東西的初學者!

這一切,我從幾個渠道獲得:

CathmullRom

Beziers and Triangle strip

+0

有趣的問題。出於好奇,你的船會留下什麼樣的蹤跡(煙霧,光線等)?如果是煙霧,那麼您可以在當前位置(每幀)部署n煙霧量,然後可以隨着時間的推移而逐漸消失,而無需Beziers Paths或Cathmull Rom。 – user3256944

+0

@ user3256944是的,這是我一直在考慮的選擇之一。但是我希望這能起作用,如果過了一段時間,我不會嘗試一些其他的效果,比如你建議的煙霧效果不應該那麼難。我也想學習如何有效地與beziers和cathmull ROM使用三角形標籤:) – Joze

回答

0

的一種方式可能是您創建路徑/粒子的列表,你初始化每幀或多少上你喜歡。我會嘗試在下面的僞代碼中解釋。我還爲每個軌跡旋轉了一下,並使用了不同大小和顏色的煙霧紋理,並在init中添加了一些+5像素。

class Trail 
    position as vector2d 
    duration as single 
    velocity as vector2d 
    fade as integer = 1 
    active = true 
end class 

class Trails 
    inherits list of Trail 
    sub Init(position as vector2d, velocity as vector2d) 
     // add trail to list 
    end sub 
    sub Update() 
     for each trail in me.findAll(function(c) c.active)) 
      position += velocity 
      fade -= .05 // or some value 
     end for 
     me.removeAll(function(c) not(c.active)) // remove from list when unused 
    end sub 
    sub Draw() 
     for each trail in me.findAll(function(c) c.active)) 
      draw(smokeTexture, position, size, rotate, color * trail.fade) 
     end for 
    end sub 
end class 

這個我已經實現了這個效果,這是幾乎看不見,但它給人的效果。

enter image description here

+0

非常感謝Davor的答案,但這並不是真的我要找的效果,因爲這種方法對於直線效果很好,但它會看起來很粗糙的曲線等。 – Joze

1

http://www.imagehosting.cz/images/trails.gif

我只是簡單介紹一下這是如何工作:

這是接收位置的功能,它是你想添加線索的下一個片段時調用。

函數被調用時,它在位置上添加兩個頂點,查看上一步的切線矢量,根據路徑寬度創建法線矢量到當前位置並沿着該法線放置頂點。

接下來,它看起來在前兩個頂點,並根據當前和前一個切線的平均值對齊它們,從而創建梯形。

我建議離開GPU計算衰落(有效使用GPU粒子的方法)。

如果您在調用更新軌跡時知道對象的速度矢量,則可以使用它來優化該算法。使用動態頂點緩衝區可能是不言而喻的(只需使用您自己的頂點格式,其中包括創建頂點時的當前時間,以便您可以在GPU上淡化它)。

+0

你有一些示例代碼來說明你的意思嗎?你展示的GIF *正是*我正在尋找的東西。 – Joze