椭圆的线宽不是常数

line-width for ellipse is not constant

我正在使用 opengl 绘制空心椭圆。我使用标准椭圆公式计算 C++ 代码中的顶点。在片段着色器中,我只是为每个片段分配颜色。与曲线不那么尖锐的椭圆相比,我在屏幕上看到的椭圆在更尖锐的曲线上具有更细的线宽。那么问题来了,如何使整个椭圆参数的线宽一致呢?请看下图:

C++代码:

std::vector<float> BCCircleHelper::GetCircleLine(float centerX, float centerY, float radiusX, float radiusY, float lineWidth, int32_t segmentCount)
{
    auto vertexCount = (segmentCount + 1) * 2;
    auto floatCount = vertexCount * 3;

    std::vector<float> array(floatCount);
    const std::vector<float>& data = GetCircleData (segmentCount);
    float halfWidth = lineWidth * 0.5f;

    for (int32_t i = 0; i < segmentCount + 1; ++i)
    {
        float sin = data [i * 2];
        float cos = data [i * 2 + 1];

        array [i * 6 + 0] = centerX + sin * (radiusX - halfWidth);
        array [i * 6 + 1] = centerY + cos * (radiusY - halfWidth);

        array [i * 6 + 3] = centerX + sin * (radiusX + halfWidth);
        array [i * 6 + 4] = centerY + cos * (radiusY + halfWidth);

        array [i * 6 + 2] = 0;
        array [i * 6 + 5] = 0;
    }
    return std::move(array);
}

const std::vector<float>& BCCircleHelper::GetCircleData(int32_t segmentCount)
{
    int32_t floatCount = (segmentCount + 1) * 2;
    float segmentAngle = static_cast<float>(M_PI * 2) / segmentCount;

    std::vector<float> array(floatCount);

    for (int32_t i = 0; i < segmentCount + 1; ++i)
    {
        array[i * 2 + 0] = sin(segmentAngle * i);
        array[i * 2 + 1] = cos(segmentAngle * i);
    }

    return array;
}

瞄准这个:

问题很可能是您的片段基本上是从椭圆中心向外辐射的线段。

如果你画一条线,从椭圆的中心穿过你画的椭圆,在周长上的任何一点,你可能会说服自己那条红线所覆盖的距离实际上是宽度您所追求的(粗略地说,因为您在低空间分辨率下工作;有些像素化)。但由于这是一个椭圆,该距离并不垂直于所追踪的路径。这就是问题所在。这对圆非常有用,因为来自中心的射线总是垂直于圆。但是对于这些扁平的椭圆来说,它是非常倾斜的!

如何解决?你能在椭圆上的每个点画圆,而不是画线段吗?

如果不是,您可能需要重新计算在那个倾斜角度测量时那么厚意味着什么 - 它不再是您的线宽,可能需要一些微积分和更多三角函数。

好的,所以向量与

描述的曲线相切
c(i) = (a * cos(i), b * sin(i))

c'(i) = (- a * sin(i), b * cos(i))

(注意这不是单位向量)。与此垂直的是

c'perp = (b * cos(i), a * sin(i))

您应该能够通过计算他们的点积说服自己这是真的。

让我们计算一下 c'perp 的大小,暂时称它为 k

k = sqrt(b * b * cos(i) * cos(i) + a * a * sin(i) * sin(i))

所以我们走到椭圆 (c(i)) 上的一个点,我们想要绘制一条垂直于曲线的线段 - 这意味着我们想要添加 c'perp 的缩放版本.缩放是除以幅度(k),然后乘以你线宽的一半。所以两个端点是:

P1 = c(i) + halfWidth * c'perp / k
P2 = c(i) - halfWidth * c'perp / k

我还没有测试过这个,但我很确定它很接近。这是您正在使用的几何图形:

-- 编辑:

所以我上面给出的 P1P2 的值是垂直于椭圆的线段的端点。如果您真的想继续按照原来的方式更改 radiusXradiusY 值,您可以这样做。您只需要计算出每个角度的 'Not w' 长度,并使用该值的一半代替 radiusX +/- halfWidthradiusY +/- halfwidth 中的 halfWidth。我把那部分几何留作 reader.

的练习