views:

182

answers:

2

Hello! I writing small program in OpenGL, and I have problem ( textures are skew, and I dont know why, this model work in another obj viewer) What I have: http://img696.imageshack.us/i/obrazo.png/ What I want http://img88.imageshack.us/i/obraz2d.jpg/ Code of project (I use devil for images):

#pragma once

#include <windows.h>              
#define GLUT_DISABLE_ATEXIT_HACK  
#include <glut.h>
#include <GL/glu.h>
#include <GL/gl.h>
#include <GL/GLEXT.h>
#include <iostream>
#include <cmath>
#include <IL/il.h>
#include <vector>
#include <fstream>
#include <string>
#include <cstdlib>
#include <sstream>
#include <clocale>

class TextureManager
{
    struct TextureInfo{
        std::string name;
        GLuint image;
    };

private:
    std::vector<TextureInfo> textures;
public:
    TextureManager(void);
    ~TextureManager(void);

    bool AddTexture(std::string name, std::string fileName);
    int GetTexture(std::string name);
};
TextureManager::TextureManager(void)
{
    ilInit();
}

TextureManager::~TextureManager(void)
{

}

bool TextureManager::AddTexture(std::string name, std::string fileName)
{
    bool success;
    ILuint texId;
    GLuint image;
    ilGenImages(1, &texId);
    ilBindImage(texId);
    success = ilLoadImage((WCHAR*)fileName.c_str());
    if(success)
    {
        success = ilConvertImage(IL_RGB, IL_UNSIGNED_BYTE); 
        if(!success)
        {   
            return false;
        }
    }
    else
    {
        return false;
    }

    glGenTextures(1, &image);
    glBindTexture(GL_TEXTURE_2D, image);

    glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_NEAREST_MIPMAP_LINEAR);
    gluBuild2DMipmaps( GL_TEXTURE_2D, 3, ilGetInteger(IL_IMAGE_WIDTH), ilGetInteger(IL_IMAGE_HEIGHT),GL_RGB, GL_UNSIGNED_BYTE, ilGetData());
    ilDeleteImages(1, &texId); 


    TextureInfo ti;
    ti.name = name;
    ti.image = image;
    textures.push_back(ti);

    return true;
}
int TextureManager::GetTexture(std::string name)
{
    int size = textures.size();
    for(int i=0;i<size;i++)
    {
        if(textures.at(i).name.compare(name) == 0)
        {
            return textures.at(i).image;
        }
    }

    return -1;
}
using namespace std;

TextureManager tm;

struct Point
{
    double x,y,z;
};
struct Normal
{
    double x,y,z;
};
struct Triangle
{
    int a,b,c;
    int at,bt,ct;
    int an,bn,cn;

};
struct TexCord
{
    float x,y;
};
vector<Point> points;
vector<Normal> normals;
vector<Triangle> triangles;
vector<TexCord> texcords;
int w,h;
double j = 0.0;
double k = 0.0;
int mode = 1;
bool showNormals = false;
void setCamera(double eyex,double eyey, double eyez, double centerx, double centery, double centerz)
{
    gluLookAt(eyex,eyey,eyez,centerx,centery,centerz,0,1,0);
}

void DrawPoint(TexCord tc,Point p,Normal n)
{
    glTexCoord2f(tc.x,tc.y);
    glNormal3f(n.x,n.y,n.z); 
    glVertex3f(p.x,p.y,p.z);
}

void DrawNormal(Point p,Normal n)
{
    glPushMatrix();
    glTranslated(p.x,p.y,p.z);
    glBegin(GL_LINES);
    glVertex3f(0,0,0);
    glVertex3f(n.x*2,n.y*2,n.z*2);
    glEnd();
    glPopMatrix();
}

void processNormalKeys(unsigned char key, int x, int y) {

    if (key == 27) 
        exit(0);
    if (key == 'q')
    {
        mode = 0;
    }
    if (key == 'w')
    {
        mode = 1;
    }
    if (key == 'a')
    {
        k -= 0.1;
    }
    if (key == 's')
    {
        k += 0.1;
    }   
    if (key == 'z')
    {
        j -= 0.1;
    }
    if (key == 'x')
    {
        j += 0.1;
    }   
    if (key == 'n')
    {
        if(showNormals == true)
        {
            showNormals = false;
        }
        else
        {
            showNormals = true;
        }
    }
    glutPostRedisplay();
}


