c++ - 椭圆的线宽不是常数

标签 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

最佳答案

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

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

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

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

好的,所以一个 vector 与由

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

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

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

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

-- 编辑:

因此 P1 的值和 P2我上面给出的是垂直于椭圆的线段的端点。如果你真的想继续只是改变 radiusXradiusY重视你做事的方式,你可以做到这一点。您只需要弄清楚每个角度的“Not w”长度是多少,然后使用该值的一半代替 halfWidthradiusX +/- halfWidthradiusY +/- halfwidth .我将那部分几何知识留给读者作为练习。

关于c++ - 椭圆的线宽不是常数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38986938/

相关文章:

C++ 函数指针名称在函数模板内查找

java - 如何从脸部检测特定物体并实时添加我的图像?

c++ - 如何以最快的速度加载 128 位数据并兼容 GPU (CUDA C++) 和 CPU (C++)?

c++ - 不匹配删除

c++ - 有什么办法可以避免发生堆栈粉碎时终止程序?

c++ - 如何声明实例化 `emplace()` 的 `std::set` 的返回?

c++ - 在 Visual Studio 2013 中编译静态库

c++ - std::shared_ptr<X> 是否有复制构造函数?

java - glTexImage2D 中的 ByteBuffer.wrap() 导致过多的垃圾收集

ios - 更换Vuforia中的茶壶