OpenGL游戏引擎开发[5]-自己动手写STL模型加载器

前面我们绘制的物体要么是手动设置的顶点(比如简单的三角形),要么是程序生成的顶点(比如绘制的地球)。还有一种就是加载3D建模软件建好的3D模型。常见的3D模型格式有很多:.OBJ, .STL, .PLY, .fbx, .x 等等。当然加载这些3D模型有成熟的第三方库,如Assimp,我们自己手动写代码解析这些模型的格式是为了熟悉模型加载的流程,为了以后在使用第三方库的时出错了,或者加载的模型和预期的结果不同时,方便排错。

本节我们来介绍如何加载STL格式的3D模型。这种格式很简单,只包含顶点数据位置数据以及三角面片的法线数据,其他的数据格式还可能包括:纹理坐标数据,纹理贴图数据,甚至是动画数据,这需要在解析的时候建立相应的数据结构来存储这些数据,特别是动画数据,往往和你的引擎动画机制相关,你需要将模型文件中的动画数据加载为你引擎能够工作的数据结构,否则你读出来动画数据,你也使用不了。

原先我是打算加载OBJ模型的,因为OBJ文件中包含物体的顶点,法线,还有纹理数据。但是应一位小伙伴的请求,这节先加载个STL文件吧。

STL文件格式

STL (STereoLithography, 立体光刻)是由3D Systems软件公司创立、原本用于立体光刻计算机辅助设计软件的文件格式。

STL文件仅描述三维物体的表面几何形状,没有颜色、材质贴图或其它常见三维模型的属性。

STL文件两种格式,ASCII STL和Binary STL。说白了,就是一个是文本数据,一个是二进制数据。

STL的ASCII格式

ASCII STL,每一个facet由7行数据组成,outer loop后面三个顶点的顺序沿法线矢量逆时针排序,格式如下:

solid name // 文件名及文件路径

facet normal ni nj nk          // 三角形法向量的三个分量
    outer loop
        vertex v1x v1y v1z     // 第一个顶点坐标
        vertex v2x v2y v2z     // 第二个顶点坐标
        vertex v3x v3y v3z     // 第三个顶点坐标
    endloop
endfacet                       // 完成一个三角形的定义

endsolid name                  // 整个文件结束

STL的二进制格式

Binary STL,起始有80个字节文件头用于存储文件名,紧接4个字节表示三角形数量,而每个三角面片占用固定的50个字节,3个4字节浮点数(法线矢量),3个4字节浮点数(第一个顶点坐标),3个4字节浮点数(第二个顶点坐标),3个4字节浮点数(第三个顶点坐标),接着2个字节描述三角形基本属性,那么一个完整的二进制STL文件的字节大小就是三角形面数乘50再加上84字节,格式如下:

UINT8[80] – Header             // 文件头
UINT32 – Number of triangles   // 三角形数量

foreach triangle
REAL32[3] – Normal vector      // 法线矢量
REAL32[3] – Vertex 1           // 第一个顶点坐标
REAL32[3] – Vertex 2           // 第二个顶点坐标
REAL32[3] – Vertex 3           // 第三个顶点坐标
UINT16 – Attribute byte count  // 文件属性
end

加载STL二进制文件

说实话C++读取文件文件太费劲了,用C#就方便多了。我们这里读一下二进制文件吧,按照文件字节读取就行。读文本文件就作为课后作业吧,照葫芦画瓢的事。其实就是因为太麻烦了。

因为我们的引擎还没有添加光照,所以只显示了线框模型和纯色模型,看起来并没有立体感。

ok。本节结束。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的使用OpenGL加载STL模型的示例代码: ``` c++ #include <GL/glut.h> #include <stdio.h> typedef struct { float x, y, z; } Vertex; typedef struct { Vertex normal; Vertex v1, v2, v3; } Triangle; int numTriangles; Triangle *triangles; void loadSTLModel(const char *filename) { FILE *fp = fopen(filename, "rb"); if (!fp) { fprintf(stderr, "Failed to open file %s\n", filename); exit(1); } // Read the header char header[80]; fread(header, 1, 80, fp); // Read the number of triangles fread(&numTriangles, sizeof(int), 1, fp); // Allocate memory for the triangles triangles = (Triangle *)malloc(numTriangles * sizeof(Triangle)); // Read the triangles for (int i = 0; i < numTriangles; i++) { fread(&triangles[i], sizeof(Triangle), 1, fp); } fclose(fp); } void drawScene() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); // Draw the triangles glBegin(GL_TRIANGLES); for (int i = 0; i < numTriangles; i++) { glNormal3f(triangles[i].normal.x, triangles[i].normal.y, triangles[i].normal.z); glVertex3f(triangles[i].v1.x, triangles[i].v1.y, triangles[i].v1.z); glVertex3f(triangles[i].v2.x, triangles[i].v2.y, triangles[i].v2.z); glVertex3f(triangles[i].v3.x, triangles[i].v3.y, triangles[i].v3.z); } glEnd(); glutSwapBuffers(); } void initRendering() { glEnable(GL_DEPTH_TEST); } void handleResize(int w, int h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0, (double)w / (double)h, 1.0, 200.0); } int main(int argc, char *argv[]) { // Initialize GLUT glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(400, 400); // Create the window glutCreateWindow("STL Model Viewer"); // Load the STL model loadSTLModel("model.stl"); // Set up rendering callbacks glutDisplayFunc(drawScene); glutReshapeFunc(handleResize); // Set up initialization initRendering(); // Start the main loop glutMainLoop(); // Clean up free(triangles); return 0; } ``` 该程序使用了OpenGL和GLUT库来绘制STL模型。 `loadSTLModel`函数从STL文件中读取三角形数据,并将其存储在`Triangle`结构体数组中。`drawScene`函数将所有三角形绘制出来。`initRendering`函数启用深度测试。`handleResize`函数设置视口和投影矩阵。 要使用此代码,您需要将STL文件的名称作为参数传递给`loadSTLModel`函数,并将其放在与源文件相同的目录中。然后,您可以编译并运行该代码,以在窗口中查看STL模型
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值