標籤:

如何利用shader在文字上添加漸變陰影的效果?


Signed distance field(有向距離場)。源於Valve在siggraph07的一篇paper:Improved Alpha-Tested Magnification for Vector Textures and Special Effects。這篇文章的主旨是通過有向距離場的平滑插值來代替傳統的alpha-test來渲染文字,可以使用較小的文本紋理且放大不會嚴重失真,且能夠和傳統的alpha-test的方法無縫整合,在文本渲染上有很大的優勢,劣勢(也算不上劣勢)是需要通過一張較大的文本圖片預計算出較小的一張有向距離場紋理。

這裡有一個使用簡單alpha-test技術,使用雙線性插值技術以及使用上文所提的方法實現的文本渲染效果的一個對比:

可以看出基於SDF的方法邊緣明顯好於前兩者。

用二值標定一個圖片上像素,比如黑表示內部,白表示外部,則有向距離場表示的是任意一個像素到其邊界(黑白交界處)的最近距離,這個距離可以用於平滑的插值,也可以產生題主問到的投影效果,除此以外,它還可以產生外發光等文本效果。

下圖表示的是一張圖片和它對應的SDF(圖片來自於Valve的Paper):

看起來還是比較直觀的是不是,利用它可以實現的特殊文本效果Valve也舉了一些例子:

(1)外發光

(2)投影

這個技術應該是最初應用在《軍團要塞2》這款遊戲里。他們同年在NPAR上關於《軍團要塞2》的卡通渲染也是一篇非常好的paper:Illustrative Rendering in Team Fortress 2

SDF是通過預計算得到的,演算法比較簡單,是一個最近距離傳遞的概念,從思想上應該算是動態規劃,它的CPU實現版本的時間複雜度是O(N),對應也有一個多pass的GPU版本,複雜度是O(N*log(N))。


opengl es 文本描邊的 shader

const char* ccLabelOutline_frag = STRINGIFY(

#ifdef GL_ES

precision lowp float;

#endif

varying vec4 v_fragmentColor;
varying vec2 v_texCoord;

uniform vec4 u_effectColor;
uniform vec4 u_textColor;

void main()
{
vec4 sample = texture2D(CC_Texture0, v_texCoord);
float fontAlpha = sample.a;
float outlineAlpha = sample.r;
if ((fontAlpha + outlineAlpha) &> 0.0){
vec4 color = u_textColor * fontAlpha + u_effectColor * (1.0 - fontAlpha);
gl_FragColor = v_fragmentColor * vec4( color.rgb,max(fontAlpha,outlineAlpha)*color.a);
}
else {
discard;
}
}
);

shader代碼 摘自 cocos2d-x


推薦閱讀:

這款遊戲中 主角被遮擋部分變成半透明的效果是如何實現的?
unity 最後一次drawcall 如何避免?
在U3D等引擎當道的年代,我有沒有必要學opengl/dx或者osg???
如何開始寫一個virtual globe軟體,類似於google earth那樣?
3d引擎開發需要那些技能儲備?

TAG:OpenGL | shader |