获得一致的法线从3D立体贝塞尔路径 [英] Getting consistent normals from a 3D cubic bezier path

查看:328
本文介绍了获得一致的法线从3D立体贝塞尔路径的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在写一个包含BezierPoints列表的BezierPath类。每个BezierPoint有一个位置,一个inTangent和outTangent:

I'm writing a BezierPath class that contains a list of BezierPoints. Each BezierPoint has a position, an inTangent and an outTangent:

BezierPath包括获取从路径线性位置和切线功能。我的下一个步骤是对从路径获取法线提供功能

BezierPath contains functions for getting linear positions and tangents from the path. My next step is to provide functionality for getting the normals from the path.

我知道,任何给定的行3D将会有无限多个线是垂直的,所以不会是一组答案。

I'm aware that any given line in 3D is going to have an unlimited number of lines that are perpendicular, so there isn't going to be a set answer.

我的目标是为用户能够指定法线(或辊角度θ)在每一BezierPoint我将间插以获得沿路径法线。我的问题是,我不知道如何选择起点切线(又该默认的切线是什么?)。

My aim is for the user to be able to specify normals (or a roll angle?) at each BezierPoint which I will interpolate between to get normals along the path. My problem is that I don't know how to choose a starting tangent (what should the default tangent be?).

在获得首发切线我的第一次尝试是使用Unity3D方法 Quaternion.LookRotation

My first attempt at getting the starting tangents is using the Unity3D method Quaternion.LookRotation:

Quaternion lookAt = Quaternion.LookRotation(tangent);
Vector3 normal = lookAt * Vector3.up;
Handles.DrawLine(position, position + normal * 10.0f);

这将导致以下(绿线切线,蓝色是法线):

This results in the following (green lines are tangents, blue are normals):

在大多数情况下,这似乎是一个很好的基础的结果,但它看起来像有在某些方向的突然变化:

For the most part this seems like a good base result, but it looks like there are sudden changes in certain orientations:

所以我的问题是:是否有得到一致的默认法线线在3D的好办法

So my question is: Is there a good way for getting consistent default normals for lines in 3D?

谢谢, VES

推荐答案

获取正常的Bezier曲线上的点实际上是pretty的直线前进,如法线只是垂直于一个函数的切线(定向在平面中行程的曲线的方向),和Bezier曲线的正切函数的实际上只是另一个贝齐尔曲线,1阶低。让我们找到正常的三次贝塞尔曲线。一维的常规功能,用(A,B,C,D)是曲线坐标:

Getting the normal for a point on a Bezier curve is actually pretty straight forward, as normals are simply perpendicular to a function's tangent (oriented in the plane of the direction of travel for the curve), and the tangent function of a Bezier curve is actually just another Bezier curve, 1 order lower. Let's find the normal for a cubic Bezier curve. The regular function, with (a,b,c,d) being the curve coordinates in a single dimension:

function computeBezier (t,a,b,c,d) {
  return a * (1-t)³ + 3 * b * (1-t)² * t + 3 * c * (1-t) * t² + d * t³
}

注意,贝塞尔曲线是对称的,VS之间的 T 的唯一区别 1-T 是哪一端曲线重新presents开始。使用 A *(1-T)³表示曲线开始于 A 。使用 A *³t将使它开始 D 代替。

Note that Bezier curves are symmetrical, the only difference between t vs 1-t is which end of the curve represents "the start". Using a * (1-t)³ means the curve starts at a. Using a * ³t would make it start at d instead.

让我们定义一个快捷曲线坐标如下:

So let's define a quick curve with the following coordinates:

a = (-100,100,0)
b = (200,-100,100)
c = (0,100,-500)
d = (-100,-100,100)

为了获得正常的这个功能,我们首先需要衍生

In order to get the normal for this function, we first need the derivative:

function computeBezierDerivative (t,a,b,c,d) {
  a = 3*(b−a)
  b = 3*(c-b)
  c = 3*(d-c)
  return a * (1-t)² + 2 * b * (1-t) * t + 3 * c * t²
}

完成。计算的衍生物是太简单(贝塞尔曲线的一个梦幻般的属性)。

Done. Computing the derivative is stupidly simple (a fantastic property of Bezier curves).

现在,为了获得正常的,我们需要的归一化切向量在某个值 T ,并通过四分之一圈旋转。我们可以把它在相当多的方向,所以进一步的限制是,我们希望把它仅在被切向量定义的平面和切向量就在旁边,一个无限小的时间间隔分开。

Now, in order to get the normal, we need to take the normalised tangent vector at some value t, and rotate it by a quarter turn. We can turn it in quite a few directions, so a further restriction is that we want to turn it only in the plane that is defined by the tangent vector, and the tangent vector "right next to it", an infinitesimally small interval apart.

任何贝塞尔曲线的切线矢量通过采取然而,许多维度你有,然后将它们分开评估,因此对于3D曲线简单地形成:

The tangent vector for any Bezier curve is formed simply by taking however-many-dimensions you have, and evaluating them separately, so for a 3D curve:

             | computeBezierDerivative(t, x values) |    |x'|
Tangent(t) = | computeBezierDerivative(t, y values) | => |y'|
             | computeBezierDerivative(t, z values) |    |z'|

