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

OpenGL单圆角矩形渲染:解决大半径裁剪异常问题

单个圆角矩形的OpenGL渲染优化问题

我尝试在OpenGL中渲染仅单个角为圆角的矩形,已在Shadertoy上实现了基础着色器,但当圆角半径超过矩形宽度/高度的一半时会出现裁剪问题。现有代码如下:

const vec4 color = vec4(1);

const vec2 half_size = vec2(150.0, 100.0);

const float radius = 20.0;

// from iquilezles.org/articles/distfunctions
float roundedBoxSDF(vec2 center, vec2 size, float radius) {
    radius = (center.x < 0.0 && center.y > 0.0) ? radius : 0.0;
    vec2 q = abs(center) - size + radius;
    return min(max(q.x,q.y),0.0) + length(max(q,0.0)) - radius;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
    vec2 center = (fragCoord - iResolution.xy / 2.0);
    float distance = roundedBoxSDF(center, half_size, radius);
    float smoothedAlpha =  1.0 - smoothstep(-1.0, 1.0, distance);
    fragColor = mix(vec4(0), color, smoothedAlpha);
}

问题核心是当前SDF实现中,针对单个圆角的半径逻辑会在半径过大时导致裁剪异常,想知道更优的SDF实现方式,以及对比先渲染矩形再用模板缓冲的方案是否更合适。


一、优化SDF实现(避免裁剪问题)

当前代码的问题在于动态修改radius的时机不对——在计算SDF前才给圆角区域设radius,会导致当radius超过矩形半宽/半高时,SDF计算逻辑出现矛盾。正确的做法是:先对目标圆角区域单独处理,再和矩形的SDF合并,而非直接修改全局radius。

优化后的SDF函数如下:

float singleRoundedCornerBoxSDF(vec2 center, vec2 halfSize, float radius) {
    // 计算基础矩形的SDF
    vec2 boxDist = abs(center) - halfSize;
    float boxSDF = min(max(boxDist.x, boxDist.y), 0.0) + length(max(boxDist, 0.0));
    
    // 针对目标圆角区域(左上,对应center.x < 0 && center.y > 0)单独处理
    bool isTargetCorner = center.x < 0.0 && center.y > 0.0;
    if (isTargetCorner) {
        // 将该角落坐标转换到以圆角圆心为原点的坐标系
        vec2 cornerPos = center + vec2(halfSize.x, -halfSize.y);
        float cornerDist = length(cornerPos) - radius;
        // 取矩形SDF和圆角SDF的最大值(相当于取两者的交集)
        return max(boxSDF, cornerDist);
    }
    
    return boxSDF;
}

优化逻辑说明:

  • 先计算完整矩形的SDF,保证基础形状正确;
  • 仅对目标圆角区域,额外计算该角落的圆形SDF,通过max()取两者交集——既保留矩形其他直角,又让目标角落被圆形裁剪成圆角;
  • 无论radius多大(合理范围为不超过半宽、半高中的较小值),都不会出现裁剪异常,因为圆形SDF独立于矩形基础SDF计算。

只需将原代码中的roundedBoxSDF替换为这个函数,其余逻辑保持不变即可。


二、模板缓冲方案的对比

模板缓冲方案的思路是:

  1. 先渲染一个带圆角的小四边形(仅目标角落的圆角区域)到模板缓冲;
  2. 再渲染完整矩形,仅在模板缓冲标记过的区域绘制圆角,其他区域正常绘制直角。

优缺点对比:

  • SDF方案优势:
    • 纯着色器实现,无需额外几何绘制和模板缓冲操作,逻辑简洁;
    • 可无缝支持抗锯齿(通过smoothstep),无需额外处理;
    • 方便动态修改圆角半径、矩形尺寸或目标圆角位置,仅需修改着色器参数。
  • 模板缓冲方案优势:
    • 批量渲染大量相同圆角的矩形时,性能可能略高(现代GPU下差异极小);
    • 适合需要混合纹理、复杂材质的场景,无需在着色器中处理形状逻辑。

结论:

如果是单个/少量动态的单圆角矩形,SDF方案更合适,代码维护和灵活性更好;如果是大量静态单圆角矩形且需要复杂材质,可考虑模板缓冲方案,但整体收益不大。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 04:15:39