VS+opengl加载obj和mtl文件

opengl和opencv的配置忘记存了...现在也不记得是怎么配置的了。

从obj和mtl文件的结构开始,除开网上都能查到的,个人认为还有的坑点有:
1.不一定所有的面(f行)都是三角形/四边形,同一个obj文件中可能同时存在不同顶点数的面,所以在画的时候要用“glBegin(GL_POLYGON)”代表开始画一个多边形,每画完一个多边形接“glEnd()”。
2.obj文件和mtl文件的联系:mtl中以“newmtl material_name”行定义一个名为material_name的材质,在obj中以“usemtl material_name”行说明从现在开始往下直到一个新的usemtl行的f都用这个材质。在材质定义中可能用到纹理贴图,“map_Kd file_directory”。
3.f v/vt/vn,可能是负数,代表从当前行开始往前索引,这种情况很麻烦,我没管。
4.纹理贴图的坐标是以左下角为(0,0),左上角为(1,0)。opencv加载的图片在mat中存的坐标是左上角为(0,0),左下角为(1,0),x坐标是反的.
5.在我使用的版本opengl竟然还是在图片长宽不是2的整数倍的时候还是会出现加载问题,所以要resize成(1024,1024)。

工程中定义了两个类,一个存obj一个存mtl信息和texture.

材质类头文件
/* Class Model */
#include <vector>
#include <string>
#include <fstream>
#include <GL/glut.h>

/* Class Materail */

struct material {
	std::string material_name="";
	int texture_id=-1;
	float Ns = 1024;
	//Ns exponent 指定材质的反射指数,定义了反射高光度.exponent是反射指数值,该值越高则高光越密集,一般取值范围在0~1000。
	float d = 1;
	//取值为1.0表示完全不透明,取值为0.0时表示完全透明
	float Ni = 0.001;
	//Ni ptical density 指定材质表面的光密度,即折射值。可在0.001到10之间进行取值。若取值为1.0,光在通过物体的时候不发生弯曲。玻璃的折射率为1.5。
	int illum = 2;
	// Highlight on
	GLfloat Ka[3] = { 1.0, 0.0, 0.0 };
	//环境反射
	GLfloat Kd[3] = { 1.0, 0.0, 0.0 };
	//漫反射
	GLfloat Ks[3] = { 1.0, 0.0, 0.0 };
	//镜面反射
};

class Material
{
public:
	void loadFile(const char* file_name);
	void load_texture(const char* file_name);

	//vectors
	std::vector<material> material_list;
	std::vector<GLuint> texture_list;

};

#endif

obj类头文件
/* Class Model */
#include <vector>
#include <string>
#include <fstream>
#include <GL/glut.h>

/* Class Model */
 
class Model
{
public: 		
   void loadFile(const char* file_name);		// load model coords from file
	
	//vectors
	std::vector<float> vertex_list;
	std::vector<float> normal_list;
	std::vector<float> texture_list;
	std::vector<std::string> s_list;
	std::vector<std::vector<int>> face_list;
	std::vector<std::string> face_material;

};

#endif

材质和纹理贴图加载函数
#include "Material.h"
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;

void Material::load_texture(const char* file_name)
{
	Mat img = imread(file_name);
	resize(img, img, Size(1024, 1024));
	GLint height = img.rows, width = img.cols, total_bytes;
	GLubyte* pixels = 0;
	GLint last_texture_ID;
	GLuint texture_ID = 0;

	{
		GLint line_bytes = width * 3;
		/*while (line_bytes % 4 != 0)
			++line_bytes;*/      //不一定是bmp了,不存在这个问题
		total_bytes = line_bytes * height;
	}


	pixels = (GLubyte*)malloc(total_bytes);

	//cout << height << " "<<width<<endl;
	for (int i = 0;i < height;i++)
		for (int j = 0;j < width;j++)
		{
			pixels[(i * width + j) * 3] = img.at<Vec3b>(height-1-i, j)[0];
			pixels[(i * width + j) * 3 + 1] = img.at<Vec3b>(height-1-i, j)[1];
			pixels[(i * width + j) * 3 + 2] = img.at<Vec3b>(height-1-i, j)[2];
		}

	glGenTextures(1, &texture_ID);
	if (texture_ID == 0)
	{
		free(pixels);
		return ;
	}

	glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture_ID);
	glBindTexture(GL_TEXTURE_2D, texture_ID);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
		GL_BGR_EXT, GL_UNSIGNED_BYTE, pixels);
	glBindTexture(GL_TEXTURE_2D, last_texture_ID);

	free(pixels);
	this->texture_list.push_back(texture_ID);
}

