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

如何在线性帧缓冲上绘制二次Bézier曲线?

二次Bézier曲线帧缓冲绘制优化方案(针对字体渲染)

问题背景

我需要在线性帧缓冲(像素绘制)上绘制二次Bézier曲线,用于字体渲染。目前尝试了两种方法但效果不佳:

  • 基于三次Bézier曲线绘制函数改造,但曲线不够平滑;
  • 暴力遍历参数t的方式,代码如下,但线条过粗:
void quadratic_bezier_curve(const Vector2 p[3], const color_t color) {
    for (double t = 0; t < 1; t += 0.001) {
        putPixel((uint32_t) ((1 - t) * (1 - t) * p[0].x + 2 * (1 - t) * t * p[1].x + t * t * p[2].x),
                 (uint32_t) ((1 - t) * (1 - t) * p[0].y + 2 * (1 - t) * t * p[1].y + t * t * p[2].y), color);
    }
}

最优方案:中点细分法

中点细分法是针对贝塞尔曲线绘制的高效算法,尤其适合字体渲染场景——它能精准控制曲线平滑度,避免冗余像素,同时保证渲染效率。

核心思路

  1. 平坦度判断:计算曲线偏离端点连线的程度,当偏差小于1像素时,直接用直线连接端点;
  2. 曲线细分:将二次Bézier曲线拆分为两段更小的二次Bézier曲线;
  3. 递归处理:对拆分后的两段曲线重复判断与细分,直到所有段都足够平坦。

C语言实现示例

#include <math.h>
#include <stdint.h>

typedef struct {
    double x, y;
} Vector2;

typedef uint32_t color_t;

// Bresenham直线绘制(需适配你的帧缓冲putPixel接口)
void draw_line(Vector2 p0, Vector2 p1, color_t color) {
    int x0 = (int)round(p0.x), y0 = (int)round(p0.y);
    int x1 = (int)round(p1.x), y1 = (int)round(p1.y);
    int dx = abs(x1 - x0), dy = abs(y1 - y0);
    int sx = x0 < x1 ? 1 : -1;
    int sy = y0 < y1 ? 1 : -1;
    int err = dx - dy;

    while (1) {
        putPixel(x0, y0, color);
        if (x0 == x1 && y0 == y1) break;
        int e2 = 2 * err;
        if (e2 > -dy) { err -= dy; x0 += sx; }
        if (e2 < dx) { err += dx; y0 += sy; }
    }
}

// 判断曲线是否足够平坦(叉积法,偏差小于1像素)
int is_flat(Vector2 p[3]) {
    double cross = (p[1].x - p[0].x) * (p[2].y - p[0].y) - (p[1].y - p[0].y) * (p[2].x - p[0].x);
    return fabs(cross) < 0.5;
}

// 递归细分绘制二次Bézier
void quadratic_bezier_subdivide(Vector2 p[3], color_t color) {
    if (is_flat(p)) {
        draw_line(p[0], p[2], color);
        return;
    }

    // 计算细分中点
    Vector2 A = { (p[0].x + p[1].x)/2, (p[0].y + p[1].y)/2 };
    Vector2 B = { (p[1].x + p[2].x)/2, (p[1].y + p[2].y)/2 };
    Vector2 C = { (A.x + B.x)/2, (A.y + B.y)/2 };

    // 拆分左右两段曲线
    Vector2 left[3] = { p[0], A, C };
    Vector2 right[3] = { C, B, p[2] };

    quadratic_bezier_subdivide(left, color);
    quadratic_bezier_subdivide(right, color);
}

// 对外调用接口
void quadratic_bezier_curve(const Vector2 p[3], color_t color) {
    quadratic_bezier_subdivide((Vector2*)p, color);
}

适配字体渲染的优势

  • 平滑度可控:通过平坦度阈值精准控制曲线像素对齐精度,避免锯齿;
  • 效率更高:递归次数随曲线复杂度动态调整,远少于暴力遍历的固定步数;
  • 无冗余像素:仅绘制必要像素,解决暴力遍历导致的线条过粗问题;
  • 可优化空间大:可将浮点运算转为整数运算,进一步提升嵌入式/低性能环境下的渲染速度。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 13:46:28