计算曲面的地平线?

发布于 2024-07-13 13:58:01 字数 172 浏览 15 评论 0原文

我需要找到曲面的视觉地平线的两个点。

我有:

  • 4 个角点的 XYZ
  • 2 个弯曲边缘贝塞尔点的 XYZ

我需要计算:

  • 地平线点的 XY
  • 地平线点的 XYZ

I need to find the 2 points of the visual horizon, of a curved face.

I have:

  • XYZ of the 4 corner points
  • XYZ of the 2 curved edge bezier points

And I need to calculate either:

  • XY of the horizon points
  • XYZ of the horizon points

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

晌融 2024-07-20 13:58:01

首先,您必须将 3D 贝塞尔曲线转换为 2D。 如果我没记错的话,就像投影 3D 点进行渲染一样投影曲线就足够了。

然后你必须找到曲线的极值。

一个小方法:

将贝塞尔曲线从贝塞尔曲线表示形式转换为以下形式的多项式

  x(t) = a*t^3 + b*t^2 + c*t + d
  y(t) = e*t^3 + f*t^2 + g*t + g

  Here t is your interpolation variable that goes from 0 to 1.
  a to d are the coefficients for the curve along the x-axis
  e to g are the coefficients for the curve along the y-axis.

现在您构建曲线的第一个推导(很简单,因为它是多项式)。
这将为您提供一个二次方程。 求解这些根并丢弃 0..1 范围之外的所有根。 同样,找到根很容易,因为它只是一个二次多项式。

你怎么有一堆根。 将所有这些重新插入到原始贝塞尔曲线中,评估它们的位置,然后您将得到一堆点。 极值(如果存在)将位于这些点之中。

现在您所要做的就是搜索 y 坐标最高(或最低 - 不知道您的坐标系是什么样子)的坐标。

请注意,您可能根本得不到极值。 例如,如果您的贝塞尔曲线是一条直线,就会发生这种情况。 在这些情况下,您可能还希望在极值搜索中包含第一个和最后一个贝塞尔曲线控制点。


编辑:

您问过如何将贝塞尔曲线变成多项式。 好吧,您从正常的贝塞尔曲线方程开始:

 x(t) = x0 * (1-t)³ + 3*x1*(1-t)²*t + 3*x2*(1-t)*t² +x3*t³

(x0 到 x3 是曲线的四个控制点的 x 值)。

然后将所有项逐一相乘,并按 t 的幂对它们进行排序。 不幸的是,我没有在我正在编写的计算机上运行我的数学包,而且我懒得在纸上做:-)所以如果有人运行数学实验室,您能否编辑这个答案并添加扩展版本?

不管怎样,因为你对多项式并不真正感兴趣,而只是对它的导数感兴趣,所以事情会更容易一些。 您可以直接获得系数(此处仅显示 x):

A = 3.0f*(x[1] - x[0]);
B = 6.0f*(x[2] - 2.0f*x[1] + x[0]);
C = 3.0f*(x[3] - 3.0f*x[2] + 3.0f *x[1] - x[0]);

使用这三个值 (A、B、C),一阶导数的多项式如下所示:

  x(t) = A*t^2 + B*t + C

现在将 A、B 和 C 插入二次多项式的根求解器,并你完成了。 作为参考,我使用下面的求解器 C 代码:

int GetQuadraticRoots (float A, float B, float C, float *roots)
{
  if ((C < -FLT_EPSILON) || (C > FLT_EPSILON))
  {
    float d,p;
    // it is a cubic:
    p = B*B - 4.0f * C*A;
    d = 0.5f / C;
    if (p>=0)
    {
      p = (float) sqrt(p);
      if ((p < -FLT_EPSILON) || (p > FLT_EPSILON))
      {
        // two single roots:
        roots[0] = (-B + p)*d;
        roots[1] = (-B - p)*d;
        return 2;
      } 
      // one double root:
      roots[0] = -B*d;
      return 1;
    } else {
      // no roots:
      return 0;
    }
  } 
  // it is linear:
  if ((B < -FLT_EPSILON) || (B > FLT_EPSILON))
  {
    // one single root:
    roots[0] = -A/B;
    return 1;
  }
  // it is constant, so .. no roots.
  return 0;
}

First off you have to convert your 3D beziers to 2D. If I remember right it's sufficient to project the curves just like you project 3D points for rendering.

Afterwards you have to find the extrema of the curves.

A small HowTo:

Convert your bezier-curve from bezier representation to a polyonomial of the form

  x(t) = a*t^3 + b*t^2 + c*t + d
  y(t) = e*t^3 + f*t^2 + g*t + g

  Here t is your interpolation variable that goes from 0 to 1.
  a to d are the coefficients for the curve along the x-axis
  e to g are the coefficients for the curve along the y-axis.

Now you build the first derivation of the curve (easy as it's a polynomail).
This will give you a quadratic equation. Solve these for the roots and discard all roots that are outside the 0..1 range. Again finding the roots is easy as it's just a quadratic polynomial.

You how have a bunch of roots. Plug all these back into the original bezier curve, evaluate their position and you get a bunch of points. The extrema - if exist - will be among these points.

Now all you have to do is to search for the one with the highest (or lowest - dunno how your coordinate system looks like) y-coordinate.

Note that you may not get an extrema at all. This happends if your bezier is for example a straight line. In these cases you may want to include the first and last bezier control point in your extrema search as well.


EDIT:

You've asked how to turn the bezier into a polynomial. Well, you start with the normal bezier curve equation:

 x(t) = x0 * (1-t)³ + 3*x1*(1-t)²*t + 3*x2*(1-t)*t² +x3*t³

(x0 to x3 are the x-values of the four control-points of the curve).

Then you multiply out all terms one after another and sort them by the powers of t. Unfortunately I don't have my math package running on the computer I'm writing on, and I'm to lazy to do it on paper :-) So if anyone has mathlab running, could you please edit this answer and add the expanded version?

Anyway, since you're not really interested in the polynomial but just the derivate of it things are a bit easier. You can get the coefficients directly (here shown for x only):

A = 3.0f*(x[1] - x[0]);
B = 6.0f*(x[2] - 2.0f*x[1] + x[0]);
C = 3.0f*(x[3] - 3.0f*x[2] + 3.0f *x[1] - x[0]);

Using these three values (A,B,C) the polynomial of the first derivate looks like this:

  x(t) = A*t^2 + B*t + C

Now plug A,B and C into a root solver for quadratic polynomials and you're done. For reference I use the solver C-code below:

int GetQuadraticRoots (float A, float B, float C, float *roots)
{
  if ((C < -FLT_EPSILON) || (C > FLT_EPSILON))
  {
    float d,p;
    // it is a cubic:
    p = B*B - 4.0f * C*A;
    d = 0.5f / C;
    if (p>=0)
    {
      p = (float) sqrt(p);
      if ((p < -FLT_EPSILON) || (p > FLT_EPSILON))
      {
        // two single roots:
        roots[0] = (-B + p)*d;
        roots[1] = (-B - p)*d;
        return 2;
      } 
      // one double root:
      roots[0] = -B*d;
      return 1;
    } else {
      // no roots:
      return 0;
    }
  } 
  // it is linear:
  if ((B < -FLT_EPSILON) || (B > FLT_EPSILON))
  {
    // one single root:
    roots[0] = -A/B;
    return 1;
  }
  // it is constant, so .. no roots.
  return 0;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文