不描边
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 ); }
使用的是A8,一个像素只有一个通道
,渲染的时候根据alpha就能知道label的样子
描边的shader
描边label的pixel format为AI88
,
2dx中的描边效果的纹理是通过freetype生成的描边纹理和非描边纹理后,再合并为一个AI88的纹理,即一个像素是由2个通道[luminance,alpha]
组成。
上图的2个纹理数据,会分别存储在AI88的luminance和alpha中:
- 一个通道:luminance是带描边的纹理数据
- 一个通道:alpha是不带描边的纹理数据
对于OpenGL来说,它是GL_LUMINANCE_ALPHA
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
这样绘制出来的效果 = 描边纹理 - 非描边纹理
第二次:绘制字符
先重置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)