我在Java中创建了一个非常简单的三次贝塞尔曲线形式,以便在给定时间(t)的情况下检索点的Y值。在我的实现中,我的第一个(P1)点和最后一个(P4)点分别始终分别是(0,0)和(1,1),而我只打算操纵P1和P2。这样做的目的是创建一条可修改的曲线,用于检索一个值,该值将用于乘法和操纵其他值,例如视频游戏中的难度提升。
我已经使用P2 =(0.1,0.1)和P3 =(0.9,0.9)测试了我的实现,因此曲线实际上应该是一条直线,无论我的输入值(t)是多少,输出都应该模仿:
这是我的CubicBezier课:
@AllArgsConstructor
public class CubicBezier {
private static final Point P1 = new Point(0, 0);
private static final Point P4 = new Point(1, 1);
private Point p2;
private Point p3;
public double getValue(double t) {
double dt = 1d - t;
double dt2 = dt*dt;
double t2 = t*t;
Point temp = p2.copy();
return P1.copy()
.scale(dt2 * dt)
.add(temp.scale(3 * dt2 * t))
.add(temp.set(p3).scale(3 * dt * t2))
.add(temp.set(P4).scale(t2 * t))
.getY();
}
}
和我的Point类:
@Data
@AllArgsConstructor
public class Point {
private double x;
private double y;
public Point(Point point) {
this.x = point.x;
this.y = point.y;
}
public Point copy() {
return new Point(this);
}
public Point set(Point point) {
this.x = point.x;
this.y = point.y;
return this;
}
public Point add(double scalar) {
this.x += scalar;
this.y += scalar;
return this;
}
public Point add(double x, double y) {
this.x += x;
this.y += y;
return this;
}
public Point add(Point point) {
return add(point.x, point.y);
}
public Point scale(double scalar) {
this.x *= scalar;
this.y *= scalar;
return this;
}
public Point scale(double x, double y) {
this.x *= x;
this.y *= y;
return this;
}
public Point scale(Point point) {
return scale(point.x, point.y);
}
}
我的主要方法:
public static void main(String[] args) {
CubicBezier bezier = new CubicBezier(new Point(0.1d, 0.1d), new Point(0.9d, 0.9d));
double value = 0.4;
System.out.println(value + ": " + bezier.getValue(value));
}
预期的输出应该是:
0.4: 0.4
但是,我收到的输出是:
0.4: 0.36640000000000006
而且我不明白为什么。我的getValue
方法是使用Cubic Bézier explicit form specified on Wikipedia建模的。我想念什么吗?
注意:我正在使用Lombok删除一些样板。如果需要,我可以指定此样板。
编辑:
[因此,看来我的贝塞尔曲线实际上正在按预期方式工作,并且我一直误以为t
作为x
轴上的值,假设计算出的贝塞尔曲线的y
值为相对于x
轴。我想要的功能是,给定结果曲线,给定值x
,并返回y
值。因此,在上面的屏幕截图中,曲线是一条直线,x
应该等于y
。
您可能会在浮点运算中失去精度。
尝试使用BigDecimal
代替double
。
我想出了我问题的答案。我的代码从来没有任何错误,错误是缺乏理解。我假设因为P1
,p2
,p3
和P4
都是在x和y轴上都位于0和1之间的直线上的点,所以无论它们位于该位置上线,时间将相同地反映进度,即x
等于y
。
但是,由于p2
和p3
分别更接近P0
和P4
,所以沿曲线的进度相对于时间伸展开了。
为了使三次贝塞尔曲线具有与时间(y
)值相同的级数(t
),其中P1 = (0, 0)
和P4 = (1, 1)
的两个内点都必须沿曲线均匀分布轴。因此,p2
必须为(0.33333, 0.33333)
,p3
必须为(0.66666, 0.66666)
。
this video here中显示了此问题的示例。当这些点分开时,结果值会受到影响。