そのため、スーパー ファミコンのような古き良きエミュレーター用のピクセル シェーダーに取り組んでいます。HQnx、2xSaI などの古典的なアルゴリズムがあり、それらは間違いなく CPU 上で実行するように作成されており、画面にブリットする前に正確に 2 倍のサイズにスケーリングされます。
GPU フラグメント シェーダーに移ると、これらのアルゴリズムは基本的に無料で実行できます。私は OpenGL と Cg/GLSL を使用していますが、この質問は Direct3D/HLSL コーダーにも当てはまります。
主な問題は、これらのアルゴリズムが何らかのアルゴリズムを使用して隣接するピクセルとブレンドして色を決定することです。しかし、この概念はシェーダー言語では非常に難しいと感じました。通常、フラグメント シェーダーを使用すると、浮動小数点のテクスチャ座標を取得できます。これを使用してテクスチャ ルックアップを実行できます。通常は、GL_LINEAR をテクスチャ フィルタとして使用します。ほとんどのピクセル シェーダーは GL_NEAREST を使用し、スムージング自体を行います。
たとえば、正確な隣接ピクセルを見つけたい場合に問題が発生します。いくつかの実装を見てきましたが、画面にアーティファクトが発生することがあります。おそらく、発生する浮動小数点の不正確さが原因です。2 のべき乗サイズのテクスチャを使用すると、ほとんどのアーティファクトが単純に消えることがわかりました。これは、浮動小数点の不正確さが発生しているという私の信念をさらに強めるものです。問題を示す 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;
}
別のピクセルではなく、期待するピクセルからカラー データを取得できることを確認する方法はありますか? この問題は、2 つのピクセルの間にある座標からピクセルをクエリする可能性があるために発生すると考えられます (それが理にかなっている場合)。私が見落としているこれらのシェーダー言語に組み込み関数があることを願っています。