在GPU上绘制二次曲线

Ily*_*lya 9 algorithm bezier triangulation fragment-shader stage3d

我的任务是通过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;  
}  
Run Code Online (Sandbox Code Playgroud)

有用.但是有两个基本问题:

  1. 我不明白那个算法:(.我读过有关签名的距离场,衍生物和其他...我想了很多时间再读一遍 - 但没有结果!我的问题是:有没有人帮我解释发生了什么那个着色器(逐行(!),如果可能的话)?

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

我喜欢这种方法,每个曲线段使用一个三角形,因为不需要任何几何.而且我不需要非常粗的曲线(1-2 px非常好),但是可变厚度是个问题.有谁能够帮我?

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

[Spektre编辑]刚刚发表评论和无效答案

我计划每个曲线段使用一个三角形,类似于图片

  • 路径
  • 路径由许多三角形组成
  • 每个路径段一个(二次曲线)
  • 如果所有控制点共线(位于同一直线上)或几乎共线,如何处理这种方法的问题?

Spe*_*tre 7

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

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

    三角形放大

这种方式很快,计算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. float使用控制点创建一个2D 纹理

    • 就像是 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)
  2. 还可以创建1D颜色纹理

    • 就像是 rgba col[N]
    • x两个纹理的轴分辨率= N是贝塞尔曲线的数量
  3. 现在绘制单个四边形覆盖整个屏幕

    并且在片段着色器内部检查像素是否在任何曲线内.如果是则输出其颜色......

对于高贝塞尔曲线计数,这可能变得非常慢 N

[edit1]几乎共线控制点

对于那些我会使用四边形

四角放大

  • D,EA,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

这可以用于任何Bezier,而不仅仅是几乎共线,但它使用更大的多边形,因此性能会更慢(然后真正需要更多碎片)