1

我需要编写一个函数,该函数应从 2D 纹理(非 2 次幂)中获取子矩形,并使用着色器(无 glSubImage 或类似)将其复制到输出 2D 纹理的目标子矩形。此外,源和目标的大小可能不同,所以我需要使用线性过滤(甚至是 mipmap)。

void CopyToTex(GLuint dest_tex,GLuint src_tex,
               GLuint src_width,GLuint src_height,
               GLuint dest_width,GLuint dest_height,
               float srcRect[4],
               GLuint destRect[4]);

这里 srcRect 是标准化的 0-1 坐标,即矩形 [0,1]x[0,1] 触摸输入纹理的每个边框像素的中心。

为了在输入和源尺寸不匹配时获得良好的结果,我想使用GL_LINEAR过滤。

我希望这个函数以一种连贯的方式运行,即多次使用多个子区域调用它会产生与使用子区域联合的一次调用相同的结果;也就是说,线性采样器应该对输入像素的确切中心进行采样。

此外,如果输入矩形恰好适合目标矩形,则应该出现精确的副本。这似乎特别难。

我现在得到的是这样的:

//Setup RTT, filtering and program

float vertices[4] = { 
      float(destRect[0]) / dest_width * 2.0 - 1.0,
      float(destRect[1]) / dest_height * 2.0 - 1.0, 
      //etc..
};

float texcoords[4] = {
      (srcRect[0] * (src_width - 1) + 0.5) / src_width - 0.5 / dest_width,
      (srcRect[1] * (src_height - 1) + 0.5) / src_height - 0.5 / dest_height,
      (srcRect[2] * (src_width - 1) + 0.5) / src_width + 0.5 / dest_width,
      (srcRect[3] * (src_height - 1) + 0.5) / src_height + 0.5 / dest_height,
};

glBegin(GL_QUADS);
glTexCoord2f(texcoords[0], texcoords[1]);
glVertex2f(vertices[0], vertices[1]);

glTexCoord2f(texcoords[2], texcoords[1]);
glVertex2f(vertices[2], vertices[1]);

//etc...
glEnd();

为了编写此代码,我遵循了页面中的信息。

这似乎在某些极端情况下按预期工作(精确复制,复制一个像素的行或列)。

我最难的测试案例是在输入和输出纹理都大于 2xN 时执行 2xN 矩形的精确复制。

我可能对偏移和缩放有一些问题(琐碎的不起作用)。

4

1 回答 1

0

解决方案:

texcoords 定义中的0.5/tex_width部分是错误的。一个简单的解决方法是完全删除该部分。

float texcoords[4] = {
      (srcRect[0] * (src_width - 1) + 0.5) / src_width,
      (srcRect[1] * (src_height - 1) + 0.5) / src_height,
      (srcRect[2] * (src_width - 1) + 0.5) / src_width,
      (srcRect[3] * (src_height - 1) + 0.5) / src_height
};

相反,我们通过以下方式偏移顶点来绘制一个较小的四边形:

float dx = 1.0 / (dest_rect[2] - dest_rect[0]) - epsilon;
float dy = 1.0 / (dest_rect[3] - dest_rect[1]) - epsilon;

// assume glTexCoord for every vertex 
glVertex2f(vertices[0] + dx, vertices[1] + dy);
glVertex2f(vertices[2] - dx, vertices[1] + dy);
glVertex2f(vertices[2] - dx, vertices[3] - dy);
glVertex2f(vertices[0] + dx, vertices[3] - dy);

通过这种方式,我们绘制了一个四边形,它从每个边界像素的确切中心穿过。由于 OpenGL 在这种情况下可能会或可能不会绘制边界像素,因此我们需要 epsilon。

我相信我最初的解决方案(不要偏移顶点坐标)仍然可以工作,但需要一些额外的数学来计算 texcoords 的正确偏移量。

于 2013-08-23T15:45:34.290 回答