void Material::loadFile(const char* file_name)
{

	ifstream fileObject(file_name);
	string fileObjectLine;

	if (fileObject.is_open()) {
		while (!fileObject.eof()) {
			getline(fileObject, fileObjectLine);
			if (fileObjectLine.c_str()[0] == 'n' && fileObjectLine.c_str()[1] == 'e')
			{
				istringstream iss(fileObjectLine);
				string temp, name;
				iss >> temp >> name;
				material now_material;
				now_material.material_name = name;
				while (fileObjectLine.c_str()[0] != '\n' && fileObjectLine.c_str()[0] != '\r')
				{
					getline(fileObject, fileObjectLine);
					if (fileObjectLine.size() < 4)
					{
						break;
					}
					else if (fileObjectLine.c_str()[1] == 'N' && fileObjectLine.c_str()[2] == 's')
					{
						istringstream iss(fileObjectLine);
						string temp;
						float Ns;
						iss >> temp >> Ns;
						now_material.Ns = Ns;
					}
					else if (fileObjectLine.c_str()[1] == 'd' && fileObjectLine.c_str()[2] == ' ')
					{
						istringstream iss(fileObjectLine);
						string temp;
						float d;
						iss >> temp >> d;
						now_material.d = d;
					}
					else if (fileObjectLine.c_str()[1] == 'N' && fileObjectLine.c_str()[2] == 'i')
					{
						istringstream iss(fileObjectLine);
						string temp;
						float Ni;
						iss >> temp >> Ni;
						now_material.Ni = Ni;
					}
					else if (fileObjectLine.c_str()[1] == 'i' && fileObjectLine.c_str()[2] == 'l')
					{
						istringstream iss(fileObjectLine);
						string temp;
						float illum;
						iss >> temp >> illum;
						now_material.illum = illum;
					}
					else if (fileObjectLine.c_str()[1] == 'K' && fileObjectLine.c_str()[2] == 'a')
					{
						istringstream iss(fileObjectLine);
						string temp;
						float a, b, c;
						iss >> temp >> a >> b >> c;
						now_material.Ka[0] = a;
						now_material.Ka[1] = b;
						now_material.Ka[2] = c;
					}
					else if (fileObjectLine.c_str()[1] == 'K' && fileObjectLine.c_str()[2] == 'd')
					{
						istringstream iss(fileObjectLine);
						string temp;
						float a, b, c;
						iss >> temp >> a >> b >> c;
						now_material.Kd[0] = a;
						now_material.Kd[1] = b;
						now_material.Kd[2] = c;
					}
					else if (fileObjectLine.c_str()[1] == 'K' && fileObjectLine.c_str()[2] == 's')
					{
						istringstream iss(fileObjectLine);
						string temp;
						float a, b, c;
						iss >> temp >> a >> b >> c;
						now_material.Ks[0] = a;
						now_material.Ks[1] = b;
						now_material.Ks[2] = c;
					}
					else if (fileObjectLine.c_str()[1] == 'm' && fileObjectLine.c_str()[2] == 'a')
					{
						istringstream iss(fileObjectLine);
						string temp, filename;
						iss >> temp >> filename;
						this->load_texture(filename.c_str());
						now_material.texture_id = this->texture_list.size() - 1;
					}
				}
				this->material_list.push_back(now_material);
			}
		}
	}
}
obj文件加载函数
#include "Model.h"
#include <opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;

