OpenGL着色器可以混合最近和线性缩放吗?

时间:2017-12-24 08:22:14

标签: opengl glsl

我正在将一些旧的OpenGL 1.2位图字体渲染代码移植到现代OpenGL(至少OpenGL 3.2+),我想知道我是否可以使用GLSL着色器来实现我手动完成的工作。

当我想绘制字符串“123”,缩放到特定大小时,我使用下面的精灵执行以下步骤。

enter image description here

  1. 我将精灵画到屏幕上,用GL_NEAREST缩放2倍。然而,为了获得黑色轮廓,我实际上画了几次精灵。

    1. x + 1,y + 0,BLACK
    2. x + 0,y + 1,BLACK
    3. x - 1,y + 0,BLACK
    4. x + 0,y - 1,BLACK
    5. x + 0,y + 0,COLOR(RED)
    6. enter image description here

    7. 精灵被绘制到屏幕后,我通过glCopyTexSubImage2D将屏幕复制到纹理。

    8. 我将该纹理绘制回屏幕,但使用GL_LINEAR。
    9. 最终结果是一种更具视觉吸引力的缩放像素精灵形式。当将小像素精灵升级到任意尺寸时,仅使用GL_NEAREST(右下角)或仅使用GL_LINEAR(左下角)会产生我不喜欢的效果。使用GL_NEAREST加倍像素,然后使用GL_LINEAR进行剩余缩放,得到我更喜欢的结果(顶部)。

      enter image description here

      我非常确定GLSL可以做黑色轮廓(从而使我不必进行大量绘制),但它是否也可以组合GL_NEAREST和GL_LINEAR缩放?

1 个答案:

答案 0 :(得分:1)

你可以实现" 2x最近邻扩频的效果,接着是线性采样"通过假装从放大的纹理中采样4个纹素的邻域,而实际上从原始纹理中采样它们。然后,您必须手动实施双线性插值。如果您的目标是OpenGL 4+,textureGather()会很有用,但请记住this issue。在我下面提出的解决方案中,我将使用4个texelFetch()调用,而不是textureGather(),因为textureGather()会使事情变得相当复杂。

假设您有一个未缩放的纹理,并且已经存在的字形周围有黑色边框。假设您将vec2 pn = ...的标准化纹理坐标放入该纹理中,其中pn.xpn.y介于0和1之间。以下代码应达到预期效果,但我还没有测试过它:

ivec2 origTexSize = textureSize(sampler, 0);
int upscaleFactor = 2;

// Floating point texel coordinate into the upscaled texture.
vec2 ptu = pn * vec2(origTexSize * upscaleFactor);

// Decompose "ptu - 0.5" into the integer and fractional parts.
vec2 ptuf;
vec2 ptui = modf(ptu - 0.5, ptuf);

// Integer texel coordinates into the upscaled texture.
ivec2 ptu00 = ivec2(ptui);
ivec2 ptu01 = ptu00 + ivec2(0, 1);
ivec2 ptu10 = ptu00 + ivec2(1, 0);
ivec2 ptu11 = ptu00 + ivec2(1, 1);

// Integer texel coordinates into the original texture.
ivec2 pt00 = clamp(ptu00 / upscaleFactor, ivec2(0), origTexSize - 1);
ivec2 pt01 = clamp(ptu01 / upscaleFactor, ivec2(0), origTexSize - 1);
ivec2 pt10 = clamp(ptu10 / upscaleFactor, ivec2(0), origTexSize - 1);
ivec2 pt11 = clamp(ptu11 / upscaleFactor, ivec2(0), origTexSize - 1);

// Sampled colours.
vec4 clr00 = texelFetch(sampler, pt00, 0);
vec4 clr01 = texelFetch(sampler, pt01, 0);
vec4 clr10 = texelFetch(sampler, pt10, 0);
vec4 clr11 = texelFetch(sampler, pt11, 0);

// Bilinear interpolation.
vec4 clr0x = mix(clr00, clr01, ptuf.y);
vec4 clr1x = mix(clr10, clr11, ptuf.y);
vec4 clrFinal = mix(clr0x, clr1x, ptuf.x);