讀取STL模型 並用opengl顯示

xds1224@163.comwindows

提及STL模型,相信使用過CAD三維軟件的人都不陌生,數組

STL = STL文件,一種3D模型文件格式STL(STereo Lithography的縮寫)
STL文件格式是由3D SYSTEMS 公司於1988 年制定的一個接口協議,是一種爲快速原型製造技術服務的三維圖形文件格式。STL 文件由多個三角形面片的定義組成,每一個三角形面片的定義包括三角形各個定點的三維座標及三角形面片的法矢量。三角形頂點的排列順序遵循右手法則。 STL 文件有2 種類型:文本文件(ASCII格式)和二進制文件(BINARY)。
在此文中咱們對ASCII格式的STL文件進行解析,而且用opengl對其進行顯示。
STL的ASCII格式以下:
solid filenamestl //文件路徑及文件名
facet normal x y z // 三角面片法向量的3個份量值
  outer loop
  vertex x y z ∥三角面片第一個頂點的座標
  vertex x y z // 三角面片第二個頂點的座標
  vertex x y z ∥三角面片第三個頂點的座標
  endloop
  endfacet // 第一個三角面片定義完畢
  ……
  ……
  endsolid filenamestl ∥整個文件結束
  下面來講說處理這個解析的思路,首先咱們能夠按行一行行讀來下,去掉第一行開始一直往下讀,每讀一行都檢查是否是到了最後一行,可是這樣顯然效率不高,不如咱們一開始把三角面片個個數求出來,循環中對每一個三角面片進行解析,能夠觀察出每一個三角面片所佔的ASCII文件的行數爲7行,那麼把行數讀出來除以七所得的商就是三角面片的個數,那麼咱們再一一對每一個三角面片進行解析,實際上這個工做並非很難,關鍵是要知道STL的格式與OPENGLBATCH的接口,OPENGL的接口其實是一串float的數組,這裏面保存了verts即頂點座標信息,以及norms即法向量信息,那麼恰好和咱們的stl文件相一致。
  如下是咱們的核心代碼;
#include "windows.h"
#include <GLTools.h>    // OpenGL toolkit
#include <GLMatrixStack.h>
#include <GLFrame.h>
#include <GLFrustum.h>
#include <GLGeometryTransform.h>

#include <math.h>
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif


