OpenGL---加载obj模型

21 篇文章 1 订阅
12 篇文章 0 订阅

obj文件格式介绍:http://www.cnblogs.com/youthlion/archive/2013/01/21/2870451.html

mesh.h

#pragma once

#include "vector"
#include "iostream"
#include "string"
#include "fstream"
#include "sstream"
#include "algorithm"
#include "assert.h"
#include <windows.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>

#pragma comment(lib, "glut.lib")

using namespace std;

struct vec3
{
    double x, y, z;
};

struct vec2
{
    double x, y;
};

class Vertex
{
public: 
    int vertIndex;     // 此顶点在顶点列表中的索引
    int normIndex;     // 顶点的法线索引
    int textIndex;     // 顶点的纹理索引
};

class Face
{
public:
    vector<Vertex> vertex; // 顶点和法线索引组成的列表

    Face(){}
    ~Face(){}
};

class Mesh
{
private:
    vector<vec3> vVertex;  // 顶点数组
    vector<vec2> vText;    // 纹理数组
    vector<vec3> vNorm;    // 法线数组
    vector<Face> vFace;    // 面片数组

public:
    Mesh(){};
    ~Mesh(){};

    bool readFile(char* path);
    void drawMesh();
};

bool Mesh::readFile(char* path)
{   
    ifstream file(path);
    if (!file)
    {
        cerr << "Error::ObjLoader, could not open obj file:"
            << path << " for reading." << std::endl;
        return false;
    }
    string line;
    while (getline(file, line))
    {
        if (line.substr(0, 2) == "vt")     // 顶点纹理坐标数据
        {
            istringstream s(line.substr(2));
            vec2 v;
            s >> v.x; s >> v.y;
            //cout << "vt " << v.x << " " << v.y << endl;
            v.y = -v.y;                     // 注意这里加载的dds纹理 要对y进行反转
            vText.push_back(v);
        }
        else if (line.substr(0, 2) == "vn") // 顶点法向量数据
        {
            istringstream s(line.substr(2));
            vec3 v;
            s >> v.x; s >> v.y; s >> v.z;
            //cout << "vn " << v.x << " " << v.y << " " << v.z << endl;
            vNorm.push_back(v);
        }
        else if (line.substr(0, 1) == "v")  // 顶点位置数据
        {
            istringstream s(line.substr(1));
            vec3 v;
            s >> v.x; s >> v.y; s >> v.z;
            //cout << "v " << v.x << " " << v.y << " " << v.z << endl;
            vVertex.push_back(v);
        }
        else if (line.substr(0, 1) == "f")  // 面数据
        {
            Face face;
            //cout << "f ";
            istringstream vtns(line.substr(1));
            string vtn;
            while (vtns >> vtn)             // 处理一行中多个顶点属性
            {
                Vertex vertex;
                replace(vtn.begin(), vtn.end(), '/', ' ');
                istringstream ivtn(vtn);
                if (vtn.find("  ") != string::npos) // 没有纹理数据,注意这里是2个空格
                {
                    ivtn >> vertex.vertIndex        
                         >> vertex.normIndex;

                    vertex.vertIndex--;     //使得下标从0开始
                    vertex.normIndex--;
                }
                else
                {
                    ivtn >> vertex.vertIndex  
                         >> vertex.textIndex 
                         >> vertex.normIndex;

                    //cout <<  vertex.vertIndex << "/" << vertex.textIndex << "/" << vertex.normIndex << " ";
                    vertex.vertIndex--;   
                    vertex.textIndex--;
                    vertex.normIndex--;
                }
                face.vertex.push_back(vertex);
            }
            vFace.push_back(face);
            //cout << endl;
        }
        else if (line[0] == '#')            // 注释忽略
        { }
        else  
        {
            // 其余内容 暂时不处理
        }
    }

    return true;
}

void Mesh::drawMesh()
{ 
    if(vFace.empty())
        return;

    // 有纹理
    if(vText.size() > 0)  
    {
        for(int f = 0; f < vFace.size(); f++)  // 绘制每个面片
        {
            int n = vFace[f].vertex.size();    // 面的顶点数
            glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
            glBegin(GL_TRIANGLES);
            for(int v = 0; v < n; v++)
            {
                int it = vFace[f].vertex[v].textIndex;
                glTexCoord2f(vText[it].x, vText[it].y);

                int in = vFace[f].vertex[v].normIndex;  
                glNormal3f(vNorm[in].x, vNorm[in].y, vNorm[in].z);

                int iv = vFace[f].vertex[v].vertIndex; 
                glVertex3f(vVertex[iv].x, vVertex[iv].y, vVertex[iv].z);
            }
            glEnd();
        }
    }
    // 没有纹理
    else                  
    {
        for(int f = 0; f < vFace.size(); f++)  // 绘制每个面片
        {
            int n = vFace[f].vertex.size();    // 面的顶点数
            glBegin(GL_TRIANGLES);
            for(int v = 0; v < n; v++)
            {
                int in = vFace[f].vertex[v].normIndex;
                glNormal3f(vNorm[in].x, vNorm[in].y, vNorm[in].z);

                int iv = vFace[f].vertex[v].vertIndex; 
                glVertex3f(vVertex[iv].x, vVertex[iv].y, vVertex[iv].z);
            }
            glEnd();
        }
    }

    //glFlush();
}

main.cpp

#include "mesh.h"

const int windowWidth = 800;
const int windowHeight = 600;

Mesh mesh;

void myDisplay()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_NORMALIZE);
    glColor3f(1, 1, 1);

    mesh.drawMesh();

    glutSwapBuffers();
    glutPostRedisplay();
}   

void myInit()
{
    glClearColor(0, 0, 0, 0);
    glEnable(GL_NORMALIZE);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_TEXTURE_2D);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60.0, windowWidth/ windowHeight, 1.0, 21.0);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(5, 6, 7, 0, 0, 0, 0, 1, 0);

    mesh.readFile("1.obj");
}


int main()
{
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); 
    glutInitWindowPosition(50, 50); 
    glutInitWindowSize(windowWidth, windowHeight);
    glutCreateWindow("DEMO"); 

    myInit();
    glutDisplayFunc(myDisplay); 

    glutMainLoop(); 
    return 0; 
}

1.obj

# Blender3D v249 OBJ File: untitled.blend
# www.blender3d.org
mtllib cube.mtl
v 1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v 1.000000 1.000000 -1.000000
v 0.999999 1.000000 1.000001
v -1.000000 1.000000 1.000000
v -1.000000 1.000000 -1.000000
vt 0.748573 0.750412
vt 0.749279 0.501284
vt 0.999110 0.501077
vt 0.999455 0.750380
vt 0.250471 0.500702
vt 0.249682 0.749677
vt 0.001085 0.750380
vt 0.001517 0.499994
vt 0.499422 0.500239
vt 0.500149 0.750166
vt 0.748355 0.998230
vt 0.500193 0.998728
vt 0.498993 0.250415
vt 0.748953 0.250920
vn 0.000000 0.000000 -1.000000
vn -1.000000 -0.000000 -0.000000
vn -0.000000 -0.000000 1.000000
vn -0.000001 0.000000 1.000000
vn 1.000000 -0.000000 0.000000
vn 1.000000 0.000000 0.000001
vn 0.000000 1.000000 -0.000000
vn -0.000000 -1.000000 0.000000
usemtl Material_ray.png
s off
f 5/1/1 1/2/1 4/3/1
f 5/1/1 4/3/1 8/4/1
f 3/5/2 7/6/2 8/7/2
f 3/5/2 8/7/2 4/8/2
f 2/9/3 6/10/3 3/5/3
f 6/10/4 7/6/4 3/5/4
f 1/2/5 5/1/5 2/9/5
f 5/1/6 6/10/6 2/9/6
f 5/1/7 8/11/7 6/10/7
f 8/11/7 7/12/7 6/10/7
f 1/2/8 2/9/8 3/13/8
f 1/2/8 3/13/8 4/14/8

这里写图片描述

不足:没有对纹理处理,比如没有纹理图片,缺乏相关操作等。

—————————–变一下样式———————————-
将drawMesh()修改一下(仍然没有对纹理进行处理)

void Mesh::drawMesh()
{ 
    if(vFace.empty())
        return;

    // 有纹理
    if(vText.size() > 0)  
    {
        for(int f = 0; f < vFace.size(); f++)  // 绘制每个面片
        {
            int n = vFace[f].vertex.size();    // 面的顶点数
            glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
            glBegin(GL_TRIANGLES);
            glColor3f(1, 1, 1);
            for(int v = 0; v < n; v++)
            {
                int it = vFace[f].vertex[v].textIndex;
                glTexCoord2f(vText[it].x, vText[it].y);

                int in = vFace[f].vertex[v].normIndex;  
                glNormal3f(vNorm[in].x, vNorm[in].y, vNorm[in].z);

                int iv = vFace[f].vertex[v].vertIndex; 
                glVertex3f(vVertex[iv].x, vVertex[iv].y, vVertex[iv].z);
            }
            glEnd();

            glBegin(GL_LINE_LOOP);
            glColor3f(0, 0, 1);
            for (int v = 0; v < n; v++)
            {
                int it = vFace[f].vertex[v].textIndex;
                glTexCoord2f(vText[it].x, vText[it].y);

                int in = vFace[f].vertex[v].normIndex;
                glNormal3f(vNorm[in].x, vNorm[in].y, vNorm[in].z);

                int iv = vFace[f].vertex[v].vertIndex;
                glVertex3f(vVertex[iv].x, vVertex[iv].y, vVertex[iv].z);
            }
            glEnd();
        }
    }
    // 没有纹理
    else                  
    {
        for(int f = 0; f < vFace.size(); f++)  // 绘制每个面片
        {
            int n = vFace[f].vertex.size();    // 面的顶点数
            glBegin(GL_TRIANGLES);
            for(int v = 0; v < n; v++)
            {
                int in = vFace[f].vertex[v].normIndex;
                glNormal3f(vNorm[in].x, vNorm[in].y, vNorm[in].z);

                int iv = vFace[f].vertex[v].vertIndex; 
                glVertex3f(vVertex[iv].x, vVertex[iv].y, vVertex[iv].z);
            }
            glEnd();
        }
    }
}

这里写图片描述

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值