OpenGL - Wavefront .obj Loader
-
Hallo,
ich habe anhand der Youtube-Tutorials von "thecpluspplusguy" versucht einen .obj Loader zu basteln, nur leider bekomme ich beim Starten des Programms diesen Fehler:Debug Assertion Failed!
Program:
....\MeinProgramm.exe
File: ...\visual studiio10.0\vc\include\vector
Line: 932Expression: vector subscript out of range
Das klingt für mich alles ziemlich nach einem "Vector_Überlauf".
Mein cube.obj:
# cube.obj # v 0.0 0.0 0.0 v 0.0 0.0 1.0 v 0.0 1.0 0.0 v 0.0 1.0 1.0 v 1.0 0.0 0.0 v 1.0 0.0 1.0 v 1.0 1.0 0.0 v 1.0 1.0 1.0 vn 0.0 0.0 1.0 vn 0.0 0.0 -1.0 vn 0.0 1.0 0.0 vn 0.0 -1.0 0.0 vn 1.0 0.0 0.0 vn -1.0 0.0 0.0 f 1//2 7//2 5//2 f 1//2 3//2 7//2 f 1//6 4//6 3//6 f 1//6 2//6 4//6 f 3//3 8//3 7//3 f 3//3 4//3 8//3 f 5//5 7//5 8//5 f 5//5 8//5 6//5 f 1//4 5//4 6//4 f 1//4 6//4 2//4 f 2//1 6//1 8//1 f 2//1 8//1 4//1
und hier mein Objektloader:
int objloader::loadObject(const char* dateiname){ this->filename = dateiname; vector<string*> coord; //speichert ganze zeilen als string vector<coordinate*> vertex; //member der struktur coordinate um die vertex zu speichern vector<face*> faces;//member der struktur face um die faces zu speichern vector<coordinate*> normals; ifstream in(filename);//lädt die datei if(!in.is_open() ){ MessageBox(NULL, "Objektfile konnte nicht geladen werden", "Error", MB_OK); return -1; } char buf[256]; //buffer für die zeichen while(!in.eof()){//solang nicht ende der datei... in.getline(buf,256); //lädt in die variable buffer den wert der aktuellen zeile coord.push_back(new string(buf)); //erstellt einen neuen member des vectors coord und setzt diesen string ans ende an (alles dynamisch durch "new") } for(int i=0;i<coord.size();i++){//geht alle zeilen durch if(coord[i]->c_str()[0]=='#'){//testet ob in das erste zeichen der zeile ein # ist -> nur ein kommentar continue; } else if(coord[i]->c_str()[0]=='v' && coord[i]->c_str()[1]==' '){ //if vector float tmpx, tmpy, tmpz; sscanf(coord[i]->c_str(),"v %f %f %f",&tmpx,&tmpy,&tmpz);//putts first char in tmp, first float in tmpx, second float in tmpy,.... vertex.push_back(new coordinate(tmpx, tmpy, tmpz)); } else if(coord[i]->c_str()[0]=='v' && coord[i]->c_str()[1]=='n'){ //if normal vector float tmpx,tmpy,tmpz; sscanf(coord[i]->c_str(),"vn %f %f %f",&tmpx,&tmpy,&tmpz); normals.push_back(new coordinate(tmpx,tmpy,tmpz)); } else if(coord[i]->c_str()[0]=='f'){ //if face int a,b,c,d,e; if(count(coord[i]->begin(),coord[i]->end(),' ')==3){ //if it is a triangle (it has 3 space in it) sscanf(coord[i]->c_str(),"f %d//%d %d//%d %d//%d",&a,&b,&c,&b,&d,&b); faces.push_back(new face(b,a,c,d)); //read in, and add to the end of the face list } else{ sscanf(coord[i]->c_str(),"f %d//%d %d//%d %d//%d %d//%d",&a,&b,&c,&b,&d,&b,&e,&b); faces.push_back(new face(b,a,c,d,e)); //do the same, except we call another constructor, and we use different pattern } } } //raw int num; //the id for the list num=glGenLists(1); //generate a uniqe glNewList(num,GL_COMPILE); //and create it for(int i=0;i<faces.size();i++) { if(faces[i]->bquad_face) //if it's a quad draw a quad { glBegin(GL_QUADS); //basically all I do here, is use the facenum (so the number of the face) as an index for the normal, so the 1st normal owe to the first face //I subtract 1 because the index start from 0 in C++ glNormal3f(normals[faces[i]->iface_number-1]->x,normals[faces[i]->iface_number-1]->y,normals[faces[i]->iface_number-1]->z); //draw the faces glVertex3f(vertex[faces[i]->faces[0]-1]->x,vertex[faces[i]->faces[0]-1]->y,vertex[faces[i]->faces[0]-1]->z); glVertex3f(vertex[faces[i]->faces[1]-1]->x,vertex[faces[i]->faces[1]-1]->y,vertex[faces[i]->faces[1]-1]->z); glVertex3f(vertex[faces[i]->faces[2]-1]->x,vertex[faces[i]->faces[2]-1]->y,vertex[faces[i]->faces[2]-1]->z); glVertex3f(vertex[faces[i]->faces[3]-1]->x,vertex[faces[i]->faces[3]-1]->y,vertex[faces[i]->faces[3]-1]->z); glEnd(); }else{ glBegin(GL_TRIANGLES); glNormal3f(normals[faces[i]->iface_number-1]->x,normals[faces[i]->iface_number-1]->y,normals[faces[i]->iface_number-1]->z); glVertex3f(vertex[faces[i]->faces[0]-1]->x,vertex[faces[i]->faces[0]-1]->y,vertex[faces[i]->faces[0]-1]->z); glVertex3f(vertex[faces[i]->faces[1]-1]->x,vertex[faces[i]->faces[1]-1]->y,vertex[faces[i]->faces[1]-1]->z); glVertex3f(vertex[faces[i]->faces[2]-1]->x,vertex[faces[i]->faces[2]-1]->y,vertex[faces[i]->faces[2]-1]->z); glEnd(); } } glEndList(); //delete everything to avoid memory leaks for(int i=0; i<coord.size();i++) delete coord[i]; for(int i=0;i<faces.size();i++) delete faces[i]; for(int i=0;i<normals.size();i++) delete normals[i]; for(int i=0;i<vertex.size();i++) delete vertex[i]; }
Würde mich sehr freuen, wenn jemand mir helfen könnte (auf Wunsch gern auch über Teamviewer), oder mir Tipps geben könnte meinen Fehler zu finden, sowie meine Code zu verbessern :).
Gruß
silent12
-
Die Fehlermeldung sagt ja schon, dass du auf ein Element eines vectors zuzugreifen versuchst, das nicht existiert. Der Debugger sagt dir, wo genau das passiert, einfach am Callstack raufgehen bis du in deinem Code landest...
Abgesehen davon: Warum genau speicherst du erst alle Zeilen in einem vector? Du könntest doch einfach das Einlesen und Interpretieren der Zeilen in die selbe Schleife packen. Und wieso speicherst du Pointer in deinem vector und nicht einfach direkt die Werte? Und wenn es schon Pointer sein müssen, wäre es wohl empfehlenswert, Smartpointer zu verwenden; std::unique_ptr bietet sich an...
-
Ok habe jetzt die entscheidende Zeile:
if(count(coord[i]->begin(),coord[i]->end(),' ')==3)
Ich habe es jetzt einfach in:
if(count(coord[i]->begin(),coord[i]->end(),' ')==6)
Änderung: 6 am Ende, da bei mir immer 2 Leerzeichen statt eins zwischen den Werten für jedes face stehen.
geändert und jetzt startet mein Programm, das Model wird aber nicht gezeichnet.
Code der ausgeführt wird:
Loadfunktion:
this->filename = dateiname; vector<string*> coord; //speichert ganze zeilen als string vector<coordinate*> vertex; //member der struktur coordinate um die vertex zu speichern vector<face*> faces;//member der struktur face um die faces zu speichern vector<coordinate*> normals; ifstream in(filename);//lädt die datei if(!in.is_open() ){ MessageBox(NULL, "Objektfile konnte nicht geladen werden", "Error", MB_OK); return -1; } char buf[256]; //buffer für die zeichen while(!in.eof()){//solang nicht ende der datei... in.getline(buf,256); //lädt in die variable buffer den wert der aktuellen zeile coord.push_back(new string(buf)); //erstellt einen neuen member des vectors coord und setzt diesen string ans ende an (alles dynamisch durch "new") } //#########################Hier ist der Inhalt der If-bedingung, die aufgerufen wird (habe ich getestet)##################################### sscanf(coord[i]->c_str(),"f %d//%d %d//%d %d//%d",&a,&b,&c,&b,&d,&b); faces.push_back(new face(b,a,c,d)); //read in, and add to the end of the face list
Initfunktion:
const char* tmp_filename = get_filename(); this->cube=loadObject(tmp_filename); //load the test.obj file glEnable(GL_LIGHTING); //we enable lighting, to make the 3D object to 3D glEnable(GL_LIGHT0); float col[]={1.0,1.0,1.0,1.0}; //light color is white glLightfv(GL_LIGHT0,GL_DIFFUSE,col);
Displayfunktion:
float pos[]={-1.0,1.0,-2.0,1.0}; //set the position glLightfv(GL_LIGHT0,GL_POSITION,pos); glCallList(this->cube); //draw the 3D mesh
Aufruf der Funktionen:
objloader Myobjloader; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); //andere Objekte (mit direkten Verticesangaben werden aufgerufen) Myobjloader.loadObject("Data/cube.obj"); Myobjloader.init(); Myobjloader.display();
Was sollte ich anpassen, oder hat jemand eine Idee wo der Fehler liegen könnte ?
Gruß
silent12
-
Stimmen die eingelesenen Koordinaten? Wird die Display List korrekt erstellt? Hast du auch eine korrekte und passende ModelView und Projection Matrix gesetzt (wenn die Kamera das Modell nicht anschaut, gibts nicht viel zu sehen)?
-
Die eingelesenen Koordinaten stimmen (zumindest die die ich gerade überprüft habe).
Ich habe das alles in eine "Egoshooter"-Perspektive eingebaut, sodass ich in meiner Welt rumlaufen kann, aber das Modell ist nirgends zu sehen...
Das Objekt WIRD nicht erstellt (habe gerade alles ausgeblendet, aber ich kann mich in alle Richtungen drehen und es ist nirgends zu sehenAch ich merke gerade, dass die initFunktion die LoadObject-Funktion aufruft. Evtl gibt es da Probleme...
-
Habe das Problem gelöst, wenn auch etwas unschön.
Und zwar habe ich direkt in der LoadObjekt-Funktion den Befehl:glNewList(num,GL_COMPILE_AND_EXECUTE);
statt den Befehl:
glNewList(num,GL_COMPILE);
benutzt, wodurch das Objekt direkt und nicht erst von der DisplayFunktion mit dem Befehl:
glCallList(this->cube);
gezeichnet wird
Gruß
silent12
-
Sorry wegen den Mehrfachposts, aber es passt immer noch zum Thema.
Und zwar klappt alles wunderbar mit einfachen Modellen wie einem Würfel, aber sobald ich etwas komplexere Objekte erstelle, wie zB der Monkey von Blender, dann läuft alles nur noch ruckelnd (Objekt dreht sich ruckelnd und ich laufe ruckelnd).
An der Hardware kann es eig nicht liegen, da ich eine GTX580 Lightning und einen i5-2500k nutze.Woran kann es liegen ?
Gruß
silent12
-
Kann es sein, dass du nun in jedem Frame das Model neu aus der obj Datei lädst?
-
Ohman bin ich blöd Danke nochmal
Gruß
silent12