使用GLSL片段着色器在四边形中间绘制纹理

我不知道这是多么可能,但我正在尝试使用片段着色器在四边形中间绘制一部分纹理。 这全是2D。 四边形由从(0,0)到(宽度,高度)的四个顶点组成。 模型视图matrix被转换以定位四边形。

我有一个32×32图标的精灵图表和一个图标被映射到的32×32四元组。 在顶点着色器中,我通过将顶点向外移动2个像素,在四边形周围创建一个2像素“边框”。 在一个片段着色器中,我想用它的原始大小来显示它的原始位置; 基本上,原来的32×32 quad和36×36 quad应该没有明显的区别。 结果应该是一个无形的“边界”。

唯一的解决scheme是计算顶点着色器中四边形角的窗口坐标,然后将其传递给片段着色器,并从gl_FragCoord中减去它,以便获得每个像素相对于角的位置的四边形。 有了这些信息,我可以在四边形的中央显示纹理,并且具有原始大小。

有没有更简单的方法来完成这个?

我现在不能尝试,但试试这个:

在顶点着色器中取gl_VertexID的值,并将其赋予平面属性中的片段着色器(平坦的,所以不能插入)。 同时将未转换的顶点(也是平坦的)和插入但未转换的顶点(非平坦)推入片段着色器。

在片段着色器中查看顶点id属性的值。 通过查看这个值,你可以找出四边形的哪一个角落。 那么你可以使用简单的if放弃边框:

 if(vertexIDAttribute indicates that we are in the top left corner && interpolatedVertex.x < uninterpolatedVertex.x + 2 && interpolatedVertex.y < uninterpolatedVertex.y + 2 || vertexIDAttribute indicates that we are in the top right corner && interpolatedVertex.x > uininterpolatedVertex.x - 2 && interpolatedVertex.y < uninterpolatedVertex.y + 2 // etc ) { discard; } else { render the fragment } 

(老答案在历史以下)


我能想到的一个解决scheme是计算边框四边形的大小与无边框四边形大小的比率,并相应地转换纹理matrix。 例如,

 // quadSize would be 32 in your case float border = 2.0f; float scale = (quadSize + border) / quadSize; glMatrixMode(GL_TEXTURE); glLoadIdentity(); glScalef(scale, scale, 1.0f); glTranslatef(-border/2, -border/2, 0.0f); glMatrixMode(GL_MODELVIEW); 

(你应该把matrix存储在某个地方,所以你不必每一帧都计算一下,如果边框尺寸保持不变,也可以预先计算)。

这正确地缩放和定位纹理。 但是,这会在纹理周围留下2像素大小的边框,您可以在片段着色器中轻松放弃该边框。 只需导出一个描述四边形矩形的制服,并检查片段是否在“边框”中。 如果是的话,丢弃片段,否则就像你以前那样渲染它。

编辑:复制/粘贴起来,它应该是(quadSize+border) / quadSize ,反之亦然。

大概最简单的方法就是让精灵独自离开,并在边缘周围添加4个额外的四边形。

但是,如果你不能添加额外的四边形,你应该可以通过操纵四边形的UV来完成。 当您将顶点推出两个像素时,同样将UV也推出两个像素。

如果你的精灵紧密地包装在一起,这可能会导致邻近的精灵片在边界可见的问题。 你可以通过存储原始的UV矩形(在2px扩展之前)并将其发送到片段着色器来修复它在着色器中。 然后检查插入的扩展UV是否落在这个矩形之外,如果是的话,丢弃像素(或用黑色replace颜色,或者在边框中做任何你想做的)。 当然,这会使着色器更昂贵。