分享
 
 
 

SM3D的OpenGL教程(一):超酷三维汉字特效

王朝vc·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

大家好,我是Skyman(SM3D),喜欢三维编程,现在正在系统学习OpenGL,DirectX,VR等.我经常到各大论坛上去转转.其中去得最多的地方是NeHe的OpenGL网站(http://nehe.gamedev.net),那是我所见过的最好的学习OpenGL的网站,强烈推荐!!!这是我的第一篇关于OpenGL的文章,写得不是很好,欢迎大家指正.

大家知道,在OpenGL中输出文本有两个函数:wglUseFontBitmaps和wglUseFontOutlines,前者用来输出2维文字,后者用来输出3维文字.而要输出汉字,必须使用TrueType字体.本文就教你如何使用wglUseFontOutlines来创建很酷的三维汉字特效.从此文,你可以学到三点知识:1.如何从文件中载入位图作为纹理;2.如何生成三维汉字;3.如何将纹理贴到三维汉字上.本程序运行效果如下图所示:

我使用的是NeHe的Simple框架.为了简便起见,我这里只列出增加的代码.

首先,再头文件定义区加上:#include <stdio.h>

接着,在bool fullscreen=TRUE;后面定义要用到的变量:

GLuint texture[1];//纹理ID

int rot=0;//三维汉字绕x轴旋转的角度

HFONT hFont;//字体句柄

LOGFONT lf;//逻辑字体

GLYPHMETRICSFLOAT gmf[128];//包括字形的位置和方向信息的结构

unsigned int ichar=0; //字符的整型值

char cchar; //要转换为显示列表的字符

unsigned int i=0;//循环变量

unsigned int j=0; //循环变量

char Text[128];//存放要显示的字符的数组

BYTE TextList[128];//显示列表

const GLuint ListBase=1000; //显示列表的基

然后在LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);后面定义载入文理的函数LoadBMP和LoadGLTextures,这个在NeHe的许多教程里都有,这里再写一下:

AUX_RGBImageRec *LoadBMP(char *Filename) // 载入位图

{

FILE *File=NULL; // 文件句柄

if (!Filename) //文件名已给了吗?

{

return NULL; // 若没有则返回NULL

}

File=fopen(Filename,"r"); // 检查文件是否存在

if (File) // 文件存在吗?

{

fclose(File); // 关闭文件

return auxDIBImageLoad(Filename); // 载入位图并返回位图的指针

}

return NULL; // 若载入失败则返回NULL

}

int LoadGLTextures() // 载入位图并转换为纹理

{

int Status=FALSE; // 状态指示

AUX_RGBImageRec *TextureImage[1]; // 为纹理创建存储空间

memset(TextureImage,0,sizeof(void *)*1); // 清零

// 载入位图,检查误,如位图不存在则退出

if (TextureImage[0]=LoadBMP("Data/tex.bmp"))//纹理图片的路径

{

Status=TRUE; // 状态设为TRUE

glGenTextures(1, &texture[0]); // 创建纹理

glBindTexture(GL_TEXTURE_2D, texture[0]);

gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);//过滤

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);//过滤

glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);//自动生成纹理坐标

glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);//自动生成纹理坐标

glEnable(GL_TEXTURE_GEN_S);

glEnable(GL_TEXTURE_GEN_T);

}

if (TextureImage[0]) // 如果纹理存在

{

if (TextureImage[0]->data) // 如果纹理图象存在

{

free(TextureImage[0]->data); // 释放纹理图象所占用的内存

}

free(TextureImage[0]); // 释放图象结构

}

return Status; // 返回状态

}

注明:因为三维字体是比较复杂的模型,所以要手工定义纹理坐标很难.我们可以让OpenGL自动生成纹理坐标.函数glTexGen()用于自动生成纹理坐标.

Void gltexgen{ifd}(GLenum coord,GLenum pname,TYPE param);

参数coord必须是GL_S,GL_T,GL_R或GL_Q,表明是否要生成纹理坐标s,t,r或q.参数pname为GL_TEXTURE_GEN_MODE,表示纹理坐标的生成模式.参数param可选GL_OBJECT_LINEAR,GL_EYE_LINEAR或GL_SPHERE_MAP. GL_OBJECT_LINEAR表示纹理图象相对于一个移动的物体静止,本程序就采用这种方式.

然后在InitGL()函数中的glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);后面加入如下语句:

glEnable(GL_LIGHT0); // 激活默认光照 (虽然光照效果不是很好但是速度快)

glEnable(GL_LIGHTING); // 激活光照

glEnable(GL_COLOR_MATERIAL);//激活材质颜色

glEnable(GL_TEXTURE_2D);//激活二维纹理

glBindTexture(GL_TEXTURE_2D, texture[0]);//绑定纹理

memset(&lf,0,sizeof(LOGFONT));//清空内存

//设定逻辑字体lf的属性

lf.lfHeight=-1;//指定字高

lf.lfWidth = -1 ;//指定字宽

