cocos2dx 字體描邊方法介紹


轉載地址:http://www.taikr.com/group/2/thread/1606

 

關於cocos2dx 字體描邊的實現,不考慮效果和效率的話,是有三種方式:

① 利用CCLabelTTF制作文字描邊和陰影效果

② 利用CCRenderTexture渲染文理的方式生成帶有描邊效果的文字

③ 利用shader來實現,使用cocos2dx中CCGLProgram類與OpenGl繪圖機制中的着色器交互來實現

第三種方式我沒試過,不過基於shader的強大特效功能,實現起來是沒問題的,后面我還會寫一篇關於shader來實現改變紋理顏色做特殊效果的文章。現在我們主要研究一下前兩種。前兩種方式從原理來說都是利用多個CCLabelTTF的重疊來做的,只不過第二種方式是使用CCLabelTTF繪制了一個帶有描邊效果的文字圖片。

利用CCLabelTTF制作文字描邊和陰影效果

網上大量博客都講了這種方式,寫的很好,這里給一個鏈接:http://www.taikr.com/

原理就是創建了4個描邊用的CCLabelTTF和一個正文主體CCLabelTTF,先畫描邊的label,顏色設置成要用的描邊色,分別在目標位置出做上下左右4個方向偏移,然后在蓋上我們的正文主體label即可。

【cpp】 view plaincopy在CODE上查看代碼片派生到我的代碼片

/*string     文本

*fontName   文本字體類型

*fontSize   文本大小

*color3     文本顏色

*lineWidth  所描邊的寬度

*/

CCLabelTTF* HelloWorld::textAddStroke(const char* string, const char* fontName, float fontSize,const ccColor3B &color3,float lineWidth)

{

/* 正文CCLabelTTF */

CCLabelTTF* center = CCLabelTTF::create(string, fontName, fontSize);

center->setColor(color3);

/* 描邊CCLabelTTF 上 */

CCLabelTTF* up = CCLabelTTF::create(string, fontName, fontSize);

up->setColor(ccBLACK);

up->setPosition(ccp(center->getContentSize().width*0.5, center->getContentSize().height*0.5+lineWidth));

center->addChild(up,-1);

/* 描邊CCLabelTTF 下 */

CCLabelTTF* down = CCLabelTTF::create(string, fontName, fontSize);

down->setColor(ccBLACK);

down->setPosition(ccp(center->getContentSize().width*0.5, center->getContentSize().height*0.5-lineWidth));

center->addChild(down,-1);

/* 描邊CCLabelTTF 左 */

CCLabelTTF* left = CCLabelTTF::create(string, fontName, fontSize);

left->setPosition(ccp(center->getContentSize().width*0.5-lineWidth, center->getContentSize().height*0.5));

left->setColor(ccBLACK);

center->addChild(left,-1);

/* 描邊CCLabelTTF 右 */

CCLabelTTF* right = CCLabelTTF::create(string, fontName, fontSize);

right->setColor(ccBLACK);

right->setPosition(ccp(center->getContentSize().width*0.5+lineWidth,center->getContentSize().height*0.5));

center->addChild(right,-1);

return center;

}  <span style="font-family: verdana, Arial, Helvetica, sans-serif;"> </span>

陰影效果就更簡單了,只需要兩個label,一個陰影用的label和正文label,只需要設置陰影label:顏色、透明度和位置偏移即可。

【cpp】 view plaincopy在CODE上查看代碼片派生到我的代碼片

/*string         文本

*fontName       文本字體類型

*fontSize       文本大小

*color3         文本顏色

*shadowSize     陰影大小

*shadowOpacity  陰影透明度

*/

CCLabelTTF* HelloWorld::textAddShadow(const char* string, const char* fontName, float fontSize,const ccColor3B &color3,float shadowSize,float shadowOpacity)

{

/* 陰影label */

CCLabelTTF* shadow = CCLabelTTF::create(string, fontName, fontSize);

shadow->setColor(ccBLACK);

shadow->setOpacity(shadowOpacity);

/* 正文label */

CCLabelTTF* center = CCLabelTTF::create(string, fontName, fontSize);

center->setColor(color3);

center->setPosition(ccp(shadow->getContentSize().width*0.5-shadowSize,shadow->getContentSize().height*0.5+shadowSize));

shadow->addChild(center);

return shadow;

} <span style="font-family: verdana, Arial, Helvetica, sans-serif;"> </span>

這里提到一點,就是具體要創建幾個label是不一定的,創建的越多,效果是描邊越粗越亮但是效率越低,比如創建了40個描邊用的label,4個方向各10個,互相之間有微小的偏移不完全重疊,這樣的效果是label更加的粗且亮,陰影效果等同。

利用CCRenderTexture渲染文理的方式生成帶有描邊效果的文字

這種方式難點在於,很多人不了解OpenGl的繪圖着色機制,不過也不要緊,這里只用到了一點着色知識,就是顏色的混合,這個大多數的人都知道,紅色和綠色混合會變成黃色,黑色和任何顏色混合還是黑色(0*任何數=0),任何顏色和白色的混合不改變顏色。

