Glsl 有可能加厚二次Bé;仅使用GPU的zier曲线?

Glsl 有可能加厚二次Bé;仅使用GPU的zier曲线?,glsl,bezier,Glsl,Bezier,我在OpenGL程序中绘制了许多二次Bézier曲线。现在,这些曲线只有一个像素,是由软件生成的,因为我还处于一个相当早期的阶段,这就足以看出什么是有效的 简单地说,给定3个控制点(P0到P2),我在软件中使用t从0到1(步骤为1/8)来评估以下等式,并使用GL\u LINE\u STRIP将它们链接在一起: B(t)=(1-t)2P0+2(1-t)tP1+t2P2 其中,B,显然会产生一个二维向量 这种方法效果“足够好”,因为即使是我最大的曲线也不需要超过8个步骤就能看起来弯曲。不过,一像素的

我在OpenGL程序中绘制了许多二次Bézier曲线。现在,这些曲线只有一个像素,是由软件生成的,因为我还处于一个相当早期的阶段,这就足以看出什么是有效的

简单地说,给定3个控制点(P0到P2),我在软件中使用t从0到1(步骤为1/8)来评估以下等式,并使用
GL\u LINE\u STRIP
将它们链接在一起:

B(t)=(1-t)2P0+2(1-t)tP1+t2P2

其中,
B
,显然会产生一个二维向量

这种方法效果“足够好”,因为即使是我最大的曲线也不需要超过8个步骤就能看起来弯曲。不过,一像素的细曲线还是很难看的

我想写一个GLSL着色器,它可以接受控制点和一个统一的
厚度
变量,使曲线更厚。起初,我考虑只制作一个像素着色器,只对曲线
厚度/2
距离内的像素着色,但这样做需要求解一个三次多项式,在着色器内的三个解决方案之间进行选择看起来并不是最好的主意

然后我试着去看看其他人是否已经这样做了。我无意中发现,这些家伙展示了一种填充曲线下区域的简单方法。虽然它在这种程度上工作得很好,但我很难适应在两条束曲线之间绘制的想法

使用几何体着色器查找与单个曲线匹配的边界曲线相当容易。问题来自于碎片着色器,它应该填充整个东西。他们的方法使用插值纹理坐标来确定碎片是落在曲线上还是落在曲线下;但是我想不出一种方法来处理两条曲线(我对着色器非常陌生,不是数学专家,所以我没有弄清楚如何处理这一点并不意味着这是不可能的)

我的下一个想法是将填充曲线分割成三角形,并且只在外部部分使用Bézier片段着色器。但是为了这个,我需要在不同的点上分割内曲线和外曲线,这也意味着我必须解这个方程,这实际上不是一个选项


使用着色器绘制二次Bézier曲线是否有可行的算法?

您应该能够在您提到的论文中使用Loop和Blinn技术

基本上,您需要以两种方式在法线方向上偏移每个控制点,以获得两条曲线(内部和外部)的控制点。然后遵循Loop和Blinn第3.1节中的技术-这将分割曲线的各个部分以避免三角形重叠,然后对内部的主要部分进行三角形化(请注意,该部分需要CPU)。最后,填充这些三角形,并使用Loop和Blinn的技术(在第3节的开始和结束处)在GPU上渲染它们外部的小弯曲部分

此处介绍了一种可能适用于您的替代技术:

编辑: 啊,你甚至想避免CPU三角测量-我应该仔细阅读

您遇到的一个问题是几何体着色器和片段着色器之间的接口-几何体着色器将需要生成基本体(最有可能是三角形),然后通过片段程序对这些基本体进行单独光栅化和填充

对于厚度恒定的情况,我认为一个简单的三角测量就可以了——对所有的“曲线位”使用循环和闪烁。当两个控制三角形不相交时,这很容易。当他们这样做时,交叉点外的部分很容易。因此,唯一困难的部分是在交叉点内(应该是三角形)

在交叉点内,仅当两个控制三角形通过循环和闪烁对像素进行着色时,才需要对像素进行着色。因此片段着色器需要能够对两个三角形进行纹理查找。其中一个可以作为标准,您需要为第二组纹理坐标添加一个vec2变量,您需要为三角形的每个顶点适当地设置该变量。此外,您还需要一个统一的纹理“sampler2D”变量,然后可以通过texture2D进行采样。然后,只对满足两个控制三角形(在交点内)检查的片段进行着色


我认为这在任何情况下都有效,但我可能遗漏了一些东西。

我不知道如何准确地解决这个问题,但这很有趣。我认为您需要GPU中的每个不同处理单元:

顶点着色器
将点的法线投射到顶点着色器。让顶点着色器将点置换到bezier

几何体着色器

让几何体着色器为每个顶点创建一个额外的点

foreach (point p in bezierCurve)
    new point(p+(0,thickness,0)) // in tangent with p1-p2        
片段着色器
要使用特殊笔划绘制贝塞尔曲线,可以使用带有alpha通道的纹理。您可以检查alpha通道的值。如果为零,请剪裁像素。这样,您仍然可以使系统认为它是一条实线,而不是半透明线。您可以在alpha通道中应用一些模式

我希望这会对你有所帮助。你将不得不自己弄清楚很多事情,但我认为几何着色将加快你的贝塞尔



对于抚摸,我仍然选择创建
GL_QUAD_STRIP
和alpha通道纹理。

这部分延续了我之前的答案,但事实上是完全不同的,因为我在这个答案中弄错了几个中心内容

为了允许片段着色器仅在两条曲线之间着色,将提供两组“纹理”坐标作为可变变量,并应用循环Blinn技术

varying vec2 texCoord1,texCoord2;
varying float insideOutside;

varying vec4 col;

void main()
{   
    float f1 = texCoord1[0] * texCoord1[0] - texCoord1[1];
    float f2 = texCoord2[0] * texCoord2[0] - texCoord2[1];

    float alpha = (sign(insideOutside*f1) + 1) * (sign(-insideOutside*f2) + 1) * 0.25;
    gl_FragColor = vec4(col.rgb, col.a * alpha);
}
到目前为止,很简单。最难的部分是在几何体着色器中设置纹理坐标。Loop Blinn为控制三角形的三个顶点指定它们,并且它们
    vec2[3] tex = vec2[3]( vec2(0,0), vec2(0.5,0), vec2(1,1) );

    mat3 uvmat;
    uvmat[0] = vec3(pos2[0].x, pos2[1].x, pos2[2].x);
    uvmat[1] = vec3(pos2[0].y, pos2[1].y, pos2[2].y);
    uvmat[2] = vec3(1, 1, 1);

    mat3 uvInv = inverse(transpose(uvmat));

    vec3 uCoeffs = vec3(tex[0][0],tex[1][0],tex[2][0]) * uvInv;
    vec3 vCoeffs = vec3(tex[0][1],tex[1][1],tex[2][1]) * uvInv;

    float[3] uOther, vOther;
    for(i=0; i<3; i++) {
        uOther[i] = dot(uCoeffs,vec3(pos1[i].xy,1));
        vOther[i] = dot(vCoeffs,vec3(pos1[i].xy,1));
    }   

    insideOutside = 1;
    for(i=0; i< gl_VerticesIn; i++){
        gl_Position = gl_ModelViewProjectionMatrix * pos1[i];
        texCoord1 = tex[i];
        texCoord2 = vec2(uOther[i], vOther[i]);
        EmitVertex();
    }
    EndPrimitive();