You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在OpenTK中绘制平滑的贝塞尔曲线?

OpenTK贝塞尔曲线渲染平滑度优化问题

我在OpenTK中绘制贝塞尔曲线,已得到渲染结果,但如图所示,曲线不够平滑规整,不清楚如何实现更平滑的渲染。

渲染的贝塞尔曲线

现有代码

OnLoad 代码

float[] Vertices =
{
  -1.0f,  0.0f,
   0.0f,  1.0f,
   1.0f,  0.0f,
};

InterpolatedVertices = Interpolation.Quadratic(
  (Vertices[0], Vertices[1]),
  (Vertices[2], Vertices[3]),
  (Vertices[4], Vertices[5]),
  1000,
  0.01f
);

绘制代码

GL.DrawArrays(PrimitiveType.Points, 0 , 1000);

插值实现代码

public static (float, float) Linear((float, float) start, (float, float) end, float t)
{
  // Clamp t between 0 and 1
  t = t > 1 ? 1 : t < 0 ? 0 : t;

  // Calculate the new coordinates (Offset + (Distance * t))
  float x = MathF.Round(start.Item1 + (end.Item1 - start.Item1) * t, 2);
  float y = MathF.Round(start.Item2 + (end.Item2 - start.Item2) * t, 2);

  return (x, y);
}

public static (float, float) Quadratic((float, float) start, (float, float) controlPoint, (float, float) end, float t)
{
  // Interpolate Start and ControlPoint
  var firstInterpolated = Linear(start, controlPoint, t);

  // Interpolate ControlPoint and End
  var secondInterpolated = Linear(controlPoint, end, t);

  // Interpolate the two interpolated points
  var result = Linear(firstInterpolated, secondInterpolated, t);

  return result;
}

public static float[] Quadratic((float, float) start, (float, float) controlPoint, (float, float) end, int intensity, float t)
{
  float[] interpolatedPoints = new float[intensity * 2];
  float stride = t;

  for (int i = 0; i < intensity * 2; i += 2)
  {
    var point = Quadratic(start, controlPoint, end, stride);
    interpolatedPoints[i] = point.Item1;
    interpolatedPoints[i + 1] = point.Item2;
    stride += t;
  }

  return interpolatedPoints;
}

问题分析与解决方案

1. 精度丢失导致的台阶问题

你的Linear插值方法中使用了MathF.Round将坐标保留两位小数,这会直接丢失坐标精度,导致生成的点被强制对齐到固定的小数位,曲线出现明显的台阶状不平滑。直接去掉Round操作即可恢复坐标的高精度:

修改后的Linear方法:

public static (float, float) Linear((float, float) start, (float, float) end, float t)
{
  t = Math.Clamp(t, 0f, 1f); // 用Math.Clamp简化边界判断

  float x = start.Item1 + (end.Item1 - start.Item1) * t;
  float y = start.Item2 + (end.Item2 - start.Item2) * t;

  return (x, y);
}

2. 绘制方式导致的离散感

当前用PrimitiveType.Points绘制离散点,视觉上就是一个个点组成的曲线,自然不够平滑。改成PrimitiveType.LineStrip绘制连续线段,能让曲线看起来连贯流畅:

修改后的绘制代码:

GL.DrawArrays(PrimitiveType.LineStrip, 0, 1000);

3. 采样逻辑的累积误差

当前生成点的逻辑是每次给stride加0.01,1000次后stride会达到10.0,虽然Linear里有clamp,但这种方式会有累积误差,且无法保证t在0到1之间均匀分布。改成按索引计算t值,确保采样均匀:

修改后的Quadratic批量生成方法:

public static float[] Quadratic((float, float) start, (float, float) controlPoint, (float, float) end, int intensity)
{
  float[] interpolatedPoints = new float[intensity * 2];

  for (int i = 0; i < intensity; i++)
  {
    float t = (float)i / (intensity - 1); // 从0到1均匀采样
    var point = Quadratic(start, controlPoint, end, t);
    interpolatedPoints[i * 2] = point.Item1;
    interpolatedPoints[i * 2 + 1] = point.Item2;
  }

  return interpolatedPoints;
}

对应的OnLoad调用也要修改:

InterpolatedVertices = Interpolation.Quadratic(
  (Vertices[0], Vertices[1]),
  (Vertices[2], Vertices[3]),
  (Vertices[4], Vertices[5]),
  1000
);

总结

做完以上三点修改后,曲线的精度、连贯性都会大幅提升,渲染出来的贝塞尔曲线会更平滑规整。

内容的提问来源于stack exchange,提问作者Bartek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 09:06:20