FbxSDK是解析FBX的工具,在unity和ue中使用较多,下面介绍一下用这个工具解析FBX格式并用OpenGL显示出来。
FBX的scene是由一系列node组成的,node包含一个Transfrom和NodeAttribute,NodeAttribute包含很多类型,如eMaker、eSkeleton、eMaker、eMesh等。
模型的顶点信息存放在eMesh里,eMesh中包含了控制点信息和索引信息。索引信息指的是一系列index,如1个三角形由控制点的第0,1,2这三个点组成一个三角形,则索引信息存放这3个索引数组。
控制点 信息可以由GetControlPoints方法得到,而索引信息可以由GetPolygonVertex得到。
接下来用一个数组存放这些所有的控制点和索引号,定义如下数据结构:
struct Point{
GLfloat x;
GLfloat y;
GLfloat z;
};
int TriangleVertexCount=0;
int TriangleIndexCount=0;
std::vector<Point> triangleVertexVec; //控制点列表
std::vector<int> triangleIndexVec; //索引序列
由于模型中的mesh不止一个,放在一起需要重新编号:
void readMesh(FbxMesh *mesh)
{
int ctrlcount=mesh->GetControlPointsCount();
FbxVector4 *ctrlpoints=mesh->GetControlPoints();
for(int i=0;i<ctrlcount;i++)
{
Point p;
p.x=ctrlpoints[i].mData[0];
p.y=ctrlpoints[i].mData[1];
p.z=ctrlpoints[i].mData[2];
triangleVertexVec.push_back(p);
}
int pvcount=mesh->GetPolygonVertexCount();
int pcount=mesh->GetPolygonCount();
for(int i=0;i<pcount;i++)
{
int psize=mesh->GetPolygonSize(i);
for(int j=0;j<psize;j++)
triangleIndexVec.push_back(TriangleIndexCount+mesh->GetPolygonVertex(i,j));
}
TriangleVertexCount+=ctrlcount; //加上上一个node的控制点个数
TriangleIndexCount+=ctrlcount;
}
遍历所有node的函数如下:
void parseNode(FbxNode *node) //如何加载fbx文件获得RootNode此处省略
{
int count=node->GetChildCount();
parseNodeAttribute(node);
for(int i=0;i<count;i++)
{
FbxNode* son=node->GetChild(i);
parseNode(node->GetChild(i));
}
}
void parseNodeAttribute(FbxNode *node)
{
int nacount=node->GetNodeAttributeCount();
for(int i=0;i<nacount;i++)
{
FbxNodeAttribute *na=node->GetNodeAttributeByIndex(i);
if(na->GetAttributeType()==FbxNodeAttribute::eMesh)
{
FbxMesh *mesh=(FbxMesh*)na;
readMesh(mesh);
}
}
至此所有的mesh中的控制点和索引已经存放到triangleVertexVec和triangleIndexVec中,只需要将这个三角形面放入到OpenGL里实现就可以了。初始化OpenGL,编译shader的函数如下:
void init(void)
{
ShaderInfo shaders[] = {
{ GL_VERTEX_SHADER, "primitive_restart.vs.glsl" },
{ GL_FRAGMENT_SHADER, "primitive_restart.fs.glsl" },
{ GL_NONE, NULL }
};
program=LoadShaders(shaders); //此处用了OpenGL红宝书中的LoadShaders
glUseProgram(program);
glClearColor(0,0,0,1);
glGenVertexArrays(4,voa);
glBindVertexArray(voa[0]);
glGenBuffers(4, vob);
glBindBuffer(GL_ARRAY_BUFFER, vob[0]);
triangleVertex=new GLfloat[triangleVertexVec.size()*3];
for(int i=0;i<triangleVertexVec.size();i++)
{
triangleVertex[3*i]=triangleVertexVec[i].x;
triangleVertex[3*i+1]=triangleVertexVec[i].y;
triangleVertex[3*i+2]=triangleVertexVec[i].z;
}
triangleIndex=new GLuint[triangleIndexVec.size()*3];
for(int i=0;i<triangleIndexVec.size();i++)
{
triangleIndex[i]=triangleIndexVec[i];
}
glBufferData(GL_ARRAY_BUFFER, triangleVertexVec.size()*3*sizeof(GLdouble), triangleVertex, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (const void *)(0));
glEnableVertexAttribArray(0);
delete triangleVertex;
delete triangleIndex;
}
绘制的函数如下:
void display()
{
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClearDepth(1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
GLuint t_index=glGetUniformLocation(program,"model_transform");
vmath::mat4 transformMatrix=vmath::scale<float>(0.006);
glUniformMatrix4fv(t_index,1,GL_FALSE,transformMatrix);
glDrawElements(GL_TRIANGLES,triangleIndexVec.size(),GL_UNSIGNED_INT,triangleIndex);
glFlush();
}
顶点着色器的代码为:
#version 400
layout (location = 0) in vec4 position;
uniform mat4 model_transform;
void main(void)
{
gl_Position = model_transform*position;
}
片元着色器代码为:
#version 400
layout (location = 0) out vec4 color;
void main(void)
{
color = vec4(1.0,0.0,0.0,1.0);
}
绘制出来的效果为:
虽然有点丑,但是还是能看出效果的哈。。。