GPU着色器的像素缩放算法问题

时间:2011-02-15 22:26:34

标签: opengl glsl shader cg

所以我正在研究像Super Nintendo这样的老式仿真器的一些像素着色器。你有经典的算法,如HQnx,2xSaI等,它们肯定是为了在CPU上运行而编写的,并且在插入屏幕之前可以精确缩放到两倍大小。

继续使用GPU片段着色器,这些算法可以基本上免费完成。我正在使用OpenGL和Cg / GLSL,但这个问题也适用于Direct3D / HLSL编码器。

主要问题是这些算法使用某种算法来混合相邻像素来决定颜色。但是,我用着色器语言很难找到这个概念。通常使用片段着色器,您可以获得浮点纹理坐标,您可以使用该坐标进行纹理查找,通常使用GL_LINEAR作为纹理过滤器。大多数像素着色器使用GL_NEAREST,并自行进行平滑。

如果我想找到确切的邻居像素,就会出现问题。我见过一些实现,但它们偶尔会在屏幕上造成伪影。可能是由于发生浮点不准确。我发现大多数工件在使用两个大小的纹理时都会消失,这进一步增强了我的信念,即存在浮点不准确性。以下是Cg中的示例片段着色器,它显示了问题:

struct output
{
   float4 color : COLOR;
};

struct input
{
  float2 video_size;
  float2 texture_size;
  float2 output_size;
};

struct deltas
{
   float2 UL, UR, DL, DR;
};


output main_fragment (float2 tex : TEXCOORD0, uniform input IN, uniform sampler2D s_p : TEXUNIT0)
{
   float2 texsize = IN.texture_size;
   float dx = pow(texsize.x, -1.0) * 0.25;
   float dy = pow(texsize.y, -1.0) * 0.25;
   float3 dt = float3(1.0, 1.0, 1.0);

   deltas VAR = { 
      tex + float2(-dx, -dy),
      tex + float2(dx, -dy),
      tex + float2(-dx, dy),
      tex + float2(dx, dy)
   };

   float3 c00 = tex2D(s_p, VAR.UL).xyz;
   float3 c20 = tex2D(s_p, VAR.UR).xyz;
   float3 c02 = tex2D(s_p, VAR.DL).xyz;
   float3 c22 = tex2D(s_p, VAR.DR).xyz;

   float m1=dot(abs(c00-c22),dt)+0.001;
   float m2=dot(abs(c02-c20),dt)+0.001;

   output OUT;
   OUT.color = float4((m1*(c02+c20)+m2*(c22+c00))/(2.0*(m1+m2)),1.0);
   return OUT;
}

有没有办法确保我们可以从我们期望的像素中获取颜色数据而不是另一个?我相信会出现这个问题,因为我们可能会从两个像素之间的坐标查询一个像素(如果这是有道理的)。希望我能忽略的这些着色器语言中有一些内置函数。

1 个答案:

答案 0 :(得分:4)

当然,在OpenGL中有几种方法:

  • 在着色器中,使用texelFetch函数执行纹理提取,该提取使用整数非标准化坐标。可在GL_EXT_gpu_shader4扩展或OpenGL 3.0中使用。
  • 使用纹理矩形(GL_ARB_texture_rectangle,OpenGL 3.2),此纹理目标使用非标准化坐标,但不允许使用mipmap并限制某些包裹模式。

非标准化坐标是您想要的,它们位于[0,0] x [w,h]范围/