lf.lfEscapement = 0 ; //指定角度(1/10度)

lf.lfOrientation = 0 ; //指定字符的基线与x轴的角度(1/10度)

lf.lfWeight = FW_BOLD ; //指定字体的重量(FW_BOLD=700)

lf.lfItalic = FALSE ;//指定是否斜体

lf.lfUnderline = FALSE ; //指定是否有下划线

lf.lfStrikeOut = FALSE ; //指定是否是StrikeOut字体

lf.lfCharSet = ANSI_CHARSET ; //指定字符集

lf.lfOutPrecision = OUT_TT_PRECIS ; //指定输出精度

lf.lfClipPrecision= CLIP_DEFAULT_PRECIS ; //指定裁剪精度

lf.lfQuality = PROOF_QUALITY ;//指定输出质量

lf.lfPitchAndFamily = VARIABLE_PITCH | TMPF_TRUETYPE | FF_MODERN ; //指定字体的定位和外观

lstrcpy (lf.lfFaceName, "宋体") ; //指定字体名称

hFont=CreateFontIndirect(&lf);//创建逻辑字体

SelectObject(hDC, hFont);//将逻辑字体选入设备环境

然后在DrawGLScene()函数中的glLoadIdentity();后面加入:

strcpy(Text,"重庆大学欢迎你");//指定所要显示的字符

i=0;//对i赋初制值

j=0;// 对j赋初制值

while(i<128)

{

if(IsDBCSLeadByte(Text[i]))//判断是否为双字节

{

ichar=Text[i];

ichar=(ichar<<8)+256; //256为汉字内码的“偏移量”

ichar=ichar+Text[i+1];

i++;i++;

wglUseFontOutlines(hDC, //设备环境句柄

ichar, //要转换为显示列表的第一个字符

1, //要转换为显示列表的字符数

1000+j, //显示列表的基数

0.0f, //指定与实际轮廓的最大偏移量

0.2f, //在Z轴负方向的值

WGL_FONT_POLYGONS, //指定显示列表用多边形创建字体

&gmf[j]); //接受字符的地址

TextList[j]=j;

j++;

}

Else//若是单字节(英文)

{

cchar=Text[i];

i++;

wglUseFontOutlines(hDC, //设备环境句柄

cchar, //要转换为显示列表的第一个字符

1, //要转换为显示列表的字符数

1000+j, //显示列表的基数

0.0f, //指定与实际轮廓的最大偏移量

0.5f, //在Z轴负方向的值

WGL_FONT_POLYGONS, //指定显示列表用多边形创建字体

&gmf[j]); //接受字符的地址

TextList[j]=j;

j++;

}

}

glListBase(ListBase);//设置显示列表的初始索引值

glTranslatef(-4.0f,0.0f,-10.0f);//要显示的文本的位置

glRotatef(float(rot),1.0f,0.0f,0.0f);//文本绕x轴旋转

glCallLists(strlen(Text),GL_UNSIGNED_BYTE,& TextList);//调用多显示列表绘制文本

glFlush();//强制绘图

rot=(rot+1)%360;//旋转变量递增

注明:1. 双字节内码DBCS(双字节字符集) 支持很多不同的东亚语言字母,如汉语、日语和朝鲜语等。 DBCS 使用数字 0–128 表示 ASCII 字符集。其它大于 128 的数字作为前导字节字符,它并不是真正的字符,只是简单的表明下一个字符属于非拉丁字符集。在 DBCS 中,ASCII 字符的长度是一个字节,而日语、朝鲜语和其它东亚字符的长度是 2 个字节。汉字内码的偏移量为256。

2.执行多显示列表可以有效的提高渲染速度。方法是将显示列表的索引值放入一个数组中,然后调用glCallLists()命令。对于有多种字体的情况,需要为每种字体建立一个不同的初始显示列表索引值。这些初始索引值可以在调用glCallLists()函数之前,通过调用glListBase()函数来指定。该函数指定一个偏移量,该偏移量被加到glCallLists()函数中的显示列表索引中,以获取最终的显示列表索引值。函数glCallLists(n,type,*lists)执行n个显示列表。所执行的列表索引值是由当前显示列表基(由glListBase()指定)指明的偏移量,加上由 lists指向的数组中的整数之和。

OK。一切搞定!编译运行,你看到了什么!不错,很酷的三维汉字特效!(注:本程序不仅可以显示汉字,也可以显示英文:))。你可以加入光照、材质、雾等效果,使它更酷!!!

这是我的第一个关于OpenGL的教程,如果你发现有什么错误或有什么意见,请写信给我。我的E-mail是:skyman_2001@163.com,QQ:175910174,我的网站是:http://sm3d.126.com,欢迎交流!

下载源代码:Visual C++ (注:下载的文件后缀名为.txt,将其后缀名改为.rar,再用WinRar解压缩即可.源代码存放在免费空间上,不稳定,哪位有稳定的存放空间可以供我存放请通知我)

向 NeHe 学 习!!!

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有