【问题标题】:Automatic interior edges in bezier surfaces贝塞尔曲面中的自动内部边缘
【发布时间】:2014-06-19 10:19:12
【问题描述】:

通常,贝塞尔曲面用作具有 16 个控制点的双三次面片。但是,在 3dsMax 中,可以隐藏内部边缘以防止编辑和计算 automatically(这是它们的默认状态)。这样就只剩下 12 个控制点,这使得编辑更简单。

来自Primitives3D sample project 的 XNA 代码(简化版):

void CreatePatchVertices(Vector3[] patch, int tessellation)
{
    Debug.Assert(patch.Length == 16);

    for (int i = 0; i <= tessellation; i++)
    {
        float ti = (float)i / tessellation;

        for (int j = 0; j <= tessellation; j++)
        {
            float tj = (float)j / tessellation;

            // Perform four horizontal bezier interpolations
            // between the control points of this patch.
            Vector3 p1 = Bezier(patch[0], patch[1], patch[2], patch[3], ti);
            Vector3 p2 = Bezier(patch[4], patch[5], patch[6], patch[7], ti);
            Vector3 p3 = Bezier(patch[8], patch[9], patch[10], patch[11], ti);
            Vector3 p4 = Bezier(patch[12], patch[13], patch[14], patch[15], ti);

            // Perform a vertical interpolation between the results of the
            // previous horizontal interpolations, to compute the position.
            Vector3 position = Bezier(p1, p2, p3, p4, tj);

            // Perform another four bezier interpolations between the control
            // points, but this time vertically rather than horizontally.
            Vector3 q1 = Bezier(patch[0], patch[4], patch[8], patch[12], tj);
            Vector3 q2 = Bezier(patch[1], patch[5], patch[9], patch[13], tj);
            Vector3 q3 = Bezier(patch[2], patch[6], patch[10], patch[14], tj);
            Vector3 q4 = Bezier(patch[3], patch[7], patch[11], patch[15], tj);

            // Compute vertical and horizontal tangent vectors.
            Vector3 tangentA = BezierTangent(p1, p2, p3, p4, tj);
            Vector3 tangentB = BezierTangent(q1, q2, q3, q4, ti);

            // Cross the two tangent vectors to compute the normal.
            Vector3 normal = Vector3.Cross(tangentA, tangentB);
            normal.Normalize();

            // Create the vertex.
            AddVertex(position, normal);
        }
    }
}

在这个示例中,如何像在 3dsMax 中一样自动计算向量 5、6、9 和 10(patch[5] 等)?

【问题讨论】:

  • 我不知道3dsMax是做什么的,但是你试过简单的线性插值吗? patch[5] = 0.66 * patch[1] + 0.33 * patch[13]

标签: c# algorithm xna geometry bezier


【解决方案1】:

这个答案一定是多余的,但我想提醒您注意另一种构造贝塞尔曲面的方法,称为 Coons patches。 Coons 补丁明确地仅使用边界曲线,转换为双三次补丁非常简单。

我推荐这个的原因是,它被开发用于相当精确地推断汽车设计中典型的边界特征线,并自动计算内部点(对于双三次贝塞尔补丁)或镶嵌。

给定四个边界曲线bu0、bu1、bv0、bv1;

bu0, bu1  // boundaries in u direction u <- [0, 1]
bv0, bv1  // in v direction  v <- [0, 1]
// bu0, bu1, bv0, bv1 are arrays of bezier coefficients

可以通过首先独立评估 u 和 v 方向上的规则曲面以及 u 和 v 两个方向的双线性插值来评估 coons 补丁表面上的内部点和点。

// In matrix form, so that you can reduce it all together

                      ⎡        ⎤
ruled_u = [ (1-u) u ] ⎜ bv0(v) ⎟
                      ⎜ bv1(v) ⎟
                      ⎣        ⎦ 

// Similarly
                      ⎡        ⎤
ruled_v = [ (1-v) v ] ⎜ bu0(u) ⎟
                      ⎜ bu1(u) ⎟
                      ⎣        ⎦ 