void Model::loadFile(const char* file_name)
{
	ifstream fileObject(file_name);
	string fileObjectLine;

	if (fileObject.is_open()) {
		while (!fileObject.eof()) {
			getline(fileObject, fileObjectLine);

			if (fileObjectLine.c_str()[0] == 'v' && fileObjectLine.c_str()[1] == ' ')
			{
				float x, y, z;
				fileObjectLine[0] = ' ';
				sscanf_s(fileObjectLine.c_str(), "%f %f %f ", &x, &y, &z);
				this->vertex_list.push_back(x);
				this->vertex_list.push_back(y);
				this->vertex_list.push_back(z);
				continue;
			}
			else if (fileObjectLine.c_str()[0] == 'v' && fileObjectLine.c_str()[1] == 'n')
			{
				float x, y, z;
				fileObjectLine[0] = ' ';
				fileObjectLine[1] = ' ';
				sscanf_s(fileObjectLine.c_str(), "%f %f %f ", &x, &y, &z);
				this->normal_list.push_back(x);
				this->normal_list.push_back(y);
				this->normal_list.push_back(z);
				continue;
			}
			else if (fileObjectLine.c_str()[0] == 'v' && fileObjectLine.c_str()[1] == 't')
			{
				float x, y, z;
				fileObjectLine[0] = ' ';
				fileObjectLine[1] = ' ';
				sscanf_s(fileObjectLine.c_str(), "%f %f", &x, &y);
				this->texture_list.push_back(x);
				this->texture_list.push_back(y);
				continue;
			}
		}

		fileObject.clear();
		fileObject.seekg(0, ios::beg);

		string now_material = "";
		while (!fileObject.eof()) {
			getline(fileObject, fileObjectLine);
			if (fileObjectLine.c_str()[0] == 'u')
			{
				istringstream iss(fileObjectLine);
				string temp;
				iss >> temp >> now_material;
			}
			if (fileObjectLine.c_str()[0] == 'f')
			{

				s_list.push_back(fileObjectLine);
				fileObjectLine[0] = ' ';

				istringstream iss(fileObjectLine);

				vector<int> tri;
				while (iss)
				{
					int value;
					char x;
					iss >> value;
					if (iss.fail()) {/* cout << "qi" << endl;*/break; }
					tri.push_back(value);
					iss >> x >> value;
					tri.push_back(value);
					iss >> x >> value;
					tri.push_back(value);
				}
				this->face_list.push_back(tri);
				this->face_material.push_back(now_material);
			}
		}
	}
}
main函数
#include "Model.h"
#include "Material.h"
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <cassert>
#include <GL/glut.h>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;

Model model_object;		// an instance of Model
Material material_object;
GLdouble perspective = 100.0;
double rot_x = 0.0, rot_y = 0;
double dx = 0.0, dy = 0.0;
double mouse_x = 0.0, mouse_y = 0.0;
int moving = 0;
void set_light()
{
    float light[] = { 16.0,16.0,0.0,0.0 };
    glGetLightfv(GL_LIGHT0, GL_POSITION, light);
}

void set_camera()
{
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(75, 1, 1, 21);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(0.1, 0.1, 4, 0, 0, 0, 0, 1, 0);
}

void reshape(int w, int h)
{
    glViewport(0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(perspective, (GLfloat)w / (GLfloat)h, 10.0, 200.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslatef(0.0, 0.0, -30.0);
}


void initialize()
{
    glClearColor(0.0, 0.0, 0.0, 0.0);
    set_light();
    glShadeModel(GL_SMOOTH);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_COLOR_MATERIAL);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_TEXTURE_2D);
}

void display(void)
{
    // 清除屏幕
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    // 设置光和视角
    set_light();
    set_camera();
    //处理旋转
    glRotatef(rot_x, 1.0f, 0.0f, 0.0f);
    glRotatef(rot_y, 0.0f, 1.0f, 0.0f);

    GLint last_texture_ID;
    glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture_ID);
    for (int i = 0;i < model_object.face_list.size();i++)
    {
        vector<int>tri = model_object.face_list.at(i);
        string material_name = model_object.face_material.at(i);
        material now_material;
        for (int k = 0;k < material_object.material_list.size();k++)
        {
            now_material = material_object.material_list.at(k);
            if (now_material.material_name == material_name)
            {
                break;
            }
        }
        if (now_material.texture_id != -1)
        {
            glBindTexture(GL_TEXTURE_2D, material_object.texture_list.at(now_material.texture_id));
            glBegin(GL_POLYGON);
            for (int j = 0;j < tri.size();j += 3)
            {
                int value = tri.at(j + 1);
                glTexCoord2f(model_object.texture_list.at(2 * (value - 1)), model_object.texture_list.at(2 * (value - 1) + 1));
                value = tri.at(j + 2);
                glNormal3f(model_object.normal_list.at(3 * (value - 1)) + dx, model_object.normal_list.at(3 * (value - 1) + 1) + dy, model_object.normal_list.at(3 * (value - 1) + 2));
                value = tri.at(j);
                glVertex3f(model_object.vertex_list.at(3 * (value - 1)) + dx, model_object.vertex_list.at(3 * (value - 1) + 1) + dy, model_object.vertex_list.at(3 * (value - 1) + 2));
            }
            glEnd();
        }
        else {
            glMaterialfv(GL_FRONT, GL_SPECULAR, now_material.Ks);
            glMaterialfv(GL_FRONT, GL_DIFFUSE, now_material.Kd);
            glLightModelfv(GL_LIGHT_MODEL_AMBIENT, now_material.Ka);
            //glMaterialfv(GL_FRONT, GL_SHININESS, shininess);
            glBegin(GL_POLYGON);
            for (int j = 0;j < tri.size();j += 3)
            {
                int value = tri.at(j + 2);
                glNormal3f(model_object.normal_list.at(3 * (value - 1)) + dx, model_object.normal_list.at(3 * (value - 1) + 1) + dy, model_object.normal_list.at(3 * (value - 1) + 2));
                value = tri.at(j);
                glVertex3f(model_object.vertex_list.at(3 * (value - 1)) + dx, model_object.vertex_list.at(3 * (value - 1) + 1) + dy, model_object.vertex_list.at(3 * (value - 1) + 2));
            }
            glEnd();
        }
    }
    glBindTexture(GL_TEXTURE_2D, last_texture_ID);
    glutSwapBuffers();
}

void keyboard_recall(unsigned char key, int x, int y)
{
    if (key == 'a')
    {
        dx -= 0.1;
    }
    else if (key == 'd')
    {
        dx += 0.1;
    }
    else if (key == 'w')
    {
        dy += 0.1;
    }
    else if (key == 's')
    {
        dy -= 0.1;
    }
    glutPostRedisplay();
}

void mouse_recall(int button, int state, int x, int y)
{
    if (button == GLUT_LEFT_BUTTON)
    {
        if (state == GLUT_DOWN)
        {
            if (moving == 0)
            {
                moving = 1;
                mouse_x = x-rot_y;
                mouse_y = -y+rot_x;
            }
        }
        else if (state == GLUT_UP)
        {
            mouse_x = -1;
            mouse_y = -1;
            moving = 0;
        }
    }
}

void mouse_move_recall(int x, int y)
{
    if (moving == 1)
    {
        rot_y = x - mouse_x;
        rot_x = y + mouse_y;
        glutPostRedisplay();
    }
}

int main(int argc, char* argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH );
    glutInitWindowPosition(100, 100);
    glutInitWindowSize(500, 500);
    glutCreateWindow("test");
    initialize();
    glutReshapeFunc(reshape);
    //glutIdleFunc(timeadd);
    glutKeyboardFunc(keyboard_recall);
    glutMouseFunc(mouse_recall);
    glutMotionFunc(mouse_move_recall);
    glutDisplayFunc(&display);

    //load the material
    material_object.loadFile("./car_red/car.MTL");
   
    // load the model
    model_object.loadFile("./car_red/car.obj");

    glutMainLoop();

    return 0;
}

好像就没什么好写的了,虽然还是折腾了好几天的orz

posted @ 2021-11-28 20:11  zyx_45889  阅读(937)  评论(0编辑  收藏  举报