【问题标题】:How to calculate normal or tanget for B-Spline如何计算 B 样条曲线的法线或切线
【发布时间】:2023-02-13 21:37:28
【问题描述】:

我有一个样条插值公式。 UE4 -> UnrealMathUtility.h

template< class T, class U > 
static FORCEINLINE_DEBUGGABLE T CubicInterp( const T& P0, const T& T0, const T& P1, const T& T1, const U& A )
{
    const float A2 = A  * A;
    const float A3 = A2 * A;

    return (T)(((2*A3)-(3*A2)+1) * P0) + ((A3-(2*A2)+A) * T0) + ((A3-A2) * T1) + (((-2*A3)+(3*A2)) * P1);
}

P0\P1 - 起点/终点 T0\T1 - 开始/结束切线

如何计算每个点的法线?

【问题讨论】:

    标签: spline


    【解决方案1】:

    曲线上一点的法线表示垂直于该点曲线的方向。要计算法线,需要找到曲线的导数,然后找到垂直于导数的单位向量。

    在三次曲线的情况下,曲线由一组四个控制点 P0、T0、P1 和 T1 以及参数“A”定义。计算法线首先需要求曲线对“A”的导数,然后将结果归一化得到单位向量。

    以下是如何计算曲线上某个点的法线的示例:

    求曲线关于“A”的导数。为此,您需要对 CubicInterp 的等式中的每一项求导关于“A”,然后简化结果。

    将结果归一化以获得单位向量。您可以通过将导数除以其大小来完成此操作,您可以将其计算为导数与其自身的点积的平方根。

    template< class T, class U >
    static FORCEINLINE_DEBUGGABLE T CubicSplineNormal( const T& P0, const T& T0, const T& P1, const T& T1, const U& A )
    {
        const float A2 = A  * A;
        
        T tangent = (T)((3*A2-2*A+1) * P0) + ((3*A-2*A2) * T0) + ((A3-A2) * T1) + ((-3*A2+A) * P1);
        tangent = normalize(tangent);
        T normal = cross(tangent, T(0, 0, 1));
        return normal;
    }
    
    vector<T> CalculateNormals(const vector<T>& controlPoints, int numSegments)
    {
        vector<T> normals;
        for (int i = 0; i < controlPoints.size() - 3; i += 3)
        {
            T P0 = controlPoints[i];
            T T0 = controlPoints[i + 1];
            T P1 = controlPoints[i + 2];
            T T1 = controlPoints[i + 3];
    
            float step = 1.0f / numSegments;
            for (int j = 0; j < numSegments; ++j)
            {
                float A = j * step;
                normals.push_back(CubicSplineNormal(P0, T0, P1, T1, A));
            }
        }
        return normals;
    }
    

    在这段代码中,'控制点'是包含样条曲线控制点的向量,并且'numSegments'是将样条划分成的段数。这'计算法线'函数将样条拆分为'numSegments'段,并使用以下方法计算沿每个段的每个点的法线'CubicSplineNormal'功能。结果存储在'法线'向量并由函数返回。

    【讨论】: