neheopengl:NeHe OpenGL Lesson 15 翻译



Lesson 15 具有纹理贴图轮廓字体(Texture Mapped Outline Fonts)   在发布了前两篇有关位图字体和轮廓字体教程以后我收到很多邮件很多读者都想知道如何才能给字体赋予纹理贴图你可以使用自动纹理坐标生成器它会为字体上个多边形生成纹理坐标

  个小注释这段代码是专门针对Windows写它使用了Windowswgl来创建字体显然Apple机系统有aglX系统有glx来支持做同样事情不幸我不能保证这些代码也是容易使用如果哪位有能在屏幕上显示文字且独立于平台代码请告诉我我将重写个有关字体教程

  我们将使用第14课代码来创作纹理字体演示如果中哪部分代码有变化我会重写那部分所有代码以便看出我做改动

下面这部分代码类似于第14课代码但是这次我们还要加上stdarg.h头文件

# <windows.h> // Header File For Windows
# <math.h> // Header File For Math Library
# <stdio.h> // Header File For Standard Input/Output
# <gl\\gl.h> // Header File For The OpenGL32 Library
# <gl\\glu.h> // Header File For The GLu32 Library
# <gl\\glaux.h> // Header File For The Glaux Library

HDC hDC=NULL; // Private GDI Device Context
HGLRC hRC=NULL; // Permanent Rendering Context
HWND hWnd=NULL; // Holds Our Window Handle
HINSTANCE hInstance; // Holds The Instance Of The Application

bool keys[256]; // Array Used For The Keyboard Routine
bool active=TRUE; // Window Active Flag Set To TRUE By Default
bool fullscreen=TRUE; // Fullscreen Flag Set To Fullscreen Mode By Default

我们还要添加个叫做texture整型变量它用于保存纹理后面3行是第14课中代码本课不做改动

GLu texture[1]; // _disibledevent=>font = CreateFont( -12, // Height Of Font
0, // Width Of Font
0, // Angle Of Escapement
0, // Orientation Angle
FW_BOLD, // Font Weight
FALSE, // Italic
FALSE, // Underline
FALSE, // Strikeout

这就是有魔力行!不使用第14课中ANSI_CHARSET我们将使用SYMBOL_CHARSET这会告诉Windows我们创建字体并不是由标准组成典型字体所谓符号字体通常是由些小图片(符号)组成如果你忘了改变这行wingdings,webdings以及你想用其它符号字体就不会工作

SYMBOL_CHARSET, // Character Set Identier

下面几行没有变化

OUT_TT_PRECIS, // Output Precision
CLIP_DEFAULT_PRECIS, // Clipping Precision
ANTIALIASED_QUALITY, // Output Quality
FF_DONTCARE|DEFAULT_PITCH, // Family And Pitch

既然我们已经选择了符号集标识符我们就可以选择wingdings字体了!

\"Wingdings\"); // Font Name

剩下几行代码没有变化

SelectObject(hDC, font); //Selects The Font We Created

wglUseFontOutlines( hDC, // Select The Current DC
0, // Starting Character
255, // Number Of Display Lists To Build
base, // Starting Display Lists

我们允许有更多误差这意味着GL不会严格遵守字体轮廓线如果你把误差设置为0.0f你就会发现严格地在曲面上贴图存在些问题但是如果你允许误差很多问题都可以避免

0.1f, // Deviation From The True Outlines

下面 3行代码还是相同

0.2f, // Font Thickness In The Z Direction
WGL_FONT_POLYGONS, // Use Polygons, Not Lines
gmf); // Address Of Buffer To Recieve Data
}

在ReSizeGLScene的前我们要加上下面段代码来读取纹理你可能会认得这些前几课中代码我们创建个保存位图地方读取位图告诉Windows生成个纹理并把它保存在texture[0]中

我们创建种细化纹理(mipmapped texture)这样会看起来好些纹理名字叫做lights.bmp

