在可变大小的四边形上包裹纹理坐标?

时间:2014-08-21 09:44:12

标签: c++ opengl user-interface textures glsl

这是我的情况:我需要在屏幕上为我的游戏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元素的矩形,我目前正在绘制uniform vec4,它会像这样偏移顶点着色器中的顶点位置:

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]


当我想做纹理包装时,我的问题出现了。当我想要拉伸纹理时,简单地传递vTexCoord = vertex.zw;就好了,但不能用于包裹。理想情况下,我想修改纹理坐标,使得屏幕上的1个像素等于gui纹理中的1个纹素。超出[0, 1]的纹理坐标在这个阶段很好,实际上正是我正在寻找的。

我计划为我的gui纹理实现纹理atlasses,但是管理相应子纹理的偏移和边界将在片段着色器中处理 - 就顶点着色器而言,我们的四边形使用一个实体纹理与[0, 1]坐标,并相应地包装。

*注意:我知道这个特殊的顶点格式对于这种特殊情况并不是非常有用,我可能会使用vec2顶点。为了方便起见,我对所有2D渲染使用相同的顶点格式,而其他对象即文本实际上确实需要那些ZW组件。我将来可能会改变它。

TL / DR:考虑到屏幕的大小,纹理的大小以及四边形的位置/大小,如何计算顶点着色器中的纹理坐标,使像素和纹素具有1: 1对应,包装?

1 个答案:

答案 0 :(得分:1)

这是非常简单的数学:你只需要以某种方式将两个空格联系起来。并且您已经制定了一条允许您这样做的规则:窗口空间像素将映射到纹理元素。 假设我们同时具有vec2 screenSizevec2 texSize,它们是像素/纹素的非标准化维度。

我不是百分之百确定你究竟要做什么。缺少一些东西:你没有指明纹理的原点应该在哪里。应该总是在四边形的左下角吗?或者它应该只是在视口的左下角?我会在这里假设这个格子,但是对于第一种情况应该很容易调整它。

我们现在需要的是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;