透视投影中的 SDF 文本渲染

SDF text rendering in perspective projection

我正在使用 SDF 技术 http://www.valvesoftware.com/publications/2007/SIGGRAPH2007_AlphaTestedMagnification.pdf 在 WebGL 中呈现文本。我制作了字体的 SDF 纹理,生成 BMFont 文本规格并使用简单的片段着色器显示文本:

        precision mediump float;
        uniform sampler2D u_texture;        
        varying vec2 vUv;

        float aastep(float value) {
          float afwidth = 0.1;
          return smoothstep(0.5 - afwidth, 0.5 + afwidth, value);
        }

        void main(void)
        {            
            vec4 texColor = texture2D(u_texture, vUv);
            float alpha = aastep(texColor.a);
            gl_FragColor = vec4(0.0, 0.0, 0.0, alpha);            
        }

我对 aastep 函数中的 afwidth 值有疑问。 afwidth 只是定义字体边界的模糊。如果它很小,那么远处的文字看起来很难看。如果大 - 靠近我的文字看起来很难看。所以问题是如何在片段着色器中计算afwidth?

PS:我有一个计算公式 GL_OES_standard_derivatives:

float afwidth = length(vec2(dFdx(value), dFdy(value))) * 0.70710678118654757;

但是我的硬件不支持这个扩展。所以我想我需要根据gl_FragCoord和变换矩阵来计算它。

人们可能会尝试根据 gl_FragCoord.w = 1.0 / gl_Position.w:

创建 distance-to-camera 的简单近似值
    float aastep(float value)
    {
          float distanceToCamera = 1.0 / gl_FragCoord.w;
          float afwidth = 0.1 * distanceToCamera;
          return smoothstep(0.5 - afwidth, 0.5 + afwidth, value);
    }

您可能需要根据自己的喜好调整常数 0.1

只是检查一下,但您确定您的硬件不支持 OES_standard_derivativeshttp://webglstats.com 看起来不太可能。

在 WebGL 中,您必须启用 OES_standard_derivatives 才能使用它。

ext = gl.getExtention("OES_standard_derivatives");
if (!ext) {
  // alert("no OES standard derivatives") or fallback to other technique
}

然后在你的着色器中你必须打开它

// at top of fragment shader
#extension GL_OES_standard_derivatives : enable

Run this test to check if they work on your system。如果您得到关于它们不存在的非常简短的结果,那么您是对的,它们不存在。如果你得到很多结果,那么它们确实存在,只是你没有在你的程序中启用它们