// Assuming cubic bezier curves as boundary, if you select appropriate control point 
// instead of bv0(u) etc, i.e. bv0[1] for u = 1/3 and bv0[2] for u = 2/3, we can convert
// a coons patch into a bicubic patch, instead of evaluating the point on surface directly

                          ⎡               ⎤ ⎡         ⎤
bilinear_uv = [ (1-u) u ] ⎜ bu0(0) bu0(1) ⎟ ⎜ (1 - v) ⎟
                          ⎜ bu1(0) bu1(1) ⎟ ⎜    v    ⎟
                          ⎣               ⎦ ⎣         ⎦

// Then the 'interior' point at u and v is
Coons (u, v) = ruled_u + ruled_v - bilinear_uv

在浣熊斑块上,内部控制点可以计算为

Coons(1/3, 1/3)
Coons(1/3, 2/3)
Coons(2/3, 1/3)
Coons(2/3, 2/3)

在上面的等式中只选择 bv0[1] 作为 1/3 而不是 bv0(1/3) 等。

在 Coons 补丁中,插值感觉比线性插值边界控制点更自然。根据我的经验,也更“正确”。不仅在美学上而且在参数上,在镶嵌之后也是如此。

最近,我不得不在 LCH 颜色空间中生成近似 sRGB 色域的贝塞尔曲面。它只是一个变形和扭曲的 RGB 立方体。 我所拥有的只是补丁的边界。仅使用线性插值时,内部值是错误的。 最后,浣熊补丁给出的错误最少。

这是从一组 coons 补丁生成的双三次曲面的示例。

【讨论】:

    【解决方案2】:

    看起来 3ds Max 构造了一个平行四边形来获取内部点。

    patch[5] = patch[0] + (patch[1] - patch[0]) + (patch[4] - patch[0]);
    patch[5] = patch[1] + patch[4] - patch[0];
    

    以及整个功能:

    void CreatePatchVertices(Vector3[] s, int tessellation, bool isMirrored)
    {
        Debug.Assert(s.Length == 16);
    
        for (int i = 0; i <= tessellation; i++)
        {
            float ti = (float)i / tessellation;
    
            for (int j = 0; j <= tessellation; j++)
            {
                float tj = (float)j / tessellation;
    
                // Compute automatic interior edges.
                s[5] = s[1] + s[4] - s[0];
                s[6] = s[2] + s[7] - s[3];
                s[9] = s[8] + s[13] - s[12];
                s[10] = s[11] + s[14] - s[15];
    
                // Perform four horizontal bezier interpolations
                // between the control points of this patch.
                Vector3 p1 = Bezier(s[0], s[1], s[2], s[3], ti);
                Vector3 p2 = Bezier(s[4], s[5], s[6], s[7], ti);
                Vector3 p3 = Bezier(s[8], s[9], s[10], s[11], ti);
                Vector3 p4 = Bezier(s[12], s[13], s[14], s[15], ti);
    
                // Perform a vertical interpolation between the results of the
                // previous horizontal interpolations, to compute the position.
                Vector3 position = Bezier(p1, p2, p3, p4, tj);
    
                // Perform another four bezier interpolations between the control
                // points, but this time vertically rather than horizontally.
                Vector3 q1 = Bezier(s[0], s[4], s[8], s[12], tj);
                Vector3 q2 = Bezier(s[1], s[5], s[9], s[13], tj);
                Vector3 q3 = Bezier(s[2], s[6], s[10], s[14], tj);
                Vector3 q4 = Bezier(s[3], s[7], s[11], s[15], tj);
    
                // Compute vertical and horizontal tangent vectors.
                Vector3 tangentA = BezierTangent(p1, p2, p3, p4, tj);
                Vector3 tangentB = BezierTangent(q1, q2, q3, q4, ti);
    
                // Cross the two tangent vectors to compute the normal.
                Vector3 normal = Vector3.Cross(tangentA, tangentB);
                normal.Normalize();
    
                // Create the vertex.
                AddVertex(position, normal);
            }
        }
    }
    

    这是具有自动内部点的茶壶图元在 3ds Max 和 Primitives3D 示例中的样子:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-12-06
      • 2017-06-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-03
      • 1970-01-01
      相关资源
      最近更新 更多