c++ - 带有纹理的 Opengl obj 对象加载器

标签 c++ opengl glut blender texture-mapping

我正在使用对象加载器加载从 blender 导出的对象模型。我可以加载模型,但没有加载任何纹理,我不知道为什么。当我在主类中渲染模型时应该加载它们还是我需要在渲染模型的同时加载纹理?

objloader.cpp

/************************************************************
*Loads obj file - limited to vertices, faces, normals, texture maps
*loads to object structure as defined in .h file
************************************************************/

#include <stdio.h>
#include <iostream>
#include <io.h>
#include <stdlib.h>
#include "glut.h"

#include "objloader.h"

using namespace std;

void object_type::render()
{
    glBegin(GL_TRIANGLES); // glBegin and glEnd delimit the vertices that define a primitive (in our case triangles)

    for (int j=0;j<polygons_qty;j++)
    {
        //----------------- FIRST VERTEX -----------------
        //Normal coordinates of the first vertex
        glNormal3f( normcoord[ polygon[j].n[0] - 1 ].i,
                normcoord[ polygon[j].n[0] - 1 ].j,
                normcoord[ polygon[j].n[0] - 1 ].k);
        // Texture coordinates of the first vertex
            glTexCoord2f( mapcoord[ polygon[j].t[0] - 1 ].u,
                  mapcoord[ polygon[j].t[0] - 1 ].v);
        // Coordinates of the first vertex
        glVertex3f( vertex[ polygon[j].v[0] - 1].x,
                vertex[ polygon[j].v[0] - 1].y,
                vertex[ polygon[j].v[0] - 1].z);

        //----------------- SECOND VERTEX -----------------
        //Normal coordinates of the first vertex
        glNormal3f( normcoord[ polygon[j].n[1] - 1 ].i,
                normcoord[ polygon[j].n[1] - 1 ].j,
                normcoord[ polygon[j].n[1] - 1 ].k);
        // Texture coordinates of the first vertex
        glTexCoord2f( mapcoord[ polygon[j].t[1] - 1 ].u,
                  mapcoord[ polygon[j].t[1] - 1 ].v);
        // Coordinates of the first vertex
        glVertex3f( vertex[ polygon[j].v[1] - 1].x,
                vertex[ polygon[j].v[1] - 1].y,
                vertex[ polygon[j].v[1] - 1].z);

        //----------------- THIRD VERTEX -----------------
        //Normal coordinates of the first vertex
        glNormal3f( normcoord[ polygon[j].n[2] - 1 ].i,
                normcoord[ polygon[j].n[2] - 1 ].j,
                normcoord[ polygon[j].n[2] - 1 ].k);
        // Texture coordinates of the first vertex
        glTexCoord2f( mapcoord[ polygon[j].t[2] - 1 ].u,
                  mapcoord[ polygon[j].t[2] - 1 ].v);
        // Coordinates of the first vertex
        glVertex3f( vertex[ polygon[j].v[2] - 1].x,
                vertex[ polygon[j].v[2] - 1].y,
                vertex[ polygon[j].v[2] - 1].z);
    }
    glEnd();
}


/*
vertex_type vertex[MAX_VERTICES]; 
mapcoord_type mapcoord[MAX_VERTICES];
normcoord_type normcoord[MAX_NORMALS];
polygon_type polygon[MAX_POLYGONS];
int id_texture
*/


int object_type::objdatadisplay()
{
   int i;
   printf("VERTICES: %d\n",vertices_qty); 
for (i =0;i<vertices_qty;i++)
 {
     printf("%f %f %f\n",vertex[i].x,vertex[i].y,vertex[i].z);
 }

   printf("NORMALS: %d\n",normcoord_qty); 
for (i =0;i<normcoord_qty;i++)
{
     printf("%f %f %f\n",normcoord[i].i,normcoord[i].j,normcoord[i].k);
}
   printf("MAP COORDS: %d\n",mapcoord_qty);
for (i =0;i<mapcoord_qty;i++)
{
     printf("%f %f\n",mapcoord[i].u,mapcoord[i].v);
}
   printf("POLYGONS: %d\n",polygons_qty); 
for (i=0;i<polygons_qty;i++) //for each vertex of polygon (triangle)
{
    for (int j = 0;j<3;j++)
    {   
             printf("%d::%d/%d/%d\n",i,polygon[i].v[j],polygon[i].t[j],polygon[i].n[j]);
    }
}
return 1;
}


int object_type::objloader(char *p_filename)
{
    int ivertex=0; //Index variable
    int inormal =0;
    int ipolygon=0;
    int imap=0;
    char string[256];
FILE *l_file; //File pointer

char l_char; //Char variable

unsigned short l_face_flags; //Flag that stores some face information

if ((l_file=fopen (p_filename, "rt"))== NULL) return 0; //Open the file


while (!feof(l_file)) //Loop to scan the whole file 
{
    fscanf(l_file,"%c",&l_char);
    if(l_char=='\n')//read char if'/n' -skip to next and read   
        fscanf(l_file,"%c",&l_char);
    switch (l_char) //parse
    {   
    default: fgets(string,256,l_file);
        break;
    case 'v':   //a vertex or a normal or a text co-ord
        fscanf(l_file,"%c",&l_char);
        switch (l_char)  
        {
        case ' ':   //a vertex -expect and so read 3 floats next
              fscanf(l_file,"%f %f %f",&vertex[ivertex].x, &vertex[ivertex].y,&vertex[ivertex].z);


              ivertex++;
              break;
        case 'n': //a normal -expect and so read 3 floats next
              fscanf(l_file,"%f %f %f",&normcoord[inormal].i, &normcoord[inormal].j,&normcoord[inormal].k);
              inormal++;
              break;
        case 't': //a texture map coord-expect and so read 2 floats next
              fscanf(l_file,"%f %f",&mapcoord[imap].u, &mapcoord[imap].v);
              imap++;
              break;
        }  //end switch
        break;
    case 'f': //a face read next assume format is -> f 1/1/1 2/2/2 3/3/3
        for (int i=0;i<3;i++) //for each vertex of polygon (triangle)
        {
             fscanf(l_file,"%c",&l_char); //read space char - ignore this
             fscanf(l_file,"%d",&polygon[ipolygon].v[i]); //read vertex.
             fscanf(l_file,"%c",&l_char); //read space char - ignore this
             fscanf(l_file,"%d",&polygon[ipolygon].t[i]); //read text coord.
             fscanf(l_file,"%c",&l_char); //read space char - ignore this
             fscanf(l_file,"%d",&polygon[ipolygon].n[i]); //read normal.
        }
        ipolygon++;
        break;

    } //end switch
}

fclose (l_file); // Closes the file stream
vertices_qty = ivertex;
polygons_qty = ipolygon;
mapcoord_qty = imap;
normcoord_qty = inormal;

return 1;  //if successful    
}

objloader.h

#ifndef OBJLOAD
#define OBJLOAD

/************************************************
*Loads obj file - limited to vertices, faces, normals, texture maps
*loads to object structure as defined in .h file
****************************************************/


#define MAX_VERTICES 8000 // Max number of vertices (for each object)
#define MAX_POLYGONS 8000 // Max number of polygons (for each object)
#define MAX_NORMALS 8000 // Max number of polygons (for each object)

// Our vertex type
typedef struct{
float x,y,z;
}vertex_type;

// Our normal type
typedef struct{
float i,j,k;
}normcoord_type;

// The polygon (triangle), 3 numbers that aim 3 vertices
typedef struct{
int v[3],t[3],n[3];
}polygon_type;

// The mapcoord type, 2 texture coordinates for each vertex
typedef struct{
float u,v;
}mapcoord_type;

// The object type
class object_type{
public:
int id_texture; 
object_type(){}
~object_type(){}
int objloader(char *p_filename); 
int objdatadisplay();
void render();

private:
char name[20];
int vertices_qty;
int polygons_qty;
int mapcoord_qty;
int normcoord_qty;

vertex_type vertex[MAX_VERTICES]; 
mapcoord_type mapcoord[MAX_VERTICES];
normcoord_type normcoord[MAX_NORMALS];
polygon_type polygon[MAX_POLYGONS];

};
#endif

