椭圆的线宽不是常数
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
我还没有测试过这个,但我很确定它很接近。这是您正在使用的几何图形:
--
编辑:
所以我上面给出的 P1
和 P2
的值是垂直于椭圆的线段的端点。如果您真的想继续按照原来的方式更改 radiusX
和 radiusY
值,您可以这样做。您只需要计算出每个角度的 'Not w' 长度,并使用该值的一半代替 radiusX +/- halfWidth
和 radiusY +/- halfwidth
中的 halfWidth
。我把那部分几何留作 reader.
的练习
我正在使用 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
我还没有测试过这个,但我很确定它很接近。这是您正在使用的几何图形:
-- 编辑:
所以我上面给出的 P1
和 P2
的值是垂直于椭圆的线段的端点。如果您真的想继续按照原来的方式更改 radiusX
和 radiusY
值,您可以这样做。您只需要计算出每个角度的 'Not w' 长度,并使用该值的一半代替 radiusX +/- halfWidth
和 radiusY +/- halfwidth
中的 halfWidth
。我把那部分几何留作 reader.