再次很简单的计算。要标准化这个载体(或事实上任何载体),我们简单地通过它的长度进行矢量划分:

Again, quite simple to compute. To normalise this vector (or in fact any vector), we simply perform a vector division by its length:

                   |x'|
NormalTangent(t) = |y'| divided by sqrt(x'² + y'² + z'²)
                   |z'|

唯一的技巧就是现在发现在旋转切向量,把切到一个正常的飞机。我们知道我们可以用另一种吨价任意接近我们想要的,并把它转换成第二个切向量差点儿在同一个点上,查找任意正确性飞机,所以让我们做到这一点:

The only trick is now to find the plane in which to rotate the tangent vector, to turn the tangent into a normal. We know we can use another t value arbitrarily close to the one we want, and turn that into a second tangent vector damn near on the same point, for finding the plane with arbitrary correctness, so let's do that:

给出原点 P 我们就来点 T'= T + E 其中的电子的是一些小的价值就像0.001 - 这一点的衍生 Q'= pointDerivati​​ce(T'),并且为了使事情更容易为我们,我们将是切向量,它开始于我们的原点 P ,这只是意味着由 PQ 三维距离移动它。尽管如此pretty的简单。

given an original point p we take a point q at t'=t+e where e is some small value like 0.001 -- this point q has a derivative q' = pointDerivatice(t'), and in order to make things easier for us, we move that tangent vector so that it starts at our original point p, which just means moving it by a 3D distance of p-q. Still pretty simple.

我们现在有两个向量,出发在同一坐标:我们真正的切线,和下一个点的切线,它是如此接近它也可能是同一个点。值得庆幸的是,由于贝塞尔曲线是如何工作的,这第二个正切的永远的相同,但略有不同,而略有不同,是我们所需要的:如果我们有两个归一化的载体,开始在同一地点,我们可以简单地通过采取叉积之间。

We now have two vectors, departing at the same coordinate: our real tangent, and the "next" point's tangent, which is so close it might as well be the same point. Thankfully, due to how Bezier curves work, this second tangent is never the same, but slightly different, and "slightly different" is all we need: If we have two normalised vectors, starting at the same point, we can find the axis over which they rotate "through each other" simply by taking the cross product between them.

订单的问题,所以我们计算的tangent₂×tangent₁,因为如果我们计算的tangent₁×tangent₂我们将计算旋转轴,导致法线在错误的方向。纠正是真的只是一个以矢量,乘以-1结尾,但为什么正确的时候,我们可以得到它的权利,这里的事实后。让我们来看看旋转的轴:

Order matters, so we compute tangent₂ × tangent₁, because if we compute tangent₁ × tangent₂ we'll be computing the rotation axis and resulting normals in the "wrong" direction. Correcting that is literally just a "take vector, multiply by -1" at the end, but why correct after the fact when we can get it right, here. Let's see those axes of rotation:

现在,我们拥有一切,我们需要:为了把我们的标准化切向量到正常的载体,我们所要做的就是转动他们了解我们只是四分之一圈中轴线。如果我们把他们的一种方式,我们得到了法线,如果我们把他们其他的,我们得到的朝后法线。

Now we have everything we need: in order to turn our normalised tangent vectors into normal vectors, all we have to do is rotate them about the axis we just found by a quarter turn. If we turn them one way, we get normals, if we turn them the other, we get backfacing normals.

旋转围绕轴线也许是费力的,但不难和四分之一圈一般都是特殊的,因为它们大大简化了数学:旋转点在我们的旋转轴 C ,旋转矩阵结果是:

Rotating about an axis is perhaps laborious, but not difficult, and the quarter turns are generally special in that they greatly simplify the maths: to rotate a point over our rotation axis c, the rotation matrix turns out to be:

    |     c₁²     c₁*c₂ - c₃  c₁*c₃ + c₂ |
R = | c₁*c₂ + c₃      c₂²     c₂*c₃ - c₁ |
    | c₁*c₃ - c₂  c₂*c₃ + c₁      c₃²    |

凡1,2和3的下标是实际上只是在x,y,和我们的矢量的z分量。所以这仍然是容易的,和所有剩下的就是矩阵旋转我们的标准化的正切值:

Where the 1, 2 and 3 subscripts are really just the x, y, and z components of our vector. So that's still easy, and all that's left is to matrix-rotate our normalised tangent:

n = R * Tangent "T"

这就是:

    | T₁ * R₁₁ + T₂ * R₁₂ + T₃ * R₁₃ |    |nx|
n = | T₁ * R₂₁ + T₂ * R₂₂ + T₃ * R₂₃ | => |ny|
    | T₁ * R₃₁ + T₂ * R₃₂ + T₃ * R₃₃ |    |nz|

和我们有正常的向量(S),我们所需要的。完美!

And we have the normal vector(s) we need. Perfect!

如果我们想内部法线,这是相同的载体,只要乘以-1:

And if we want internal normals, it's the same vector, just multiply by -1:

pretty的容易,一旦你知道的技巧!最后,因为code总是有用的这个要点是的 计划我用,以确保我说的是真话加工

Pretty easy once you know the tricks! And finally, because code is always useful this gist is the Processing program I used to make sure I was telling the truth.

这篇关于获得一致的法线从3D立体贝塞尔路径的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