【问题标题】:Why is my bezier curve implementation biased?为什么我的贝塞尔曲线实现有偏差?
【发布时间】:2014-12-12 12:55:50
【问题描述】:

我想用 C++ 渲染贝塞尔曲线,所以我开始自己实现它。目前,它不必非常有效。我的代码以某种方式产生了接近的结果,但这些曲线并不准确。 (dvec2 是两个双精度值的向量。)

list<dvec2> bezier(list<dvec2> const &points, int resolution)
{
    list<dvec2> samples;
    double step = 1.0 / resolution;
    for (double time = 0.0; time <= 1.0; time += step) {
        list<dvec2> sliders = points;
        while (sliders.size() > 1)
            sliders = slide(sliders, time);
        samples.push_back(sliders.front());
    }
    return samples;
}

list<dvec2> slide(list<dvec2> const &points, double time)
{
    list<dvec2> result;
    auto current = points.begin();
    dvec2 last = *current;
    for (++current; current != points.end(); ++current)
        result.push_back(last * time + *current * (1.0 - time));
    return result;
}

目前,我根据时间 t,通过将第一个与第二个、第二个与第三个进行插值,从曲线创建 n-1 个点。然后,我用相同的算法再次减少这组新的点,直到剩下一个可以绘制的点。我认为这种方法应该可行。

在渲染图像上,您可以在多条渲染曲线上看到算法结果。

例如,在图像的左下角,我认为两条相对的曲线应该是对称的。我的偏向于方向。此外,那些完全封闭的曲线应该至少在 t=0.5 的中心画一个点。这是什么原因造成的?

【问题讨论】:

  • 在阅读您的代码时,您使用非常量引用的事实非常烦人并且让我很困惑。我确定你正在改变函数中的列表,但实际上你没有......你使用列表而不是向量是否有原因?几乎在每个用例场景中,列表都会变慢。
  • @leemes 感谢您的建议,我会添加它们。

标签: c++ bezier


【解决方案1】:

您的方法应该有效。您稍有疏忽:在 slide() 内,您不会在循环中更新 last

试试:

for (++current; current != points.end(); ++current) {
    result.push_back(last * time + *current * (1.0 - time));
    last = *current; // <--
}

请注意,贝塞尔曲线的不同解释可以通过对这些产品求和来给出:

(来源:wikipedia

一些术语与这些参数曲线相关联。我们有

多项式在哪里

被称为 n 次的 Bernstein 基多项式。

在这里,您需要(预先计算的)二项式系数,并且通过使用 std::pow 函数,您最终会得到一个循环而不是两个嵌套循环(考虑到 n 受练习,使预计算成为可能)。

【讨论】:

  • 谢谢,现在可以使用了。是的,我稍后会优化它,因为目前我不知道如何计算系数。
  • @danijar 你想支持任意数量的控制点的贝塞尔曲线吗?如果您可以限制它们(假设为 20),我建议使用预先计算的二项式系数表。将二项式系数函数写为 constexpr 函数,因此它是在编译时计算的。如果您不想限制它们,可以执行以下技巧:如果有更多点 (n),则减少它们中的每一个 20 以获得n-20 点的列表。然后重复。所以最后它仍然是两个循环,但不太可能需要在外循环上进行一次以上的迭代。我希望这个解释有所帮助。
  • 啊,好吧,我明白了。那么系数很容易。我只需要最多 8 个点的曲线,所以没问题。我如何将时间包括在计算中?
  • 啊抱歉,公式中的术语bi,n(t) 不仅仅是 系数,而是使用它们和时间的函数。这里有解释:en.wikipedia.org/wiki/B%C3%A9zier_curve#Terminology——也许最终它并不比你的逐步减少更好,因为它使用功率:bi,n(t) = B(n,i) * t^i * (1-t)^(n-i)。其中B(n,i) 是系数,^ 表示功率。
  • 好的,谢谢你的解释,我现在明白公式了。但是,当前的实现速度足以满足我的需求。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-03-10
  • 1970-01-01
  • 2014-11-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-04
  • 1970-01-01
相关资源
最近更新 更多