尝试解决cocos2dx字体模糊时的一点收获
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录前言一、关掉抗锯齿二、生成更好的bitmap1.TTF字体2.Hint3.更高清的bitmap字体类的代码前言在业余时间想自己用cocos2dx开发一款像素游戏,但是遇到了不少的坑,其中有一项就是字体方面的。使用一个像素TTF字体,但是始终很糊,便去找各种解决办法。下面是自己使用的方法。一、关掉抗锯齿核心函数:setAlias
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
在业余时间想自己用cocos2dx开发一款像素游戏,但是遇到了不少的坑,其中有一项就是字体方面的。使用一个像素TTF字体,但是始终很糊,便去找各种解决办法。下面是自己使用的方法。一、关掉抗锯齿
核心函数:setAliasTexParameters();之前做在使用一些像素材质时也用到过这个函数,cocos2dx正在很多都开启了自动抗锯齿,可以使用该函数关闭抗锯齿。
- 对于label
可以使用label->getFontAtlas()->setAliasTexParameters();[还需测试] - 对于TextFieldTTF
可以对其进行继承,在每次draw之前对其生成的_batchNodes里面的每个SpriteBatchNode使用setAliasTexParameters();
二、生成更好的bitmap
我使用的像素字体,按照之前的理解,关闭抗锯齿应该就不会出现模糊问题了。可是字体虽然不是整体模糊了,却又很多的半像素块。于是开始了漫长的读源码之旅。1.TTF字体
现在用的比较多的就是TTF矢量字体(轮廓字体)和点阵字体。- 点阵字体
点阵字体描绘了用打字是用二维数组描绘了字体中对应部分的深度。故在缩放时容易失真产
生成马赛克式的锯齿边缘,这时便可以用抗锯齿生成半透明块使其相对平滑。 - ttf字体
ttf字体是保存了每个字对应的轮廓,使用一系列数学运算来计算对应结果。这样在对应大小下的字便会生成对应大小的轮廓。使其在缩放时不易失真。
2.Hint
ttf字体在不同大小下回自动计算对应大小下的轮廓,可是最终显示到计算机屏幕上还是需要进行光栅化。在低像素下编有可能出现有些像素块对应不满一个格子的情况。就像下图一样:
而hint(提示)技术就是想通过抗锯齿和网格对齐的方式来使这种情况减少。
在freetype2中,字体往往可以被autohint(自动)来获取不错的效果。
在cocos2dx源码中有类似这样的层级(label使用ttf或者textfieldttf):
[label]
visit();
updateContent();
alignText();
[FontAtlas]
prepareLetterDefinitions();
[CCFontFreeType]
getGlyphBitmap();
[freetype]
FT_Load_Char()
而bitmap,用于保存每个像素深度值的数组便由FT_Load_Char()产生。cocos2dx随后便通过这个bitmap和相关的输出信息来生成对应的材质。而cocos2dx在使用FT_Load_Char()时吧autohint给关了,具体原因未知。于是我就试着把这个参数给设置为打开(将LOAD_NO_AUTOHINT标记去掉),好在改这个cpp所用重新编译时间不长。
3.更高清的bitmap
打开后发现情况并没有好了很多,虽然半透明块减少了很多,但是仍然有不少,而且部分地方出现了线条大小不一的情况。于是log输出了一下对应的bitmap值。结果却是有缺项。便又去看了看cocos2dx是如何设置对应参数生成bitmap的。随后发现最终生成的bitmap大小和之前调用的FT_SET_CHAR_SIZE有关,具体是写为固定为dpi的(72)和fontsize变量。但是不管调大fontsize和dpi对应的值,其最终渲染出来的字都会变大。于是便想到手动写一个类继承了TextFieldTTF,并将fontSize调大生成更高清的bitmap,但同时又通过管理scale来让字体大小和原来一样。
字体类的代码
只是大概思路,还有很多可以完善的地方:#include "ui-UiTextFieldTTFNA.h"
Label * UiTextFieldTTFNA::create()
{
CC_ASSERT(false, "");
return nullptr;
}
float UiTextFieldTTFNA::getScale() const
{
return Node::getScale() * _precisionScale;
}
void UiTextFieldTTFNA::setScale(float scale)
{
Node::setScale(scale / _precisionScale);
}
float UiTextFieldTTFNA::getPrecisionScale() const
{
return _precisionScale;
}
void UiTextFieldTTFNA::setPrecisionScale(float scale)
{
auto fontSize = getFontSize();
auto fontScale = getScale();
_precisionScale = scale;
setFontSize(fontSize);
setScale(fontScale);
}
float UiTextFieldTTFNA::getFontSize() const
{
auto oldConfig = getTTFConfig();
auto fontSize = oldConfig.fontSize;
return fontSize / _precisionScale;
}
void UiTextFieldTTFNA::setFontSize(float sizes)
{
auto oldConfig = getTTFConfig();
auto fontName = oldConfig.fontFilePath;
auto fontSize = sizes * _precisionScale;
TTFConfig ttfConfig(fontName, fontSize, GlyphCollection::DYNAMIC);
setTTFConfig(ttfConfig);
}
void UiTextFieldTTFNA::draw(Renderer * renderer, const Mat4 & transform, uint32_t flags)
{
for (auto batchNode : _batchNodes){
auto texture0 = batchNode->getTextureAtlas()->getTexture();
auto texture1 = batchNode->getTexture();
texture0->setAliasTexParameters();
texture1->setAliasTexParameters();
}
TextFieldTTF::draw(renderer, transform, flags);
}
UiTextFieldTTFNA * UiTextFieldTTFNA::textFieldWithPlaceHolder(const std::string & placeholder, const Size & dimensions, TextHAlignment alignment, const std::string & fontName, float fontSize)
{
UiTextFieldTTFNA *ret = new (std::nothrow) UiTextFieldTTFNA();
if (ret && ret->initWithPlaceHolder("", dimensions, alignment, fontName, fontSize))
{
ret->_precisionScale = 1.0f;
ret->setPrecisionScale(3);
ret->autorelease();
if (placeholder.size() > 0)
{
ret->setPlaceHolder(placeholder);
}
return ret;
}
CC_SAFE_DELETE(ret);
return nullptr;
}
UiTextFieldTTFNA * UiTextFieldTTFNA::textFieldWithPlaceHolder(const std::string & placeholder, const std::string & fontName, float fontSize)
{
UiTextFieldTTFNA *ret = new (std::nothrow) UiTextFieldTTFNA();
if (ret && ret->initWithPlaceHolder("", fontName, fontSize))
{
ret->_precisionScale = 1.0f;
ret->setPrecisionScale(3);
ret->autorelease();
if (placeholder.size() > 0)
{
ret->setPlaceHolder(placeholder);
}
return ret;
}
CC_SAFE_DELETE(ret);
return nullptr;
}
这里是一个专注于游戏开发的社区,我们致力于为广大游戏爱好者提供一个良好的学习和交流平台。我们的专区包含了各大流行引擎的技术博文,涵盖了从入门到进阶的各个阶段,无论你是初学者还是资深开发者,都能在这里找到适合自己的内容。除此之外,我们还会不定期举办游戏开发相关的活动,让大家更好地交流互动。加入我们,一起探索游戏开发的奥秘吧!
更多推荐
所有评论(0)