节选自《OpenGL中3DMAX模型的应用》(http://ms.mblogger.cn/sillyboy/posts/4364.aspx)
1、 用C语言数据结构描述3DMAX模型
在3DMAX中建立好模型后,仅以三角形网格方式存为ASE文件(ASCII文件),在程序中我们需建立对应的模型数据结构,本文以C语言数据结构为例。 例子ASE文件包含简单的一个金字塔和球体,具体内容如下(略去头部):
*GEOMOBJECT
{
// 单个物体模型的开头
*NODENAME "Pyramid01" // 物体名称
... ...
*MESH
{
// 网格
*TIMEVALUE 0
*MESHNUMVERTEX 6 // 物体的顶点数
*MESHNUMFACES 8 // 物体的三角形面数
*MESHVERTEXLIST
{
*MESHVERTEX00.00000.000030.0000 // 顶点坐标
... ...
*MESHVERTEX50.00000.00000.0000
}
*MESHFACELIST
{
// 面号和构成面的顶点
*MESHFACE0:A:0 B:1 C:2 AB:1 BC:1 CA:0
... ...
*MESHFACE7:A:4 B:5 C:1 AB:0 BC:1 CA:1
}
}
... ...
}
*GEOMOBJECT
{
// 格式同上个物体
*NODENAME "Sphere01"
... ...
}
分析上面的ASE文件结构,可得到通用的对应ASE文件的C模型数据结构如下。
点的定义:
typedef struct PointType
{
double x,x,y;
}POINTTYPE;
三角形面的定义:
typedef struct FaceType
{
int a,b,c;
}FACETYPE;
单个物体的定义:
typedef struct ObjectType
{
int VertexNum; // 点的个数
POINTTYPE *PointList; // 点列表
int FaceNum; // 面的个数
FACETYPE *FaceList; // 面列表
OBJECTTYPE *Next; // 指向下一物体的指针
}OBJECTTYPE;
多个物体:
typedef struct ObjectsHead
{
int ObjectNum; // 物体的个数
OBJECTTYPE *ObjectList; // 物体的列表
}OBJECTSHEAD;
2、 读入3DMAX物体数据以OpenGL实现动画
从ASE文件导入物体数据:
int GetObjects(char *FileName,OBJECTSHEAD *Objects) // 从文件中读入到Objects中
{
FILE fp; // 文件指针
char line[200]; // 存储文件中一行的数据
OBJECTTYPE *p,q;
POINTTYPE tempoint;
FACETYPE tempface;
if (fp=open(FileName,"r")<=0)
then return -1; // 读文件失败
Objects->ObjectList=NULL;
Objects->ObjectNum=0;
while(not eof(fp))
{
getlint(fp,line); // 从文件中读入一行到Line;自定义函数;
if(JudgeIn(line,"GEOMOBJECT"))
{
// 物体定义的头部
q=malloc sizeof(OBJECTTYPE); // 为物体分配空间
q->Next:=NULL;
if (Objects→ObjectList=NULL)
p=ObjectList=q;
else
{
p->Next:=q;
p=p→Next;
}
++Objects->ObjectNum;
}
if (JudgeIn(line,"*MESHNUMVERTEX"))
{
q->VertexNum=GetVertexNum(line); // 读入点数
q->PointList=(POINTTYPE *) malloc(sizeof(POINTTYPE)*q→VertexNum);
}
if (JudgeIn(line,"*MESHNUMFACES") )
{
q->FaceNum=GetFaceNum(line); // 读入面数
q->FaceList=(FACETYPE *) malloc(sizeof(FACETYPE)*q->FaceNum);
}
if (JudgeIn(line," *MESHVERTEX"))
{
GetPoint(line,tempoint); // 读入点座标
AddPoint(q->PointList,tempoint);
}
// 将点加入点列表中
if(JudgeIn(line," * MESHFACE"))
{
GetFace(line,temface); // 读入面
AddFace(q->PointList,temface);
} // 将面加入面列表中
} // While语句结束
fclose(fp);
return 1;
}
在OpenGL中实现动画控制:
#include <GL/gl.h> // OpenGL核心库
#include <GL/glu.h> // OpenGL实用库
#include <GL/glaux.h> // OpenGL辅助库
OBJECTSHEAD *Objects;
Gldouble rx=0,ry=0,rz=0; // rx,ry,rz为物体旋转的角度
void CALLBACK myReshape(GLSize w,Glsize h) // 窗口改变尺寸回调函数
{
glViewPort(0,0,w,h);
}
void CALLBACK display() // 显示物体回调函数
{
int j,k;
OBJECTTYPE *p;
Delay(1000);
Rx=rx+0.1;
Ry=ry+0.1;
Rz=rz+0.1;
glClear(GLCOLORBUFFERBIT); // 清除OpenGL的颜色缓冲
glPushMatrix();
glRotate(rx,ry,rz,0.0); // 旋转物体
p=Objects->ObjectList;
for( j=1;j<Objects->num;j++)
{
for(k=1;k>p->FaceNum;k++)
{
glBegin(GLTRIANGLES); // 用OpenGL命令绘制三角形网格
glVertex3f(p->PointList[(p->Face-List[i]).a], p->PointList[(p->Face-List[i]).b]);
glVertex3f(p->PointList[(p->Face-List[i]).b], p->PointList[(p->Face-List[i]).c]);
glVertex3f(p->PointList[(p->Face-List[i]).c], p->PointList[(p->Face-List[i]).a]);
glEnd();
}
p=p->Next;
}
glPopMatrix();
glFlush()l; // 与显示区交换数据
}
void main(void)
{
auxInitDisplayMode(AUXSINGLE|AUXRGB); // 初始化显示模式
auxInitPosition(0,0,400,400); // 初始化窗口位置和大小
auInitWindow("OPENGL-3DMAX例子"); // 标题
glClearColor(0.0,0.0,0.0,0.0); // 清除显示区
auxReshapeFunc(myReshape);
auxMainLoop(display);
}