三维设计在人脸仿真上的应用软件工程课程设计Word下载.docx
《三维设计在人脸仿真上的应用软件工程课程设计Word下载.docx》由会员分享,可在线阅读,更多相关《三维设计在人脸仿真上的应用软件工程课程设计Word下载.docx(13页珍藏版)》请在冰豆网上搜索。
他所生成的图形文件格式是3DS文件格式,此格式是一种很普遍的数据格式,以3DS
保存的三维图形文件非常丰富。
我们可以在计算机上直接利用3DSMAX软件制作3DS格式的三维图形,并通过读取和操作3DS文件达到我们的目的。
3.1.1人脸的创建
启动FaceGen,并调节各项参数,建立一个初步的人头模型。
并将其保存为3DS文件格式。
FaceGen是一个参数化的三维人头模型建立工具。
图1人脸模型
3.1.2完善人头模型
将建立的人头模型导入到3dmax7.0中,采用3dmax的建模工具和命令对模型进行调整使其更逼真,主要用到的命令有多边形挤压命令,多变形修改命令,镜像半边命令。
并设置模型的皮肤纹理贴图。
3.1.3创建头发的模型
图2头发模型
3.1.4优化模型
用3dmax7.0的hairFX插件进一步优化和完美头发的模型,使其数据量更小,材质更逼真。
形成的模型样品图样
图3样品a图4样品b
模型建成后得到的是一个3ds格式的文件,简要介绍一下3ds文件:
3DS文件由许多块组成,每个块首先描述其信息类别,即该块是如何组成的。
块的信息类别用ID来标识,块还包含了下一个块的相对位置信息。
因此,即使不理解一个块的含义,也可以很容易地跳过它,因为该块中指出了下一个块地相对于改块的起始位置地偏移字节数。
与许多文件格式一样,3DS二进制文件中的数据也是按低位在前,高位在后的方式组织的。
例如,2个十六进制字节4A5C3B8F,表明5C4A是低位字节,而8F3B是高位字节。
块的前两项信息分别是:
块的ID和块的长度(也即下一个块相对于改块的字节偏移量),块的ID是一个整形数,而块的长度是一个长整形数。
每个块实际上是一个层次结构,不同类型的块,其层次结构也不相同。
3DS文件中有一个基本块,其ID是4D4D,每一个3DS文件的开头都是由这样一个块构成。
基本块内的块称为主块。
3.2导入转换阶段
此阶段的关键是OpenGL在人脸建模中的应用。
OpenGL在Windows平台上主要有以下几个图库:
基本库opengl32.lib,头文件为gl.h,函数共有100多个,都是最基本,最重要的函数,函数前缀为gl如画点函数glVertex);
实用库glu32.lib,头文件为glu.h,其中函数功能相对高级,如绘制复杂的曲线曲面,高级坐标变换,多边形分割(polygonaltessellation)。
一共有40多个。
前缀为glu(如NURBS曲面函数gluNurbsSurface);
辅助库glaux.lib,头文件为glaux.h,是一些鼠标、键盘控制、窗口管理等简单的交互函数和常用三维物体的绘制函数。
一共有30多个。
前缀为aux如窗口初始化函数auxInitWindow)。
由于简单,大型的OpenGL程序很少使用到这一套函数。
近年来,OpenGL的编程者比较多地使用到一个叫实用工具库glut32.lib,头文件glut.h。
辅助库可以看作是实用工具库的一个子集。
工具库还提供了许多辅助库没有的功能,如菜单操作等。
前缀为glut
如菜单创建函数glutCreateMenu)。
此外,还有六个WGL函数非常重要,专门用于OpenGL和Windows窗口系统的联接,其前缀为wgl,主要用于创建和选择图形操作描述(renderingcontexts)以及在窗口内任一位置显示字符位图。
一个OpenGL的Windows应用程序的基本操作步骤如下:
创建OpenGL的着色环境包括设定象素格式,创建着色环境,把着色环境指定为当前的着色环境;
进行OpenGL相关的初始化,如设立灯光,质材,纹理,变换等等;
绘制图形;
将着色环境设为非当前使用,释放着色环境。
3.2.1创建OpenGL窗口
#include<
windows.h>
//Windows的头文件
#include<
gl\gl.h>
//OpenGL32库的头文件
gl\glu.h>
//GLu32库的头文件
gl\glaux.h>
//GLaux库的头文件
设置计划在程序中使用的所有变量。
第一行设置的变量是着色描述表(RenderingContext)。
每一个OpenGL都被连接到一个着色描述表上。
着色描述表将所有的OpenGL调用命令连接到设备描述表(DeviceContext)上。
还需要创建一个设备描述表,也就是第二行的内容。
第三行的变量hWnd将保存由Windows给我们的窗口指派的句柄。
最后,第四行为我们的程序创建了一个Instance(实例)。
HGLRChRC=NULL;
//永久着色描述表
HDChDC=NULL;
//私有GDI设备描述表
HWNDhWnd=NULL;
//保存我们的窗口句柄
HINSTANCEhInstance;
//保存程序的实例
下面是重新设置OpenGL场景的大小,而不管窗口的大小是否已经改变(假定没有使用全屏模式)。
甚至无法改变窗口的大小时(例如在全屏模式下),它至少仍将运行一次—在程序开始时设置我们的透视图。
OpenGL场景的尺寸将被设置成它显示时所在窗口的大小。
GLvoidReSizeGLScene(GLsizeiwidth,GLsizeiheight) //重置并初始化窗口大小
下面为透视图设置屏幕。
意味着越远的东西看起来越小。
这么做创建了一个现实外观的场景。
此处透视按照基于窗口宽度和高度的45度视角来计算。
0.1f,100.0f是我们在场景中所能绘制深度的起点和终点。
投影矩阵负责为我们的场景增加透视。
glLoadIdentity()近似于重置。
它将所选的矩阵状态恢复成其原始状态。
调用glLoadIdentity()之后我们为场景设置透视图。
glMatrixMode(GL_MODELVIEW)指明任何新的变换将会影响模型观察矩阵(modelviewmatrix)。
模型观察矩阵中存放了我们的物体讯息。
最后我们重置模型观察矩阵。
glMatrixMode(GL_PROJECTION);
//选择投影矩阵
glLoadIdentity();
//重置投影矩阵
//计算窗口的外观比例
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);
glMatrixMode(GL_MODELVIEW);
//选择模型观察矩阵
//重置模型观察矩阵
接下来,对OpenGL进行所有的设置。
我们将设置清除屏幕所用的颜色,打开深度缓存,启用阴影平滑(smoothshading),等等。
这个例程直到OpenGL窗口创建之后才会被调用。
intInitGL(GLvoid) //此处开始对OpenGL进行所有设置
以下启用阴影平滑(smoothshading)。
阴影平滑通过多边形精细的混合色彩,并对外部光进行平滑。
我将在另一个教程中更详细的解释阴影平滑。
glShadeModel(GL_SMOOTH);
//启用阴影平滑
以下设置清除屏幕时所用的颜色。
色彩值的范围从0.0f到1.0f。
0.0f代表最黑的情况,1.0f就是最亮的情况。
glClearColor后的第一个参数是红色分量(RedIntensity),第二个是绿色,第三个是蓝色。
最大值也是1.0f,代表特定颜色分量的最亮情况。
最后一个参数是Alpha值。
现在让它为0.0f。
通过混合三种原色(红、绿、蓝),您可以得到不同的色彩。
因此,当您使用glClearColor(0.0f,0.0f,1.0f,0.0f),您将用亮蓝色来清除屏幕。
如果您用glClearColor(0.5f,0.0f,0.0f,0.0f)的话,您将使用中红色来清除屏幕。
不是最亮(1.0f),也不是最暗(0.0f)。
要得到白色背景,您应该将所有的颜色设成最亮(1.0f)。
要黑色背景的话,您该将所有的颜色设为最暗(0.0f)。
glClearColor(0.0f,0.0f,0.0f,0.0f);
//黑色背景
接下来的三行必须做的是关于深度缓存(depthbuffer)的。
深度缓存是OpenGL十分重要的部分。
glClearDepth(1.0f);
//设置深度缓存
glEnable(GL_DEPTH_TEST);
//启用深度测试
glDepthFunc(GL_LEQUAL);
//所作深度测试的类型
以下为绘图部分。
任何所想在屏幕上显示的都将在此段代码中出现。
intDrawGLScene(GLvoid) //从这里开始进行所有的绘制
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
//清除屏幕和深度缓存
//重置当前的模型观察矩阵
创建OpenGL窗口。
此过程返回布尔变量(TRUE或FALSE)。
还带有5个参数:
窗口的标题栏,窗口的宽度,窗口的高度,色彩位数(16/24/32),和全屏标志(TRUE—全屏模式,FALSE—窗口模式)。
返回的布尔值告诉我们窗口是否成功创建。
BOOLCreateGLWindow(char*title,intwidth,intheight,intbits,boolfullscreenflag)
当我们要求Windows为我们寻找相匹配的象素格式时,Windows寻找结束后将模式值保存在变量PixelFormat中。
GLuintPixelFormat;
//保存查找匹配的结果
wc用来保存我们的窗口类的结构。
窗口类结构中保存着我们的窗口信息。
通过改变类的不同字段我们可以改变窗口的外观和行为。
每个窗口都属于一个窗口类。
当您创建窗口时,您必须为窗口注册类。
WNDCLASSwc;
//窗口类结构
dwExStyle和dwStyle存放扩展和通常的窗口风格信息。
使用变量来存放风格的目的是为了能够根据我需要创建的窗口类型(是全屏幕下的弹出窗口还是窗口模式下的带边框的普通窗口);
来改变窗口的风格。
DWORDdwExStyle;
//扩展窗口风格
DWORDdwStyle;
//窗口风格
下面取得矩形的左上角和右下角的坐标值。
我们将使用这些值来调整我们的窗口使得其上的绘图区的大小恰好是我们所需的分辨率的值。
通常如果创建一个640x480的窗口,窗口的边框会占掉一些分辨率的值。
RECTWindowRect;
//取得矩形的左上角和右下角的坐标值
WindowRect.left=(long)0;
//将Left设为0
WindowRect.right=(long)width;
//将Right设为要求的宽度
WindowRect.top=(long)0;
//将Top设为0
WindowRect.bottom=(long)height;
//将Bottom设为要求的高度
以下根据创建的窗体类型调整窗口。
调整的目的是使得窗口大小正好等于我们要求的分辨率。
通常边框会占用窗口的一部分。
使用AdjustWindowRectEx后,我们的OpenGL场景就不会被边框盖住。
实际上窗口变得更大以便绘制边框。
全屏模式下,此命令无效。
AdjustWindowRectEx(&
WindowRect,dwStyle,FALSE,dwExStyle);
//调整窗口达到真正要求的大小
下一段开始创建窗口并检查窗口是否成功创建。
我们将传递CreateWindowEx()所需的所有参数。
如扩展风格、类名字(与您在注册窗口类时所用的名字相同)、窗口标题、窗体风格、窗体的左上角坐标(0,0是个安全的选择)、窗体的宽和高。
我们没有父窗口,也不想要菜单,这些参数被设为NULL。
还传递了窗口的实例,最后一个参数被设为NULL。
注意我们在窗体风格中包括了WS_CLIPSIBLINGS和WS_CLIPCHILDREN。
要让OpenGL正常运行,这两个属性是必须的。
他们阻止别的窗体在我们的窗体内/上绘图。
if(!
(hWnd=CreateWindowEx(dwExStyle, //扩展窗体风格
"
OpenGL"
//类名字
title, //窗口标题
WS_CLIPSIBLINGS| //必须的窗体风格属性
WS_CLIPCHILDREN| //必须的窗体风格属性
dwStyle, //选择的窗体属性
0,0, //窗口位置
WindowRect.right-WindowRect.left, //计算调整好的窗口宽度
WindowRect.bottom-WindowRect.top, //计算调整好的窗口高度
hInstance, //实例
下面描述象素格式。
我们选择了通过RGBA(红、绿、蓝、alpha通道)支持OpenGL和双缓存的格式。
我们试图找到匹配我们选定的色彩深度(16位、24位、32位)的象素格式。
最后设置16位Z-缓存。
其余的参数要么未使用要么不重要(stencilbuffer:
模板缓存与accumulationbuffer:
聚集缓存除外)。
static PIXELFORMATDESCRIPTORpfd= //pfd告诉窗口我们所希望的
sizeof(PIXELFORMATDESCRIPTOR), //上诉格式描述符的大小
PFD_DRAW_TO_WINDOW| //格式必须支持窗口
PFD_SUPPORT_OPENGL| //格式必须支持OpenGL
PFD_DOUBLEBUFFER, //必须支持双缓冲
PFD_TYPE_RGBA, //申请RGBA格式
bits, //选定色彩深度
0,0,0,0,0,0, //忽略的色彩位
0, //无Alpha缓存
0, //忽略ShiftBit
0, //无聚集缓存
0,0,0,0, //忽略聚集位
16, //16位Z-缓存(深度缓存)
0, //无模板缓存
0, //无辅助缓存
PFD_MAIN_PLANE, //主绘图层
0, //保留
0,0,0 //忽略层遮罩
激活着色描述表。
如果无法激活,弹出错误消息,并退出程序(返回FALSE)。
if(!
wglMakeCurrent(hDC,hRC)) //尝试激活着色描述表
{
KillGLWindow();
//重置显示区
MessageBox(NULL,"
Can’tActivateTheGLRenderingContext."
"
ERROR"
MB_OK|MB_ICONEXCLAMATION);
returnFALSE;
//返回FALSE
}
OpenGL窗口已经创建完成,接着可以显示。
将它设为前端窗口(给它更高的优先级),并将焦点移至此窗口。
然后调用ReSizeGLScene将屏幕的宽度和高度设置给透视OpenGL屏幕。
ShowWindow(hWnd,SW_SHOW);
//显示窗口
SetForegroundWindow(hWnd);
//略略提高优先级
SetFocus(hWnd);
//设置键盘的焦点至此窗口
ReSizeGLScene(width,height);
//设置透视GL屏幕
跳转至InitGL(),这里可以设置光照、纹理、等等任何需要设置的选项。
if(!
InitGL()) //初始化新建的GL窗口
//重置显示区
InitializationFailed."
"
//返回FALSE
下面是Windows程序的入口。
将会调用窗口创建例程,处理窗口消息,并监视人机交互。
intWINAPIWinMain(HINSTANCEhInstance, //实例
HINSTANCEhPrevInstance, //前一个实例
LPSTR lpCmdLine, //命令行参数
int nCmdShow) //窗口显示状态
接着创建OpenGL窗口。
CreateGLWindow函数的参数依次为标题、宽度、高度、色彩深度,以及全屏标志。
就这么简单。
我很欣赏这段代码的简洁。
如果未能创建成功,函数返回FALSE。
程序立即退出。
//创建OpenGL窗口
if(!
CreateGLWindow("
NeHe’sOpenGLFramework"
640,480,16,fullscreen))
{
return0;
//失败退出
}
3.2.2设置光源
当人们观察物质表面时,眼睛感觉色彩是取决于到达和刺激锥体细胞的光子能量分布。
这些光子是由光源或结合光源所产生,其中一些光子被表面所吸收,而另一些光子被表面反射。
在OpenGL的光照模型中,场景中的光由某些光源产产生,它们可以单独地接通或断开。
有些光来自特定方向或位置,而有些光在场景周围被散射。
在OpenGL光照模型中,光源仅当存在吸收和反射光的表面时才会产生效果。
OpenGL的光照模型考虑光照分为四个独立部分的光:
发射、反射、
漫射和镜射。
独立计算所有的四个部分,而后相加在一起。
OpenGL提供了两种类型的光源:
定位光源和定向光源。
函数glLightfv()用于指定光源的位置,而不管它是定位光源还是定向光源。
函数glNormal()用于法向量的分配。
光源中指定的颜色分量与材质中指定的颜色分量有不同的意义。
对于材质,函数glMaterialfv()通过定义材质中颜色分量的值,定义材质的属性。
函数glColorMaterial()用于减小与材质属性有关的性能消耗。
最后必须通过glEnable(GL_LIGHTING)激活光照,并且调用glEnable(GL_LIGHTi)激活场景中的每个光源。
3.2.3设置材质
在OpenGL中,用材料对光的三原色(红绿蓝)的反射率大小来定