【问题标题】:Can an OpenGL shader do a mix of nearest and linear scaling?OpenGL着色器可以混合最近和线性缩放吗?
【发布时间】:2018-06-06 03:33:47
【问题描述】:

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

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

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

    1. x + 1,y + 0,黑色
    2. x + 0,y + 1,黑色
    3. x - 1,y + 0,黑色
    4. x + 0,y - 1,黑色
    5. x + 0,y + 0,颜色(红色)

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

  3. 我将该纹理绘制回屏幕,但使用 GL_LINEAR。

最终结果是缩放像素精灵的一种更具视觉吸引力的形式。当将小像素精灵放大到任意尺寸时,仅使用 GL_NEAREST(右下)或 GL_LINEAR(左下)会产生我不喜欢的效果。使用 GL_NEAREST 将像素加倍,然后使用 GL_LINEAR 进行剩余缩放,得到了我更喜欢的结果(顶部)。

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

【问题讨论】:

    标签: opengl glsl


    【解决方案1】:

    您可以通过假装从放大后的纹理中采样 4 纹理邻域,而实际上从原始纹理中采样它们来实现“2 倍最近邻放大后线性采样”的效果。然后你必须手动实现双线性插值。如果您的目标是 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);
    

    【讨论】:

      猜你喜欢
      • 2021-09-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多