美文网首页
cocos2dx label 渲染原理分析

cocos2dx label 渲染原理分析

作者: 许彦峰 | 来源:发表于2022-05-05 16:35 被阅读0次

    不描边

    cocos2d-x\cocos\renderer\ccShader_Label_normal

    attribute vec4 a_position;
    attribute vec2 a_texCoord;
    attribute vec4 a_color;
    varying vec4 v_fragmentColor;
    varying vec2 v_texCoord;
    void main()
    {
        gl_Position = CC_MVPMatrix * a_position;
        v_fragmentColor = a_color;
        v_texCoord = a_texCoord;
    }
    
    varying vec4 v_fragmentColor;
    varying vec2 v_texCoord;
    uniform vec4 u_textColor;
    void main()
    {
        // rgb来自u_textColor,是因为字符位图是灰度的,最终被视为Alpha了
        gl_FragColor =  v_fragmentColor * vec4(u_textColor.rgb,// RGB from uniform
            u_textColor.a * texture2D(CC_Texture0, v_texCoord).a// A from texture & uniform
        );
    }
    
    位图是灰度的

    描边的shader

    2dx中的描边效果是通过freetype生成的描边纹理和非描边纹理,
    描边label的pixel format为AI88cocos对应代码,对于OpenGL来说,它是GL_LUMINANCE_ALPHA,即一个像素是由2个通道[luminance,alpha]组成。


    上图的2个纹理数据,会分别存储在luminance和alpha中,对应的cocos代码
    • luminance是带描边的纹理数据
    • alpha是不带描边的纹理数据

    label的渲染逻辑为:

    描边label使用的渲染纹理

    上图中的结果正好是和这个对应的:

    • 1是都不在描边纹理和非描边纹理范围,所以lum=0,alpha=0
    • 2是描边纹理的范围,所以lum=255,不在非描边纹理范围,所以alpha=0
    • 3是描边纹理和非描边纹理的交集,所以lum=alpha=255

    另外,位图数据在轮廓边缘的值是介于0~255的

    • 4是不带描边的轮廓数据,它的alpha不是255,
    • 5是带描边的轮廓数据,它的Lum不是255

    在shader里面,边缘是通过纹理的alpha识别的,因为位图轮廓是灰度的

    GL_LUMINANCE_ALPHA的[L,A]数据最终在着色器采样后,转换为RGBA为[L,L,L,A]

    此时的alpha刚好为非描边纹理的轮廓边缘

    varying vec4 v_fragmentColor;
    varying vec2 v_texCoord;
    uniform vec4 u_effectColor;
    uniform vec4 u_textColor;
    uniform int u_effectType;
    void main()
    {
        vec4 sample = texture2D(CC_Texture0, v_texCoord);
        // fontAlpha == 1 means the area of solid text (without edge)
        // fontAlpha == 0 means the area outside text, including outline area
        // fontAlpha == (0, 1) means the edge of text
        float fontAlpha = sample.a;
    
        // outlineAlpha == 1 means the area of 'solid text' and 'solid outline'
        // outlineAlpha == 0 means the transparent area outside text and outline
        // outlineAlpha == (0, 1) means the edge of outline
        float outlineAlpha = sample.r;
    
        if (u_effectType == 0) // draw text
        {
            gl_FragColor = v_fragmentColor * vec4(u_textColor.rgb, u_textColor.a * fontAlpha);
        }
        else if (u_effectType == 1) // draw outline
        {
            // multipy (1.0 - fontAlpha) to make the inner edge of outline smoother and make the text itself transparent.
            gl_FragColor = v_fragmentColor * vec4(u_effectColor.rgb, u_effectColor.a * outlineAlpha * (1.0 - fontAlpha));
        }
        else // draw shadow
        {
            gl_FragColor = v_fragmentColor * vec4(u_effectColor.rgb, u_effectColor.a * outlineAlpha);
        }
    }
    

    第一次:绘制outline

    gl_FragColor = v_fragmentColor * vec4(u_effectColor.rgb, u_effectColor.a * L* (1.0 - A));
    区域1因为L=A=0,alpha=effectColor.a * 0 * (1-0)=0
    区域2因为L=255,A=0,alpha=effectColor.a * 1 * (1-0)=effectColor.a
    区域3因为L=255,A=255,alpha=effectColor.a * 1 * (1-1) = 0
    这样绘制出来的效果 = 描边纹理 - 非描边纹理

    第二次:绘制字符

    重置effectType
    gl_FragColor = v_fragmentColor * vec4(u_textColor.rgb, u_textColor.a * A);
    只有A参与计算,那么也就只有区域3和4会显示出来了

    PositionTextureColor_noMVP

    ccShader_PositionTextureColor_noMVP.frag

    attribute vec4 a_position;
    attribute vec2 a_texCoord;
    attribute vec4 a_color;
    varying vec4 v_fragmentColor;
    varying vec2 v_texCoord;
    void main()
    {
        gl_Position = CC_PMatrix * a_position;
        v_fragmentColor = a_color;
        v_texCoord = a_texCoord;
    }
    
    varying vec4 v_fragmentColor;
    varying vec2 v_texCoord;
    void main()
    {
        gl_FragColor = v_fragmentColor * texture2D(CC_Texture0, v_texCoord);
    }
    

    a_color来自node.color,字符纹理变成白色即可

    PositionTexture

    ccShader_PositionTexture.vert

    attribute vec4 a_position;
    attribute vec2 a_texCoord;
    
    #ifdef GL_ES
    varying mediump vec2 v_texCoord;
    #else
    varying vec2 v_texCoord;
    #endif
    
    void main()
    {
        gl_Position = CC_MVPMatrix * a_position;
        v_texCoord = a_texCoord;
    }
    

    ccShader_PositionTexture.frag

    #ifdef GL_ES
    precision lowp float;
    #endif
    
    varying vec2 v_texCoord;
    
    void main()
    {
        gl_FragColor =  texture2D(CC_Texture0, v_texCoord);
    }
    

    矩阵的源头

    // 单位矩阵:相当于数的乘法中的1
    const Mat4 Mat4::IDENTITY = Mat4(
                        1.0f, 0.0f, 0.0f, 0.0f,
                        0.0f, 1.0f, 0.0f, 0.0f,
                        0.0f, 0.0f, 1.0f, 0.0f,
                        0.0f, 0.0f, 0.0f, 1.0f);
    
    void GLView::renderScene(Scene* scene, Renderer* renderer){
      scene->render(renderer,  Mat4::IDENTITY,nullptr);
    }
    
    Label::onDraw(const Mat4& transform)
    

    相关文章

      网友评论

          本文标题:cocos2dx label 渲染原理分析

          本文链接:https://www.haomeiwen.com/subject/fhmsyrtx.html