main.cpp

#include "objloader.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <GL/glew.h>

#ifdef __WIN32__
#include <windows.h>
#endif

#include "glut.h"  //glut has all ogl relevant .h files included 

int screen_width=800;
int screen_height=600;

//angle of rotation
float xpos = 0, ypos = 0, zpos = 0, xrot = 0, yrot = 0, angle=0.0;

float cRadius = 10.0f; // our radius distance from our character

float lastx, lasty;

object_type *objarray[2];  //objects container for our world. Used throughout so global

//Lights settings
GLfloat light_ambient[]= { 0.1f, 0.1f, 0.1f, 0.1f };
GLfloat light_diffuse[]= { 1.0f, 1.0f, 1.0f, 0.0f };
GLfloat light_specular[]= { 1.0f, 1.0f, 1.0f, 0.0f };
GLfloat light_position[]= { 100.0f, 0.0f, -10.0f, 1.0f };

//Materials settings
GLfloat mat_ambient[]= { 0.5f, 0.5f, 0.0f, 0.0f };
GLfloat mat_diffuse[]= { 0.5f, 0.5f, 0.0f, 0.0f };
GLfloat mat_specular[]= { 1.0f, 1.0f, 1.0f, 0.0f };
GLfloat mat_shininess[]= { 1.0f };


/************************************
 *
 * SUBROUTINE init(void)
 *
 * Used to initialize OpenGL and to setup our world
 *
************************************/

void init(void)
{
    glClearColor(0.0, 0.0, 0.0, 0.0); // Clear background color to black

    // Viewport transformation
    glViewport(0,0,screen_width,screen_height);  

    // Projection transformation
    glMatrixMode(GL_PROJECTION); // Specifies which matrix stack is the target for matrix operations 
    glLoadIdentity(); // We initialize the projection matrix as identity
    gluPerspective(45.0f,(GLfloat)screen_width/(GLfloat)screen_height,5.0f,10000.0f);     


//Lights initialization and activation
    glLightfv (GL_LIGHT1, GL_AMBIENT, light_ambient);
    glLightfv (GL_LIGHT1, GL_DIFFUSE, light_diffuse);
    glLightfv (GL_LIGHT1, GL_DIFFUSE, light_specular);
    glLightfv (GL_LIGHT1, GL_POSITION, light_position);    
    glEnable (GL_LIGHT1);
    glEnable (GL_LIGHTING);

    //Materials initialization and activation
glMaterialfv (GL_FRONT, GL_AMBIENT, mat_ambient);
    glMaterialfv (GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv (GL_FRONT, GL_DIFFUSE, mat_specular);
    glMaterialfv (GL_FRONT, GL_POSITION, mat_shininess);    

//Other initializations
    glShadeModel(GL_SMOOTH); // Type of shading for the polygons
glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Texture mapping perspective correction
    glEnable(GL_TEXTURE_2D); // Texture mapping ON
    glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); // Polygon rasterization mode (polygon filled)
glEnable(GL_CULL_FACE); // Enable the back face culling
    glEnable(GL_DEPTH_TEST); // Enable the depth test 

glTranslatef(0.0f, 0.0f, -cRadius);
    glRotatef(xrot,1.0,0.0,0.0);

angle++; //increase the angle

for (int i=0;i<2;i++)
{
printf("*************\n");
    objarray[i] = new (object_type);
    objarray[i]->objloader("C:/3dModels/Museum.obj");
    objarray[i]->objdatadisplay();      
}

}


/**********************************************************
 *
 * SUBROUTINE resize(int p_width, int p_height)
 *
 * This routine must be called everytime we resize our window.
 *
 * Input parameters: p_width = width in pixels of our viewport
 *                   p_height = height in pixels of our viewport
 * 
 *********************************************************/

