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