void renderScene(void) {
    //j+=0.0005;
    glMatrixMode(GL_PROJECTION); 
        glLoadIdentity(); 
    gluPerspective(60, (GLfloat)w / (GLfloat)h, 1.0, 100.0); 
    setCamera(15*sin(j),15*cos(k),15*cos(j)*sin(k),0,0,0);
    glMatrixMode(GL_MODELVIEW);  

    glEnable(GL_DEPTH_TEST);
    glEnable(GL_LIGHTING);
    //glEnable(GL_LIGHT0);

    float ambient[]={ 1.0, 1.0, 1.0, 0.0};
    float diffuse[]={1.0, 1.0, 1.0, 1.0};
    float position[]={25.0,25.0, 25.0, 1.0};


    glLightfv(GL_LIGHT0, GL_AMBIENT, diffuse);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
    glLightfv(GL_LIGHT0, GL_POSITION, position);

    glEnable(GL_DEPTH_TEST);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glShadeModel(GL_SMOOTH);
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, tm.GetTexture("tex"));
    if(mode ==  0 )
    {
    glBegin(GL_TRIANGLES);
    }
    else
    {
    glBegin(GL_LINES);
    }
    for(int i=0;i<triangles.size();i++)
    {
        //double r =  rand()/(double)RAND_MAX;
        //glColor3f(r,r,r);


        DrawPoint(texcords[triangles[i].ct-1],points[triangles[i].c-1],normals[triangles[i].cn-1]);
        DrawPoint(texcords[triangles[i].bt-1],points[triangles[i].b-1],normals[triangles[i].bn-1]);
        DrawPoint(texcords[triangles[i].at-1],points[triangles[i].a-1],normals[triangles[i].an-1]);
    }
    glEnd();
    glDisable(GL_TEXTURE_2D);
    if(showNormals == true)
    {
        glDisable(GL_LIGHTING);
        glDisable(GL_LIGHT0);
        glColor3f(1,0.5f,0.25f);
        for(int i = 0;i<points.size();i++)
        {
            DrawNormal(points[i],normals[i]);
        }
    }
    glFlush();
    glutSwapBuffers();
}
void reshape (int width, int height) {  
    w = width; h = height;
    glViewport(0, 0, (GLsizei)width, (GLsizei)height);
    glMatrixMode(GL_PROJECTION);  
    glLoadIdentity(); 
    gluPerspective(60, (GLfloat)width / (GLfloat)height, 1.0, 100.0); 

    glMatrixMode(GL_MODELVIEW);   

}  

void update(int value) {
    j += 0.1f;


    glutPostRedisplay(); //Tell GLUT that the scene has changed

    //Tell GLUT to call update again in 25 milliseconds
   // glutTimerFunc(100, update, 0);
}

int main(int argc, char **argv) {



    vector<Normal> *nn = &normals;
    vector<Point> *pp = &points;
    vector<Triangle> *tt = &triangles;
    vector<TexCord> *ttcc = &texcords;
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
    glutInitWindowPosition(100,100);
    glutInitWindowSize(320,320);
    glutCreateWindow("Model view");


    glutKeyboardFunc(processNormalKeys);


    glutDisplayFunc(renderScene);
    //glutIdleFunc(renderScene);
    glutReshapeFunc(reshape);

        ifstream f;
    string cmd;

    f.open ("model.obj");




     if (f.is_open())
  { 
    while(!f.eof())
    {
        f>>cmd;
        if(cmd=="v")
        {
            Point p;
            f>>p.x;
            f>>p.y;
            f>>p.z;
            points.push_back(p);
        }
        if(cmd=="vn")
        {
            Normal n;
            f>>n.x;
            f>>n.y;
            f>>n.z;
            normals.push_back(n);
        }
        if(cmd=="vt")
        {
            TexCord tc;
            f>>tc.x;
            f>>tc.y;
            texcords.push_back(tc);
        }
        if(cmd=="f")
        {

            Triangle t;
            string str;
            string pointStr,normalStr,cordStr;
            string delimeter("/");
            int pos,pos2;
            stringstream ss (stringstream::in | stringstream::out);

            f>>str;
            pos = str.find(delimeter);

            pointStr = str.substr(0,pos);
            cordStr = str.substr(pos+delimeter.length());
            pos2 = cordStr.find(delimeter);
            normalStr = cordStr.substr(pos2+delimeter.length());
            cordStr = cordStr.substr(0,pos2);
            ss<<pointStr;
            ss>>t.a;
            ss.clear();
            ss<<normalStr;
            ss>>t.an;
            ss.clear();
            ss<<cordStr;
            ss>>t.at;
            ss.clear();

            f>>str;
            pos = str.find(delimeter);

            pointStr = str.substr(0,pos);
            cordStr = str.substr(pos+delimeter.length());
            pos2 = cordStr.find(delimeter);
            normalStr = cordStr.substr(pos2+delimeter.length());
            cordStr = cordStr.substr(0,pos2);
            ss<<pointStr;
            ss>>t.b;
            ss.clear();
            ss<<normalStr;
            ss>>t.bn;
            ss.clear();
            ss<<cordStr;
            ss>>t.bt;
            ss.clear();

            f>>str;
            pos = str.find(delimeter);

            pointStr = str.substr(0,pos);
            cordStr = str.substr(pos+delimeter.length());
            pos2 = cordStr.find(delimeter);
            normalStr = cordStr.substr(pos2+delimeter.length());
            cordStr = cordStr.substr(0,pos2);
            ss<<pointStr;
            ss>>t.c;
            ss.clear();
            ss<<normalStr;
            ss>>t.cn;
            ss.clear();
            ss<<cordStr;
            ss>>t.ct;
            ss.clear();

            triangles.push_back(t);

        }
        cmd = "";
    }

    f.close();  }
     tm.AddTexture("tex","texture.png");
    //glutTimerFunc(100, update, 0); 

    glutMainLoop();
}
+1  A: 

