绘制船的2D轨迹。 XNA

时间:2014-06-26 15:05:00

标签: c# xna draw xna-4.0 bezier

我一直在寻找一个解决方案已经有一段时间了,并且已经有很多元素可以使用但不是真的如何将它们拼凑在一起。

目标:为玩家的船划出一条踪迹。

到目前为止:由于船的方向不可预测,我只有玩家船的先前位置可以使用。为了绘制轨迹,我可以简单地在播放器的先前位置绘制一个像素(或纹理),但这是内存昂贵且不会绘制曲线,它不会实现令人愉悦的眼睛弯曲效果。

我一直在寻找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);
                }
            }

我考虑过在绘制阶段调用函数,但这似乎非常昂贵,只是为了制作一条小曲线并画出更大的Beziers路径,我想它更糟糕。因为我会在每个帧得到一个点,所以将调用每个函数来计算点之间的曲线,以绘制3个像素(或更少)的1个曲线。

我该怎么办?有什么建议吗?

我还是这类东西的初学者!

我从以下几个方面得到了所有这些:

CathmullRom

Beziers and Triangle strip

2 个答案:

答案 0 :(得分:1)

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

我将简要解释一下这是如何工作的:

是接收位置的功能,每次想要添加下一段路径时都会调用。

调用函数时,它会在位置上添加两个顶点,查看上一步的切线向量,创建到当前位置的法线向量,并根据轨迹宽度沿顶点放置顶点。

接下来,它会查看前两个顶点并根据当前和前一个切线的平均值对齐它们,从而创建梯形。

我建议在GPU上留下衰落计算(有效地使用GPU粒子的方法)。

如果您在调用跟踪更新时知道对象的速度矢量,则可以使用它来优化该算法。动态顶点缓冲区的使用可能不用多说(只需使用您自己的顶点格式,包括当您创建这些顶点时的当前时间,以便您可以在GPU上淡化它)。

答案 1 :(得分:0)

一种方法是你可以创建一个路径/粒子列表,然后在每一帧或者你喜欢的程度上初始化它。我将尝试在下面的伪代码中解释。我还旋转了一点每条线索,并使用不同大小和颜色的烟雾纹理,并在初始化时添加了一些+ - 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