这是我的情况:我需要在屏幕上为游戏的Gui绘制一个矩形。我并不在乎这个矩形有多大或可能有多大,我希望能够处理任何情况。我现在的操作方式是存储一个仅包含一个非常基本的四边形的VAO,然后使用制服重新绘制该四边形以每次修改它在屏幕上的大小和位置。
VAO包含4个vec4
顶点:
0, 0, 0, 0;
1, 0, 1, 0;
0, 1, 0, 1;
1, 1, 1, 1;
然后将其绘制为
GL_TRIANGLE_STRIP
。每个顶点的XY是它的位置,而ZW是它的纹理坐标*。我将当前绘制的gui元素的rect作为uniform vec4
传递给rect,它像这样偏移顶点着色器中的顶点位置:vertex.xy *= guiRect.zw;
vertex.xy += guiRect.xy;
然后将顶点从屏幕像素坐标转换为OpenGL NDC坐标:
gl_Position = vec4(((vertex.xy / screenSize) * 2) -1, 0, 1);
这会将范围从
[0, screenWidth | screenHeight]
更改为[-1, 1]
。我想做纹理包装时遇到了问题。当我想拉伸(stretch)纹理时,简单地传递
vTexCoord = vertex.zw;
是很好的,但是对于包装来说却不是。理想情况下,我想修改纹理坐标,以使屏幕上的1个像素等于gui纹理中的1像素。在这个阶段,超出[0, 1]
的纹理坐标是可以的,并且实际上正是我在寻找的东西。我计划为我的gui纹理实现纹理 map 集,但是管理适当子纹理的偏移量和边界将在片段着色器中处理-就顶点着色器而言,我们的四边形使用一个带有
[0, 1]
co的实体纹理-坐标,并相应地包装。*注意:我知道这种特殊的顶点格式对于这种特殊情况并不一定有用,我可以改用
vec2
顶点。为了方便起见,我对所有2D渲染都使用相同的顶点格式,而其他对象(即文本)实际上确实需要这些ZW组件。我将来可能会改变。TL / DR:给定屏幕的大小,纹理的大小以及四边形的位置/大小,如何计算顶点着色器中的纹理坐标,以使像素和纹素具有1:1的对应关系,用包装纸?
最佳答案
那真的是非常简单的数学运算:您只需要以某种方式关联两个空间。您已经制定了一条规则,可以执行此操作:窗口空间像素将映射到纹理像素。
假设我们同时拥有vec2 screenSize
和vec2 texSize
,它们都是以像素/纹理为单位的未归一化尺寸。
我不是100%肯定您将无法实现的目标。缺少一些内容:您实际上没有指定纹理的原点应位于何处。应该始终位于四边形的左下角吗?还是应该只是在视口的左下角令人作呕?我在这里假设是杂物,但是对于第一种情况,应该很容易进行调整。
我们现在需要的是x和y中的[-1,1] ^ 2 NDC与s和t之间的映射。我们首先将其映射到[0,1] ^ 2。如果有的话,我们可以简单地将坐标乘以screenSize/texSize
以获得所需的效果。所以最后,你得到
vec2 texcoords = ((gl_Position.xy * 0.5) + 0.5) * screenSize/texSize;
您当然已经隐式计算了
(gl_Position.xy * 0.5) + 0.5) * screenSize
,因此可以将其更改为:vec2 texcoords = vertex.xy / texSize;