我的任务是通过 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;
}
它有效。但有两个根本问题:
我不明白那个算法:(。我读了关于有符号距离场、导数和其他...我想了很多小时并再次阅读 - 但没有结果!我的问题是:有人帮助我吗?解释一下该着色器中发生了什么(如果可能的话,逐行 (!))?
第二个问题是曲线在三角形的角处被剪裁并且具有可变的厚度。请看图片: https://monosnap.com/file/84EBOUQ1czNM5lprQ5VlnRUKP2mKmW 因此,如果我画一条路径,它看起来像这样:https://monosnap.com/file/54Zs5Xui6s3BL6lNdZRCx9ibcV2bCF
我喜欢这种方法,每个曲线段使用一个三角形,因为不需要任何几何图形。我不需要非常粗的曲线(1-2 px 就很好),但是可变的厚度是一个问题。有人可以帮助我吗?
(抱歉我的英语。这不是我的母语。)
[Spektre 编辑1]刚刚从评论和无效答案中移出
我计划为每个曲线段使用一个三角形,如图所示
对于 3 个控制点贝塞尔曲线,我会:
这种方式速度很快,并且从
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'
如果透明度不是一个选项
然后您需要更改方法,以便传递控制点和纹理内的位置。
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)
rgba col[N]
x
轴分辨率=N
是贝塞尔曲线的数量并且内部片段着色器检查像素是否位于任何曲线内部。如果是,输出它的颜色...
对于大量贝塞尔曲线,这可能会变得非常慢
N
[编辑1]几乎共线的控制点
对于那些我会使用Quads
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 方法,完整实现了三次贝塞尔曲线: