在 GPU 上绘制二次曲线

问题描述 投票:0回答:1

我的任务是通过 Stage3d (Adobe Flash) 技术渲染二次贝塞尔曲线(路径),该技术没有任何开箱即用的绘图扩展(据我所知,OpenGl 有它)。是的,有一个 Starling-Extension-Graphics,但它使用简单的方法将曲线段划分为许多直线,这为我的长曲线路径生成了很多三角形。

所以.. 有一种完美的方法可以为 Loop 和 Blinn 渲染与分辨率无关的形状。我读过 GPUGems3 文章 (gpugems3_ch25.html) 并将该片段着色器移植到 AGAL2:

二次曲线像素着色器

float4 QuadraticPS(float2 p : TEXCOORD0,  
  float4 color : COLOR0) : COLOR  
{  
  // Gradients  
   float2 px = ddx(p);  
   float2 py = ddy(p);  
  // Chain rule  
   float fx = (2*p.x)*px.x - px.y;  
   float fy = (2*p.x)*py.x - py.y;  
  // Signed distance  
   float sd = (p.x*p.x - p.y)/sqrt(fx*fx + fy*fy);  
  // Linear alpha  
   float alpha = thickness - abs(sd);  
  if (alpha > 1)       // Inside  
    color.a = 1;  
  else if (alpha < 0)  // Outside  
    clip(-1);  
  else                   
  // Near boundary  
    color.a = alpha;  
    return color;  
}  

它有效。但有两个根本问题:

  1. 我不明白那个算法:(。我读了关于有符号距离场、导数和其他...我想了很多小时并再次阅读 - 但没有结果!我的问题是:有人帮助我吗?解释一下该着色器中发生了什么(如果可能的话,逐行 (!))?

  2. 第二个问题是曲线在三角形的角处被剪裁并且具有可变的厚度。请看图片: https://monosnap.com/file/84EBOUQ1czNM5lprQ5VlnRUKP2mKmW 因此,如果我画一条路径,它看起来像这样:https://monosnap.com/file/54Zs5Xui6s3BL6lNdZRCx9ibcV2bCF

我喜欢这种方法,每个曲线段使用一个三角形,因为不需要任何几何图形。我不需要非常粗的曲线(1-2 px 就很好),但是可变的厚度是一个问题。有人可以帮助我吗?

(抱歉我的英语。这不是我的母语。)

[Spektre 编辑1]刚刚从评论和无效答案中移出

我计划为每个曲线段使用一个三角形,如图所示

  • the path
  • 路径由许多三角形组成
  • 每一条路径段(二次曲线)
  • 如果所有控制点共线(位于同一条直线上)或几乎共线,如何处理此方法的问题?
algorithm fragment-shader bezier triangulation stage3d
1个回答
13
投票

对于 3 个控制点贝塞尔曲线,我会:

  1. 使用三角形作为基元
  2. 放大控制点以包括曲线周围的区域以避免伪影

triangle enlargement

这种方式速度很快,并且从

A',B',C'
计算
A,B,C
没有问题,反之亦然。如果比例恒定(例如
scale=1.25
),则最大可用曲线
thickness<=2.0*min(|control_point-M|)*(scale-1.0)

为了更安全地放大,您可以计算所需的精确比例(例如在几何着色器中)并将其传递给顶点和片段......以上所有操作都可以通过几何着色器完成。您应该使用透明度将曲线正确连接在一起。平均中间点应该保持不变

M=A+B+C=A'+B'+C'

如果透明度不是一个选项

然后您需要更改方法,以便传递控制点和纹理内的位置。

  1. 创建一个带有控制点的 2D
    float
    纹理
  • 类似
    float pnt[9][N]
  • pnt[0,1,2][]
    是控制点
    A(x,y,z)
  • pnt[3,4,5][]
    是控制点
    B(x,y,z)
  • pnt[6,7,8][]
    是控制点
    C(x,y,z)
  1. 还创建一维颜色纹理
  • 类似
    rgba col[N]
  • 两个纹理的
    x
    轴分辨率=
    N
    是贝塞尔曲线的数量
  1. 现在绘制覆盖整个屏幕的单个四边形

并且内部片段着色器检查像素是否位于任何曲线内部。如果是,输出它的颜色...

对于大量贝塞尔曲线,这可能会变得非常慢

N

[编辑1]几乎共线的控制点

对于那些我会使用Quads

quad enlarge

  • D,E
    A,B
     周围的镜像点 
    C
  • D=C+C-A
  • E=C+C-B
  • C
    是中点
    M = (A+B+D+E)/4 = C = (A'+B'+C'+D')/4
  • A',B',C',D'
    放大
    A,B,D,E
    控制点
  • A'=C+(A -C)*scale
  • B'=C+(B -C)*scale
  • A =C+(A'-C)/scale
  • B =C+(B'-C)/scale

这可以用于任何贝塞尔曲线,不仅几乎共线,而且它使用更大的多边形,因此性能会更慢(比真正需要的片段更多)

这里有更先进/优化的 GLSL 方法,完整实现了三次贝塞尔曲线:

© www.soinside.com 2019 - 2024. All rights reserved.