繪圖時,OpenGL 會把源顏色和目標顏色各自取出,並乘以一個系數(源顏色乘以的系數稱為“源因子”,目標顏色乘以的系數稱為“目標因子”),然后做運算得到新的顏色值,並按照新的顏色來繪制。

比如,RGB格式,原來的顏色是(255,0,0)--紅色,目標顏色是(0,255,0)--綠色,加入系數為{1,0},運算方式為顏色的疊加,這意味着新的顏色為(255,0,0)*1+(0,255,0)*0 = (255,0,0)--紅色,就是完全不用目標顏色的值,相當於沒變色, 系數中源因子為前者:1,目標因子為后者:0,這是{1,0}的混合機制。

好了,那么我們來了解一下cocos2dx的渲染是怎么做的。

在cocos2dx中的可渲染的節點都是CCNode的子類,如精靈、場景、文本,CCNode有一個渲染混色的函數glBlendFunc()和setBlendFunc(),操作的是ccBlendFunc,ccBlendFunc有兩個調節變量,ccBlendFunc func = { GL_SRC_ALPHA, GL_ONE},這個調節變量就是前面說的系數:

GL_SRC_ALPHA:表示使用源顏色的alpha值來作為源因子。

GL_ONE: 表示使用1.0作為因子,實際上相當於完全的使用了這種顏色參與混合運算。

這類參數有很多,自己可以跟蹤引擎代碼內部去看。

再介紹一下,CCRenderTexture生成描邊字體的原理,CCRenderTexture可以理解為一張紋理畫布,我們可以再這張畫布上塗鴉,當我們收工的時候,這張畫就算畫好了,即生成一張紋理。因此,我們是在畫布上,用一個label在不同的位置不斷的去畫,類似第一種方式,我們在畫布上繪制label的時候,在目標位置處的360個方向畫多個label,重疊,最后通過畫布就生成帶有描邊文字的一張紋理圖,然后用這張紋理圖生成一個精靈放到場景里,完畢。

下面先把代碼貼上來:

【cpp】 view plaincopy在CODE上查看代碼片派生到我的代碼片

CCTexture2D* FlyBloodLabel::createStrokeTexture(const char* value,float strokeValue,ccColor3B color)

{

// float fontSize = m_fontSize - 2 * strokeSize;

/* 創建一個CCLabelTTF,含有期望字體樣式,作為畫筆 */

CCLabelTTF *label = CCLabelTTF::create(value,"Arial",EFFECT_LABEL_FONT_SIZE);

/* 通過label的大小來設置最終生成的紋理圖片的大小,strokeValue為描邊字體的偏移量,影響粗細 */

CCSize textureSize = label->getContentSize();

textureSize.width += 2 * strokeValue;

textureSize.height += 2 * strokeValue;

/* 監測OpenGl的錯誤狀態 */

glGetError();

/* 創建一張紋理畫布 */

CCRenderTexture *rt = CCRenderTexture::create(textureSize.width, textureSize.height);

if(!rt)

{

CCLog("create render texture failed !!!!");

addChild(label);

return 0;

}

/* 設置描邊的顏色 */

label->setColor(color);

/*

*拿到源文字的混色機制,存儲以備恢復,並設置新的目標混色機制

*混色機制設為:源顏色透明度(影響亮度)和目標顏色(影響顏色)

*/

ccBlendFunc originalBlend = label->getBlendFunc();

ccBlendFunc func = { GL_SRC_ALPHA, GL_ONE};

label->setBlendFunc(func);

/* 這是自定義的一些調整,傾斜了一點 */

label->setAnchorPoint(ccp(0.5, 0.5));

label->setRotationX(15);

/* 張開畫布,開始繪畫 */

rt->begin();

for(int i = 0; i < 360; i += 5)//每變化5度繪制一張

{

float r = CC_DEGREES_TO_RADIANS(i); //度數格式的轉換

label->setPosition(ccp(textureSize.width * 0.5f + sin(r) * strokeValue,textureSize.height * 0.5f + cos(r) * strokeValue));

/* CCRenderTexture的用法,在begin和end之間visit的紋理,都會畫在CCRenderTexture里面 */

label->visit();//畫了一次該label

}

/* 恢復原始的label並繪制在最上層 */

label->setColor(ccWHITE);

label->setBlendFunc(originalBlend);

label->setPosition(ccp(textureSize.width * 0.5f, textureSize.height * 0.5f));

label->visit();

/* 在畫布上繪制結束,此時會生成一張紋理 */

rt->end();

/* 取出生成的紋理,添加抗鋸齒打磨,並返回 */

CCTexture2D *texture = rt->getSprite()->getTexture();

texture->setAntiAliasTexParameters();// setAliasTexParameters();

return texture;

}

除此之外,還有一種方式就是Shader,這個還在研究,不過它的特效功能着實強大,以后逐步學習。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM