[✔️] cocos2dx label 渲染原理分析

简介: [✔️] cocos2dx label 渲染原理分析

不描边


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
    );
}


image.png


使用的是A8,一个像素只有一个通道,渲染的时候根据alpha就能知道label的样子


描边的shader


描边label的pixel format为AI88

2dx中的描边效果的纹理是通过freetype生成的描边纹理和非描边纹理后,再合并为一个AI88的纹理,即一个像素是由2个通道[luminance,alpha]组成。


image.png


上图的2个纹理数据,会分别存储在AI88的luminance和alpha中:


  • 一个通道:luminance是带描边的纹理数据


  • 一个通道:alpha是不带描边的纹理数据


对于OpenGL来说,它是GL_LUMINANCE_ALPHA


image.png


label的渲染逻辑为:


image.png


image.png


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


  • 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


这样绘制出来的效果 = 描边纹理 - 非描边纹理


第二次:绘制字符


重置effectTypegl_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)
目录
相关文章
|
iOS开发
iOS 多个滚动控件嵌套Demo
iOS 多个滚动控件嵌套Demo
90 0
|
JavaScript
Vue3.0项目——打造企业级音乐App(二)图片懒加载、v-loading指令的开发和优化
Vue3.0项目——打造企业级音乐App(二)图片懒加载、v-loading指令的开发和优化
167 0
|
weex-ui 移动开发 weex
weex-如何自定义一个控件,并向控件中传值,接上一篇vue.set和this.xxx赋值
weex-如何自定义一个控件,并向控件中传值,接上一篇vue.set和this.xxx赋值
100 0
weex-如何自定义一个控件,并向控件中传值,接上一篇vue.set和this.xxx赋值
|
JavaScript
【Vue.js 入门与实战】--动画-小球动画flag标识符的作用分析
一、实现小球动画复习 二、成功范例 三、失败案例分析
【Vue.js 入门与实战】--动画-小球动画flag标识符的作用分析
|
缓存
Flutter Tips 小技巧(更新中)(上)
Flutter Tips 小技巧(更新中)(上)
349 0
Flutter Tips 小技巧(更新中)(上)
|
Dart Android开发 开发者
Flutter Tips 小技巧(更新中)(下)
Flutter Tips 小技巧(更新中)(下)
421 0
Flutter Tips 小技巧(更新中)(下)
|
移动开发 开发工具 git
Flutter Tips 小技巧(更新中)(中)
Flutter Tips 小技巧(更新中)(中)
263 0
|
JSON 数据格式 容器
Flutter 16: 图解 ListView 异步加载数据与 Loading 等待
0 基础学习 Flutter,第十六步:ListView 日常小问题,包括异步数据加载及 Loading 等待过程~
5633 0
|
Web App开发 JavaScript 前端开发
React Native 利用webView 加载echars图表 不显示问题
先看下 效果图吧 IMG_2273.PNG IMG_2272.PNG 之前用 第三方组件 native-echarts 也实现了雷达图,但是比较复杂,而且 android 和ios 上引入tpl.html文件也不一样,而且也没有上图中的渐变,反正效果不是很好。
2135 0