void resize (int p_width, int p_height)
{
if (screen_width==0 && screen_height==0) exit(0);
    screen_width=p_width; // We obtain the new screen width values and store it
    screen_height=p_height; // Height value

    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // We clear both the color and the depth buffer so to draw the next frame
    glViewport(0,0,screen_width,screen_height); // Viewport transformation

    glMatrixMode(GL_PROJECTION); // Projection transformation
    glLoadIdentity(); // We initialize the projection matrix as identity
    gluPerspective(45.0f,(GLfloat)screen_width/(GLfloat)screen_height,5.0f,10000.0f);

    glutPostRedisplay (); // This command redraw the scene (it calls the same routine of glutDisplayFunc)
}

/**********************************************************
 *
 * SUBROUTINE keyboard(void)
 *
 * Subroutine to handle keyboard input
 * 
 *********************************************************/


void keyboard (unsigned char key, int x, int y) {
    if (key=='q')
    {
    xrot += 1;
    if (xrot >360) xrot -= 360;
    }

    if (key=='z')
    {
    xrot -= 1;

if (xrot < -360) xrot += 360;
    }

    if (key=='w')
    {
    float xrotrad, yrotrad;
    yrotrad = (yrot / 180 * 3.141592654f);
    xrotrad = (xrot / 180 * 3.141592654f); 
    xpos += float(sin(yrotrad));
    zpos -= float(cos(yrotrad));
    ypos -= float(sin(xrotrad));
    }

    if (key=='s')
    {
    float xrotrad, yrotrad;
    yrotrad = (yrot / 180 * 3.141592654f);
    xrotrad = (xrot / 180 * 3.141592654f); 
    xpos -= float(sin(yrotrad));
    zpos += float(cos(yrotrad));
    ypos += float(sin(xrotrad));
    }

    if (key=='d')
    {
    float yrotrad;
    yrotrad = (yrot / 180 * 3.141592654f);
    xpos += float(cos(yrotrad)) * 0.2;
    zpos += float(sin(yrotrad)) * 0.2;
    }

    if (key=='a')
    {
    float yrotrad;
    yrotrad = (yrot / 180 * 3.141592654f);
    xpos -= float(cos(yrotrad)) * 0.2;
    zpos -= float(sin(yrotrad)) * 0.2;
    }

    if (key==27)
    {
    exit(0);
    }
}

/**********************************************************
 *
 * SUBROUTINE mouseMovement(void)
 *
 * Subroutine to handle mouse input
 * 
 *********************************************************/

void mouseMovement(int x, int y) {
int diffx=x-lastx; //check the difference between the current x and the last x position
int diffy=y-lasty; //check the difference between the current y and the last y position
lastx=x; //set lastx to the current x position
lasty=y; //set lasty to the current y position
xrot += (float) diffy; //set the xrot to xrot with the addition of the difference in the y position
yrot += (float) diffx;    //set the xrot to yrot with the addition of the difference in the x position
}


/**********************************************************
 *
 * SUBROUTINE display(void)
 *
 * This is our main rendering subroutine, called each frame
 * 
 *********************************************************/

void display(void)
{

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // This clear the background color to dark blue
    glMatrixMode(GL_MODELVIEW); // Modeling transformation
    glPushMatrix();
glLoadIdentity(); // Initialize the model matrix as identity

    glTranslatef(0.0f, 0.0f, -cRadius); // We move the object forward (the model matrix is multiplied by the translation matrix)
    glRotatef(xrot,1.0,0.0,0.0); // Rotations of the object (the model matrix is multiplied by the rotation matrices)

    glRotatef(yrot,0.0,1.0,0.0);

glTranslated(-xpos,0.0f,-zpos); //translate the screen to the position of our camera


if (objarray[0]->id_texture!=-1) 
{
    glBindTexture(GL_TEXTURE_2D, objarray[0]->id_texture); // We set the active texture 
    glEnable(GL_TEXTURE_2D); // Texture mapping ON
    printf("Txt map ON");
}
else
    glDisable(GL_TEXTURE_2D); // Texture mapping OFF


objarray[0]->render();
glPopMatrix();
glPushMatrix();
glTranslatef(5.0,0.0,-20.0);
glFlush(); // This force the execution of OpenGL commands
glutSwapBuffers(); // In double buffered mode we invert the positions of the visible buffer and the writing buffer
}



