提起3D文字制作,不少人會馬上想到3D MAX等一些專門的3維制作工具,即使選用VC以編程的手段來實現也多是假手於OpenGL圖形開發庫來完成。熟悉OpenGL開發的編程人員一定對其初始化、材質以及燈光的渲染等一系列煩瑣而又必要的編程過程深有感觸。雖然通過以上的手段可以產生出包括3D文字在內的質感相當強的3維圖形,但如果程序僅需要產生不很復雜的3D文字,而采用OpenGL去實現未免顯得大材小用。其實在要求不很苛刻的情況下,完全可以通過MFC提供的CFont類制作出層次感較強的3D文字,其實現過程要比OpenGL簡練得多。
實現原理
計算機屏幕是平面二維的,我們之所以能欣賞到真如實物般的三維圖像,是因為顯示在計算機屏幕上時色彩灰度的不同而使人眼產生視覺上的錯覺,而將二維的計算機屏幕感知為三維圖像。基於色彩學的有關知識,三維物體邊緣的凸出部分一般顯高亮度色,而凹下去的部分由於受光線的遮擋而顯暗色。這一認識被廣泛應用於網頁或其他應用中對按鈕、3D線條的繪制。對於本文所要繪制的3D文字同樣也適用,即在原始位置顯示高亮度顏色,而在左下或右上等位置用低亮度顏色勾勒出其輪廓,這樣在視覺上便會產生3D文字的效果。具體實現時,可用完全一樣的字體在不同的位置分別繪制兩個不同顏色的2D文字,只要使兩個文字的坐標合適,就完全可以在視覺上產生出不同效果的3D文字。
具體實現
在實現3D文字時一般不使用缺省的字體設置,而是通過對字體的設置而使產生的3D文字在視覺上更美觀。在使用CFont類時,首先要通過其成員函數CreateFontIndirect根據預先設定好的LOGFONT結構來初始化CFont對象:
CFont m_font;
……
m_font.CreateFontIndirect(&lf);
其參數為一個指向LOGFONT結構的指針。LOGFONT結構主要定義了字體的屬性,其定義可通過MSDN幫助查到:
typedef struct tagLOGFONT {
LONG lfHeight;
//字符字體高度
LONG lfWidth; //字符平均寬度
LONG lfEscapement;
//文本行逆時針旋轉角度
LONG lfOrIEntation; //字體角度
LONG lfWeight; //字體粗細程度
BYTE lfItalic; //傾斜
BYTE lfUnderline; //下劃線
BYTE lfStrikeOut; //刪除線
……
} LOGFONT;
在對其進行設置時,lfOutPrecision、lfClipPrecision、lfQuality 以及lfPitchAndFamily這幾個成員變量一般可如下設置而無需改動:
LOGFONT lf;
//lf定義字體屬性
lf.lfOutPrecision= OUT_STROKE_PRECIS;
lf.lfClipPrecision= CLIP_STROKE_PRECIS;
lf.lfQuality = DRAFT_QUALITY;
lf.lfPitchAndFamily= VARIABLE_
PITCH|FF_MODERN;
對於其他的成員變量則要根據實際需求進行具體的設定。例如,對於本文要顯示的沒有下劃線和刪除線並且沒有傾斜處理的粗體幼圓漢字,可以采取如下設置:
lf.lfHeight = 50;
lf.lfWidth = 0;
lf.lfEscapement = 0;
lf.lfOrIEntation = 0;
lf.lfWeight = FW_HEAVY;
lf.lfItalic = FALSE;
lf.lfUnderline = FALSE;
lf.lfStrikeOut = FALSE;
lf.lfCharSet = GB2312_CHARSET; strcpy(lf.lfFaceName,“幼圓”);
同其他使用CDC繪圖類進行繪圖的程序類似,對字體進行繪制處理也是在視類的OnDraw()函數中完成的。首先需要選擇前面設定好的字體,由於3D文字的顯示是靠兩層(甚至更多層)文字的疊加而成,因此需要並將其背景設定透明,否則將僅在文字的輪廓處有3D效果,而文字內部仍是平面的:
CFont* pOldFont = (CFont*)pDC->SelectObject(&m_font);
pDC->SetBkMode(TRANSPARENT);
在此為了說明原理僅選擇了兩層文字進行疊加,可通過API函數GetSysColor獲得當前系統的三維高亮度色和三維低亮度色,並對字體進行設置,由於3維文字是文字在前,陰影在後,所以需要先對陰影部分進行繪制:
pDC->SetTextColor(::GetSysColor(COLOR_3DDKSHADOW));
pDC->TextOut(10,10,sTemp); //sTemp為待顯示文字
此時的效果如下圖所示,但仍是2維文字:
為了顯示出3維效果,需要在其上覆蓋上一層高亮度文字,顯然坐標不能仍是(10,10),否則顯示出的文字仍是2維的。一般可通過錯開一兩個像素來達到不同光源位置的3D文字效果,比如在此就是在原位置向右上移動了3個像素,可通過在平面移動適當的距離來控制3D效果的深度:
pDC->SetTextColor(::GetSysColor(COLOR_3DHILIGHT));
pDC->TextOut(13,7,sTemp);
從下圖可以看出此時已經具有了立體感相當強的視覺效果了:
另外,還可以通過設置路徑對象來對普通的3D文字進行輪廓勾勒,使之具備特殊的3D效果:
pDC->BeginPath(); //開始路徑
pDC->TextOut(13,7,sTemp,19);
//向路徑輸出漢字
pDC->EndPath(); //結束路徑
pDC->SetPolyFillMode(WINDING); //填充路徑
pDC->StrokeAndFillPath(); //繪制路徑外觀、設置填充模式
下圖便為通過路徑輸出而得到的勾勒出輪廓的空心3D文字:
結束語
本文通過對CFont類和CDC繪圖類的使用,結合色彩學的有關知識,成功地在VC下以簡單的代碼實現了效果比較好的3維立體文字。CFont類對字體控制的能力還是很強的,通過對CFont類的深入研究,可對字體的顯示做出更加完備的控制。