所以我正在为像超级任天堂这样的老式模拟器开发一些像素着色器。您拥有 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;
}
有什么方法可以确保我们可以从我们期望的像素而不是不同的像素中获取颜色数据?我相信会出现这个问题,因为我们可能会从两个像素之间的坐标中查询一个像素(如果这有意义的话)。希望我忽略的这些着色器语言中有一些内置功能。