我一直在寻找一个解决方案已经有一段时间了,并且已经有很多元素可以使用但不是真的如何将它们拼凑在一起。
目标:为玩家的船划出一条踪迹。
到目前为止:由于船的方向不可预测,我只有玩家船的先前位置可以使用。为了绘制轨迹,我可以简单地在播放器的先前位置绘制一个像素(或纹理),但这是内存昂贵且不会绘制曲线,它不会实现令人愉悦的眼睛弯曲效果。
我一直在寻找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个曲线。
我该怎么办?有什么建议吗?
我还是这类东西的初学者!
我从以下几个方面得到了所有这些:
答案 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
通过这个我已经达到了这个效果,它几乎不可见,但它会产生效果。