GLFrame             viewFrame;
GLFrustum           viewFrustum;
GLBatch                triangleBatch;
GLMatrixStack       modelViewMatix;
GLMatrixStack       projectionMatrix;
GLGeometryTransform transformPipeline;
GLShaderManager     shaderManager;
int num;
float* verts;
float* vnorms;
void getstlmodel()
{
    int max=0;
    bool isbegin=false;
    long size=0;
    int nlines=0;
    int count1=0;
    int count2=0;
    FILE* file=fopen("mystl.stl","r");
    fseek(file,0L,SEEK_END);
    size=ftell(file);
    fclose(file);
    file=fopen("mystl.stl","r");
    for (int i=0;i<size;i++)
    {
        if(getc(file)=='\n')
        {
            nlines++;
        }
    }
    num=nlines/7;
    rewind(file);
    while (getc(file) != '\n');
    verts=new float[9*num];
    vnorms=new float[9*num];
    for (int i=0;i<num;i++)
    {
        char x[200]="";
        char y[200]="";
        char z[200]="";
        if(3!=fscanf(file,"%*s %*s %80s %80s %80s\n",x,y,z))
        {
            break;
        }
        vnorms[count1]=vnorms[count1+3]=vnorms[count1+6]=atof(x);
        count1++;
        vnorms[count1]=vnorms[count1+3]=vnorms[count1+6]=atof(y);
        count1++;
        vnorms[count1]=vnorms[count1+3]=vnorms[count1+6]=atof(z);
        count1+=7;
        fscanf(file,"%*s %*s");
        if (3!=fscanf(file,"%*s %80s %80s %80s\n",x,y,z))
        {
            break;
        }
        if (isbegin==false)
        {
            isbegin=true;
            max=atof(z);
        }
        verts[count2]=atof(x);
        count2++;
        verts[count2]=atof(y);
        count2++;
        verts[count2]=atof(z);
        count2++;
        if (3!=fscanf(file,"%*s %80s %80s %80s\n",x,y,z))
        {
            break;
        }
        verts[count2]=atof(x);
        count2++;
        verts[count2]=atof(y);
        count2++;
        verts[count2]=atof(z);
        count2++;
        if (3!=fscanf(file,"%*s %80s %80s %80s\n",x,y,z))
        {
            break;
        }
        verts[count2]=atof(x);
        count2++;
        verts[count2]=atof(y);
        count2++;
        verts[count2]=atof(z);
        count2++;
        fscanf(file,"%*s");
        fscanf(file,"%*s");
    }

}
void SetupRC()
{
    // Black background
    glClearColor(0.3f, 0.3f, 0.3f, 1.0f );

    shaderManager.InitializeStockShaders();
    viewFrame.MoveForward(1000.0f);
     triangleBatch.Begin(GL_TRIANGLES, num*3);
     triangleBatch.CopyVertexData3f(verts);
    triangleBatch.CopyNormalDataf(vnorms);
    triangleBatch.End();

    // Make the torus
    

}
void SpecialKeys(int key, int x, int y)
{
    if(key == GLUT_KEY_UP)
        viewFrame.RotateWorld(m3dDegToRad(-5.0), 1.0f, 0.0f, 0.0f);

    if(key == GLUT_KEY_DOWN)
        viewFrame.RotateWorld(m3dDegToRad(5.0), 1.0f, 0.0f, 0.0f);

    if(key == GLUT_KEY_LEFT)
        viewFrame.RotateWorld(m3dDegToRad(-5.0), 0.0f, 1.0f, 0.0f);

    if(key == GLUT_KEY_RIGHT)
        viewFrame.RotateWorld(m3dDegToRad(5.0), 0.0f, 1.0f, 0.0f);

    // Refresh the Window
    glutPostRedisplay();
}
void ChangeSize(int w, int h)
{
    // Prevent a divide by zero
    if(h == 0)
        h = 1;

    // Set Viewport to window dimensions
    glViewport(0, 0, w, h);

    viewFrustum.SetPerspective(35.0f, float(w)/float(h), 1.0f, 2000.0f);

    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    transformPipeline.SetMatrixStacks(modelViewMatix, projectionMatrix);
}
void RenderScene(void)
{

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_CULL_FACE);
    glEnable(GL_DEPTH_TEST);
    modelViewMatix.PushMatrix(viewFrame);
    GLfloat vRed[] = { 1.0f, 0.0f, 0.0f, 1.0f };
    //shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vRed);
    shaderManager.UseStockShader(GLT_SHADER_DEFAULT_LIGHT, transformPipeline.GetModelViewMatrix(), transformPipeline.GetProjectionMatrix(), vRed);

    triangleBatch.Draw();

    modelViewMatix.PopMatrix();


    glutSwapBuffers();
}
int main(int argc, char* argv[])
{
    getstlmodel();
    gltSetWorkingDirectory(argv[0]);
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
    glutInitWindowSize(800, 600);
    glutCreateWindow("Geometry Test Program");
    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(RenderScene);
    glutSpecialFunc(SpecialKeys);

    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
        return 1;
    }
    SetupRC();
    glutMainLoop();
    return 0;
}

如下是咱們解析stl模型生成圖形的實例:ide

 

 

 

 

 

 

其實,程序中還有一個地方還有缺陷,就是一開始咱們設置的oop

viewFrame.MoveForward(1000.0f);

便是在裏原點1000米的地方進行觀測,而後spa

    viewFrustum.SetPerspective(35.0f, float(w)/float(h), 1.0f, 2000.0f);

這裏是對投影的平截頭體進行的設置,咱們也設置的爲角度35,深度爲1到2000,可是stl模型不必定是落在這個區域內,那這個時候咱們就不必定能觀測獲得圖像,或者只能觀測到部分圖像。3d

關於stl解析而且顯示的部分,在OPENCASCADE中也有功能很是強大的代碼,其中還包括了對二進制STL模型的解析和顯示,若是想深究的童鞋能夠看看這個博客:http://www.cppblog.com/eryar/archive/2013/05/01/199882.aspxcode

相關文章
相關標籤/搜索