【问题标题】:Outlining a font with a shader and using distance field使用着色器概述字体并使用距离场
【发布时间】:2014-10-02 06:44:11
【问题描述】:

我正在使用 Hiero 生成的 BitmapFont。我按照这个伟大的指南https://github.com/libgdx/libgdx/wiki/Distance-field-fonts 正确使用距离场。 我还使用指南中提供的着色器。一切都很好。

接近尾声,指南中提到在距离场抗锯齿之上,应该很容易从提供的着色器中为字体添加轮廓。它与调整 distance 参数有关。我相信对于知道如何处理着色器的人来说这很容易。但我没有。

这是片段代码

#ifdef GL_ES
precision mediump float;
#endif

uniform sampler2D u_texture;

varying vec4 v_color;
varying vec2 v_texCoord;

const float smoothing = 1.0/16.0;

void main() {
    float distance = texture2D(u_texture, v_texCoord).a;
    float alpha = smoothstep(0.5 - smoothing, 0.5 + smoothing, distance);
    gl_FragColor = vec4(v_color.rgb, alpha);
}

这里是顶点代码:

uniform mat4 u_projTrans;

attribute vec4 a_position;
attribute vec2 a_texCoord0;
attribute vec4 a_color;

varying vec4 v_color;
varying vec2 v_texCoord;

void main() {
    gl_Position = u_projTrans * a_position;
    v_texCoord = a_texCoord0;
    v_color = a_color;
}

从这里如何使用着色器添加轮廓?

【问题讨论】:

    标签: fonts libgdx shader


    【解决方案1】:

    smoothstep 函数基本上是一种创建平滑渐变以消除字母边缘的锯齿的方法。如果要勾勒出字母的轮廓,则需要将字母的 alpha 抗锯齿移出轮廓的粗细。所以首先你需要一个新的轮廓厚度常量:

    const float outlineWidth = 3.0/16.0; //will need to be tweaked
    const float outerEdgeCenter = 0.5 - outlineWidth; //for optimizing below calculation
    

    然后修改您的 alpha,使其允许现在更大的字母:

    float alpha = smoothstep(outerEdgeCenter - smoothing, outerEdgeCenter + smoothing, distance);
    

    现在您需要第二条抗锯齿边缘来将不透明的轮廓与不透明的字母分开。它将与旧的 alpha 计算相同,因为它在同一个地方。

    float border = smoothstep(0.5 - smoothing, 0.5 + smoothing, distance);
    

    最后,您需要通过混合轮廓颜色和字母颜色来计算不透明颜色。

    uniform vec4 u_outlineColor; //declared before main()
    
    gl_FragColor = vec4( mix(u_outlineColor.rgb, v_color.rgb, border), alpha );
    

    总结一下你的新片段着色器:

    #ifdef GL_ES
    precision mediump float;
    #endif
    
    uniform sampler2D u_texture;
    uniform vec4 u_outlineColor;
    
    varying vec4 v_color;
    varying vec2 v_texCoord;
    
    const float smoothing = 1.0/16.0;
    const float outlineWidth = 3.0/16.0;
    const float outerEdgeCenter = 0.5 - outlineWidth;
    
    void main() {
        float distance = texture2D(u_texture, v_texCoord).a;
        float alpha = smoothstep(outerEdgeCenter - smoothing, outerEdgeCenter + smoothing, distance);
        float border = smoothstep(0.5 - smoothing, 0.5 + smoothing, distance);
        gl_FragColor = vec4( mix(u_outlineColor.rgb, v_color.rgb, border), alpha );
    }
    

    您可以通过在batch.begin()batch.end() 之间调用它来设置边框颜色:

    shaderProgram.setUniformf("u_outlineColor", myOutlineColor);
    

    【讨论】:

    • 嗨@Tenfour04。谢谢你的回答,我很抱歉这么晚才回答。看来 shaderProgram.setUniformf("u_outlineColor", myOutlineColor);使用 Vector2 作为值。这些值是否对应于(RGB,ALPHA)?比如如何选择纯红色?
    • setUniformf 有许多不同的重载,而不仅仅是 Vector2。在这种情况下,我们想要传递四个浮点数,因为我们将 u_outlineColor 声明为 vec4。您可以像这样传递四个浮点数:setUniformf("u_outlineColor", 1f, 0f, 0f, 1f); 其中四个数字是颜色的 RGBA 分量,已标准化。或者你可以传入一个com.badlogic.gdx.graphics.Color 的实例,这就是我想要的myOutlineColor。所以对于红色你会做myOutlineColor.set(1,0,0,1); shaderProgram.setUniformf("u_outlineColor", myOutlineColor);
    • 非常感谢您的出色回答。祝你有美好的一天
    • Color 类也是通用的。如果这是您更熟悉的内容,您可以使用 myOutlineColor.set(0xff0000ff);
    • (1,0,0,1) 是最好的!简短而简单:) 再次感谢
    猜你喜欢
    • 2014-08-12
    • 2018-06-25
    • 2015-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多