AUX_RGBImageRec *LoadBMP(char *Filename) // Loads A Bitmap Image
{
FILE *File=NULL; // File Handle

(!Filename) // Make Sure A Filename Was Given
{
NULL; // If Not Return NULL
}

File=fopen(Filename,\"r\"); // Check To See If The File Exists

(File) // Does The File Exist?
{
fclose(File); // Close The Handle
auxDIBImageLoad(Filename);// Load The Bitmap And Return A Poer
}
NULL; // If Load Failed Return NULL
}

LoadGLTextures // Load Bitmaps And Convert To Textures
{
Status=FALSE; // Status Indicator

AUX_RGBImageRec *TextureImage[1]; // Create Storage Space For The Texture



mem(TextureImage,0,(void *)*1); // Set The Poer To NULL

(TextureImage[0]=LoadBMP(\"Data/Lights.bmp\")) // Load the Bitmap
{
Status=TRUE; // Set The Status To TRUE

glGenTextures(1, &texture[0]); // Create The Texture

// Build Linear Mipmapped Texture

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);

下面 4行代码将为我们绘制在屏幕上任何物体自动生成纹理坐标glTexGen非常强大而且复杂如果要完全讲清楚它数学原理需要再写篇教程不过你只要知道GL_S和GL_T是纹理坐标就可以了默认状态下它被设置为提取物体此刻在屏幕上x坐标和y坐标并把它们转换为顶点坐标你会发现到物体在z平面没有纹理只显示些斑纹正面和反面都被赋予了纹理这些都是由glTexGen产生(X(GL_S)用于从左到右映射纹理Y(GL_T)用于从上到下映射纹理

GL_TEXTURE_GEN_MODE允许我们选择我们想在S和T纹理坐标上使用纹理映射模式你有3种选择:

GL_EYE_LINEAR - 纹理会固定在屏幕上它永远不会移动物体将被赋予处于它通过地区块纹理

GL_OBJECT_LINEAR - 这种就是我们使用模式纹理被固定于在屏幕上运动物体上
GL_SPHERE_MAP - 每个人都喜欢创建种有金属质感物体

需要注意是我省略了很多代码我们还需要设置GL_OBJECT_PLANE但是默认参数就是我们想要参数如果你想了解更多那就买本好书或者查阅MSDN

// Texturing Contour Anchored To The Object

glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);

// Texturing Contour Anchored To The Object

glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);
}

(TextureImage[0]) // If Texture Exists
{
(TextureImage[0]->data) // If Texture Image Exists
{
free(TextureImage[0]->data); // Free The Texture Image Memory
}
free(TextureImage[0]); // Free The Image Structure
}
Status; // Return The Status
}

在InitGL最后有几行新代码BuildFont被放到了读取纹理代码的后glEnable(GL_COLOR_MATERIAL) 这行被删掉了如果你想使用glColor3f(r,g,b)来改变纹理颜色那么就把glEnable(GL_COLOR_MATERIAL)这行重新加到这部分代码中

InitGL(GLvoid) // All Setup For OpenGL Goes Here
{
(!LoadGLTextures) // Jump To Texture Loading Routine
{
FALSE; // If Texture Didn\'t Load Return FALSE
}
BuildFont; // Build The Font

glShadeModel(GL_SMOOTH); // Enable Smooth Shading
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background
glClearDepth(1.0f); // Depth Buffer Setup
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do
glEnable(GL_LIGHT0); // Quick And Dirty Lighting (Assumes Light0 Is Set Up)
glEnable(GL_LIGHTING); // Enable Lighting
glH(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations

启动2D纹理映射并选择第个纹理这样就把第个纹理映射到我们绘制在屏幕上3D物体上了如果你想加入更多操作可以按自己意愿启动或禁用纹理映射

glEnable(GL_TEXTURE_2D); // Enable Texture Mapping
glBindTexture(GL_TEXTURE_2D, texture[0]); // Select The Texture
TRUE; // Initialization Went OK

重置大小代码没有变化但DrawGLScene这部分代码有变化

DrawGLScene(GLvoid) // Here\'s Where We Do All The Drawing
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
glLoadIdentity; // Re The View

这里是第处变动我们打算使用COS和SIN让物体绕着屏幕旋转而不是把它固定在屏幕中间我们将把物体向屏幕里移动3个单位在x轴我们将移动范围限制在-1.1到+1.1的间我们使用rot变量来控制左右移动我们把上下移动范围限制在+0.8到-0.8的间同样使用rot变量来控制上下移动(最好充分利用你变量)

Position The Texture
glTranslatef(1.1f*float(cos(rot/16.0f)),0.8f*float(sin(rot/20.0f)),-3.0f);

下面做常规旋转这会使符号在XY和Z轴旋转

glRotatef(rot,1.0f,0.0f,0.0f); // Rotate _disibledevent=> TRUE; // Keep Going
}

最后要做事就是在KillGLWindow最后添加KillFont如下所示添加这行代码很重要它将在我们退出的前做清理工作



(!UnregisterClass(\"OpenGL\",hInstance)) // Are We Able To Unregister Class
{
MessageBox(NULL,\"Could Not Unregister Class.\",\"SHUTDOWN ERROR\",MB_OK | MB_ICONINFORMATION);
hInstance=NULL; // Set hInstance To NULL
}
KillFont;

  尽管我没有讲细致入微但我想你应该很好理解了如何让OpenGL为你生成纹理坐标在给你字体或者是同类物体赋予纹理映射时应该没有问题了而且只需要改变两行代码你就可以启用球体映射了效果简直酷毙了!


原著:Jeff Molofee (NeHe) http://nehe.gamedev.net
翻译:史峰 sh[email protected] 山西太原



Tags:  nehe中文 neheopengl源代码 neheopengl教程 neheopengl

延伸阅读

最新评论

发表评论