椭圆的线宽不是常数

时间:2016-08-17 01:48:29

标签: c++ c++11 opengl-es opengl-es-2.0 fragment-shader

我使用opengl绘制空心椭圆。我使用标准椭圆公式计算c ++代码中的顶点。在片段着色器中,我只为每个片段指定颜色。与曲线不那么尖锐的曲线相比,我在屏幕上看到的椭圆在更锐利的曲线上具有更细的线宽。所以问题是,如何使整个椭圆参数的线宽一致?请看下面的图片: not worried about jagged edges at this point but it would be great if someone can point out technique to do anti-aliasing

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;
}

瞄准:enter image description here

1 个答案:

答案 0 :(得分:3)

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

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

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

如果没有,你可能需要重新计算在倾斜角度测量时厚度的含义 - 它不再是你的线宽,可能需要一些微积分,以及更多的三角函数。

好的,所以矢量与

描述的曲线相切
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

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

enter image description here

- 编辑:

因此,我在上面给出的P1P2的值是与椭圆垂直的线段的终点。如果您真的想继续改变radiusXradiusY值,那么您可以这样做。您只需要确定每个角度的“非W”长度,并使用此值的一半代替halfWidthradiusX +/- halfWidth中的radiusY +/- halfwidth。我把那几何几何作为练习给读者留下了。