使用像素坐标的 OpenGL 子图像

OpenGL subimages using pixel coordinates

我在 learnopengl.com 的突破系列中完成了几个教程,所以我有一个非常简单的 2D 渲染器。不过,我想向它添加一个子图像功能,我可以在其中为一种“源矩形”指定一个 vec4,因此如果 vec4 是 (10, 10, 32, 32),它只会在 10、10 处呈现一个矩形32 的宽度和高度,有点像 SDL 渲染器的工作方式。

渲染器的设置方式是所有精灵都使用四边形 VAO,其中包含纹理坐标。最初,我虽然可以为每个精灵使用一个 VAO 数组,每个精灵都有不同的纹理坐标,但我希望能够在绘制精灵之前更改源矩形,以使动画之类的事情更容易......我的第二个想法是将一个单独的统一 vec4 传递到源矩形的片段着色器中,但是我如何只在像素坐标中渲染该部分?

使用 Primitiv 类型 GL_TRIANGLE_STRIPGL_TRIANGLE_FAN 渲染四边形。使用积分 one-dimensional 顶点坐标而不是 floating-point 顶点坐标。顶点坐标是四角的索引。对于 GL_TRIANGLE_FAN 他们是:

vertex 1: 0
vertex 2: 1
vertex 3: 2
vertex 4: 3

在顶点着色器中使用 Uniform 类型 vec4 变量设置矩形定义 (10, 10, 32, 32)。有了这些信息,就可以在vertex shader中计算顶点坐标了:

in int cornerIndex;
uniform vec4 rectangle;

void main()
{
    vec2 vertexArray[4] = 
        vec2[4](rectangle.xy, rectangle.zy, rectangle.zw, rectangle.xw);
    vec2 vertex = vertexArray[cornerIndex];

    // [...]
}

Vertex Shader provides the built-in input gl_VertexID,指定当前正在处理的顶点的索引。在这种情况下,可以使用此变量代替 cornerIndex。请注意,顶点着色器不需要任何显式输入。

我最终在顶点着色器中完成了这项工作。我将 vec4 作为制服传递给顶点着色器,以及图像的大小,并使用以下计算:

// convert pixel coordinates to vertex coordinates
float widthPixel = 1.0f / u_imageSize.x;
float heightPixel = 1.0f / u_imageSize.y;

float startX = u_sourceRect.x, startY = u_sourceRect.y, width = u_sourceRect.z, height = u_sourceRect.w;
v_texCoords = vec2(widthPixel * startX + width * widthPixel * texPos.x, heightPixel * startY + height * heightPixel * texPos.y);

v_texCoords 是片段着色器用来映射纹理的变量。