/**********************************************************
 *
 * The main routine
 * 
 *********************************************************/


int main(int argc, char **argv)
{
    // We use the GLUT utility to initialize the window, to handle the input and to interact with the windows system
    glutInit(&argc, argv);    
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(screen_width,screen_height);
    glutInitWindowPosition(0,0);
    glutCreateWindow("Demo 1: To exit press ESC");    
    glutDisplayFunc(display);
    glutIdleFunc(display);
    glutReshapeFunc (resize);

glutPassiveMotionFunc(mouseMovement); //check for mouse movement
glutKeyboardFunc (keyboard); 

init();
    glutMainLoop();

    return(0);    
}

来自 blender 的示例 obj,cube.obj:

# Blender v2.66 (sub 1) OBJ File: 'cube.blend'
# www.blender.org
mtllib cube.mtl
g Cube
v 1.000000 0.665869 -1.000000
v 1.000000 0.665869 1.000000
v -1.000000 0.665869 1.000000
v -1.000000 0.665869 -1.000000
v 1.000000 2.665869 -0.999999
v 0.999999 2.665869 1.000001
v -1.000000 2.665869 1.000000
v -1.000000 2.665869 -1.000000
vt 0.000000 0.334353
vt 0.332314 0.333333
vt 0.333333 0.665647
vt 1.000000 0.001019
vt 0.998981 0.333333
vt 0.666667 0.332314
vt 1.000000 0.665647
vt 0.667686 0.666667
vt 0.334353 0.666667
vt 0.333333 0.334353
vt 0.666667 0.665647
vt 0.333333 0.332314
vt 0.001020 0.333333
vt 0.332314 0.000000
vt 0.333333 0.001019
vt 0.665647 0.000000
vt 0.001019 0.666667
vt 0.667686 0.000000
vt 0.666667 0.334353
vt 0.665647 0.333333
vt 0.000000 0.001020
vt 0.334353 0.333333
vn 0.000000 -1.000000 0.000000
vn -0.000000 1.000000 0.000000
vn 1.000000 -0.000000 0.000001
vn -0.000000 -0.000000 1.000000
vn -1.000000 -0.000000 -0.000000
vn 0.000000 0.000000 -1.000000
vn 1.000000 0.000000 -0.000000
usemtl Material
s off
f 1/1/1 2/2/1 3/3/1
f 5/4/2 8/5/2 7/6/2
f 1/5/3 5/7/3 6/8/3
f 2/9/4 6/10/4 3/11/4
f 3/12/5 7/13/5 4/14/5
f 5/15/6 1/16/6 4/6/6
f 4/17/1 1/1/1 3/3/1
f 6/18/2 5/4/2 7/6/2
f 2/19/7 1/5/7 6/8/7
f 6/10/4 7/20/4 3/11/4
f 7/13/5 8/21/5 4/14/5
f 8/22/6 5/15/6 4/6/6

最佳答案

您的 OBJ 加载器甚至不会尝试解析 MTL 文件。

您必须自己添加 MTL 处理。

您可能只想支持 map_Kd

Good luck .

关于c++ - 带有纹理的 Opengl obj 对象加载器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16512614/

相关文章:

c++ - exit() 函数无法退出进程

c++ - 写入二进制文件后,用各种程序打开后,为什么结果不尽如人意?

android - 如何从二进制数据中读取数字,跨平台/C++)?

c++ - 除以 1000 对 double var 进行四舍五入并失去小数位

c++ - OpenGL VBO 数据似乎已损坏

c++ - 我如何在此代码中使用键盘交互

c++ - 如何 std::bind() 创建数据成员?

opengl - glTexImage1D 和 glTexImage2D 的区别

c++ - OpenGL系统监视器

linux - 有没有用 glut 而不是 VTK 构建的 PCL?