I think I'd just push a dummy point on the beginning of your points vector, and leave the point references 1-based. I'd also get rid of the while (!in.eof()), which will normally read the last line twice. Finally, I'd use a few overloads of operator>> to read most of the data, giving a result that looked something like this:

#include <locale>
#include <vector>
#include <sstream>
#include <string>
#include <fstream>

/* change to "#if 0" for normal compilation: */
#if 1
struct Triangle { float a, an, atc, b, bn, btc, c, cn, ctc; };
struct Vector2d { float x, y; };
struct Vector3d { float x, y, z; };

std::vector<Triangle> triangles;
std::vector<Vector3d> points, normals;
std::vector<Vector2d> texcords;
#endif

namespace { 
struct slashsep: std::ctype<char> {
    slashsep(): std::ctype<char>(get_table()) {}

    static std::ctype_base::mask const* get_table() {
        static std::vector<std::ctype_base::mask> 
            rc(std::ctype<char>::table_size,std::ctype_base::mask());

        rc['/'] = std::ctype_base::space; // Treat '/' as a separator between numbers.
        rc[' '] = std::ctype_base::space;
        rc['\n'] = std::ctype_base::space;
        rc['\t'] = std::ctype_base::space;
        return &rc[0];
    }
};

std::istream &operator>>(std::istream &in, Triangle &triangle) { 
    std::string str;

    std::getline(in, str);
    std::istringstream temp(str);
    slashsep loc;
    temp.imbue(std::locale(std::locale(), &loc));

    temp >> triangle.a >> triangle.an >> triangle.atc;
    temp >> triangle.b >> triangle.bn >> triangle.btc;
    temp >> triangle.c >> triangle.cn >> triangle.ctc;
    return in;
}

std::istream &operator>>(std::istream &in, Vector3d &v) { 
    return in >> v.x >> v.y >> v.z;
}

std::istream &operator>>(std::istream &in, Vector2d &v) { 
    return in >> v.x >> v.y;
}
}

bool read_obj(std::string const &fileName) { 
    points.clear();
    points.push_back(Vector3d());
    triangles.clear();

    std::ifstream in(fileName.c_str());
    std::string cmd;

    if (!in.is_open())
        return false;

    while(in>>cmd) {
        if(cmd=="v") {
            Vector3d vector;
            in >> vector;
            points.push_back(vector);
        }
        if(cmd=="vt") {
            Vector2d texcord;
            in >> texcord;
            texcords.push_back(texcord);
        }
        if(cmd=="vn"){
            Vector3d normal;
            in >> normal;
            normals.push_back(normal);
        }
        if(cmd=="f") {
            Triangle triangle;
            in >> triangle;
            triangles.push_back(triangle);
        }
    }
    return true;
}

One minor point: while using the locale to treat '/' as a separator between numbers works for the specific variant of OBJ that you're looking at, it will not work for files that contain lines like:

f a//b c//d e//f

Nonetheless, the general idea (most reading with operator>>) will be fine when/if you decide to enhance it to handle this variant of the format.

Edit: I think I just realized part of the problem. The code to read a face should be like this:

temp >> triangle.a >> triangle.atc >> triangle.an;
temp >> triangle.b >> triangle.btc >> triangle.bn;
temp >> triangle.c >> triangle.ctc >> triangle.cn;

I.e., in the file, it's arranged as vertex/texcoord/normal, but your code and my previous version above tried to read it as vertex/normal/texcoord). Once the code was arranged this way, checking against a reference made the problem fairly obvious.

Jerry Coffin
Thx :) But when I compile this code I get error in free.c ( some file that compiler include), I compiling with vs 2008, mayby this is problem. Error : Windows has triggered a breakpoint in Project.exe.This may be due to a corruption of the heap, which indicates a bug in Project.exe or any of the DLLs it has loaded.This may also be due to the user pressing F12 while Project.exe has focus.The output window may have more diagnostic information.
subSeven
But, what about this skew ?:/ I don't know why it spread this way.
subSeven
My guess is the incorrect placement is due to interpreting the texcoord as the normal and vice versa.
Jerry Coffin
A: 

Ok i fix all :D:D What I do: change

glTexCoord2f(tc.x,tc.y);

to

glTexCoord2f(tc.x,1-tc.y);

and the most important thing I change image resolution to 1024x1024 ( I useing mipmaping so I think correct image resolution is important) Now: Can sameone explain me why lTexCoord2f(tc.x,1-tc.y); work ? and is it important to make every image 2^x resolution ?

subSeven