• Advertisement
Sign in to follow this  

OpenGL OBJ in OpenGl

This topic is 2255 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Advertisement
OBJ files are just text files. I suggest you to export something simple from blender (a cube, a sphere) and read the .obj file with a text editor. It is very easy to understand what's saved there, once you get it, it will be super easy to parse the file and import it into your engine structure.

Share this post


Link to post
Share on other sites
Actually I would recommend getting a free .obj model from turbosquid.com and trying to load that. Something as complex as possible. There are things you would need to account for with .obj files that you might not get with a simple model you made from Blender.

Share this post


Link to post
Share on other sites
i am really new to all that ! , so that way i am looking for example !! , i look inside and try a simple one before but i cant load it there is a loot of thinks that i dont understand in the structure
if you have a example to load the obj that will help .

Share this post


Link to post
Share on other sites

i am really new to all that ! , so that way i am looking for example !! , i look inside and try a simple one before but i cant load it there is a loot of thinks that i dont understand in the structure
if you have a example to load the obj that will help .


I'm using OBJ files right now because they are easy to load and easy to edit. However, they suck. I have one file that contains 4800 faces. It takes more than a minute to load. Human readable formats really are not the way to go for a game. Not only do they take obscenely long to load, but they allow for anyone to edit them with nothing more than a text editor.

An OBJ file can store a 3D model and not much more. They are extremely limited. They contain (typically) nothing more than vertex, normal, uv and face data and possibly material data. You'll find the material data even less useful since you'll have to edit the OBJ file to put the correct path in to the material file(s). You mention ALL of the OBJ file's features. There are many, most undocumented, and even fewer have made it into an importer/exporter. Fewer still have much use in a game. So, with that being said, why are you so stuck on using OBJ files?

Share this post


Link to post
Share on other sites
I understand that this is going to be computer specific...but 4800 faces taking over a minute? What exactly is your OBJ loader doing? My loader (on my machine) is doing 100k vertexs/normals/texcoords or ~33k faces, including a rather bastardized type of triangulation, in roughly 7 seconds. Of course I'm not generating normals on models that don't have them but that would hardly account for an additional minute or processing time...

Did you write yours in python MarkS?

Share this post


Link to post
Share on other sites

I understand that this is going to be computer specific...but 4800 faces taking over a minute? What exactly is your OBJ loader doing? My loader (on my machine) is doing 100k vertexs/normals/texcoords or ~33k faces, including a rather bastardized type of triangulation, in roughly 7 seconds. Of course I'm not generating normals on models that don't have them but that would hardly account for an additional minute or processing time...

Did you write yours in python MarkS?


unsure.gif No Python! I wrote the loader using std::vector and that seemed to affect the loading times, but it was worth it since I don't have to make multiple passes through the file to count vertices and faces and it greatly simplified the code. Still, converting the same OBJ file to a binary format and reading the data directly into a data structure was orders of magnitude faster.

Share this post


Link to post
Share on other sites

[quote name='Ahl' timestamp='1323995351' post='4894342']
I understand that this is going to be computer specific...but 4800 faces taking over a minute? What exactly is your OBJ loader doing? My loader (on my machine) is doing 100k vertexs/normals/texcoords or ~33k faces, including a rather bastardized type of triangulation, in roughly 7 seconds. Of course I'm not generating normals on models that don't have them but that would hardly account for an additional minute or processing time...

Did you write yours in python MarkS?


unsure.gif No Python! I wrote the loader using std::vector and that seemed to affect the loading times, but it was worth it since I don't have to make multiple passes through the file to count vertices and faces and it greatly simplified the code. Still, converting the same OBJ file to a binary format and reading the data directly into a data structure was orders of magnitude faster.
[/quote]

I did my original OBJ loader in Python and there was a tremendous speed difference between that and my C++ re-write, hence my question. I'm presently using std::vectors and even with not pre-counting my vertexs, texcoords, normals, etc. and just push_bach()'ing everything it isn't that slow.

What kind of data structure are you reading your info into? You've peaked my curiosity.

Share this post


Link to post
Share on other sites

What kind of data structure are you reading your info into? You've peaked my curiosity.


I'll do one better. Here is the code. It isn't the best, but it worked for my purpose. I've transitioned my models to a custom, binary format. I'm still using the old stdio functions and had planned to convert this to the newer C++ functions, but it really is a moot point now.

OBJ Loader.h
[source]

#ifndef __OBJ_LOADER__
#define __OBJ_LOADER__

#include <vector>
#include <string>

using namespace std;

class OBJ_vertex{
public:
OBJ_vertex(){}
~OBJ_vertex(){}

float GetX() const {return(x);}
void SetX(float _x) {x = _x;}

float GetY() const {return(y);}
void SetY(float _y) {y = _y;}

float GetZ() const {return(z);}
void SetZ(float _z) {z = _z;}

private:
float x;
float y;
float z;
};

class uv_coords{
public:
uv_coords(){}
~uv_coords(){}

float GetU() const {return(u);}
void SetU(float _u) {u = _u;}

float GetV() const {return(v);}
void SetV(float _v) {v = _v;}

private:
float u;
float v;
};

class face{
public:
face();
face(const face &right);
~face();

long GetNumVertices() const;
long GetNumNormals() const;
long GetNumUVs() const;

void AddVertex(long index);
long GetVertex(long index) const;

void AddNormal(long index);
long GetNormal(long index) const;

void AddUV(long index);
long GetUV(long index) const;

private:
vector<long> *vertices;
vector<long> *normals;
vector<long> *uv;
};

class OBJ{
public:
OBJ();
~OBJ();

long GetNumVertices() const;
long GetNumNormals() const;
long GetNumUVs() const;
long GetNumFaces() const;

OBJ_vertex *GetVertex(long index) const;
OBJ_vertex *GetNormal(long index) const;
uv_coords *GetUV(long index) const;
face *GetFace(long index) const;

void LoadOBJ(string file_name);
void DumpOBJ(void);

private:
vector<OBJ_vertex> *vertices;
vector<OBJ_vertex> *normals;
vector<uv_coords> *uv;
vector<face> *faces;
};

#endif
[/source]

OBJ Loader.cpp
[source]

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "OBJ Loader.h"

face::face()
{
vertices = new vector<long>;
normals = new vector<long>;
uv = new vector<long>;
}

face::face(const face &right)
{
long i;

vertices = new vector<long>;
normals = new vector<long>;
uv = new vector<long>;

for(i = 0;i < right.vertices->size();i++)
vertices->push_back(right.vertices->at(i));
for(i = 0;i < right.normals->size();i++)
normals->push_back(right.normals->at(i));
for(i = 0;i < right.uv->size();i++)
uv->push_back(right.uv->at(i));
}

face::~face()
{
delete vertices;
vertices = NULL;

delete normals;
normals = NULL;

delete uv;
uv = NULL;
}

long face::GetNumVertices() const
{
return(vertices->size());
}

long face::GetNumNormals() const
{
return(normals->size());
}

long face::GetNumUVs() const
{
return(uv->size());
}

void face::AddVertex(long index)
{
vertices->push_back(index);
}

long face::GetVertex(long index) const
{
if(index < 0 || index > vertices->size() - 1)
return(NULL);

return(vertices->at(index));
}

void face::AddNormal(long index)
{
normals->push_back(index);
}

long face::GetNormal(long index) const
{
if(index < 0 || index > normals->size() - 1)
return(NULL);

return(normals->at(index));
}

void face::AddUV(long index)
{
uv->push_back(index);
}

long face::GetUV(long index) const
{
if(index < 0 || index > uv->size() - 1)
return(NULL);

return(uv->at(index));
}

OBJ::OBJ()
{
vertices = new vector<OBJ_vertex>;
normals = new vector<OBJ_vertex>;
uv = new vector<uv_coords>;
faces = new vector<face>;
}

OBJ::~OBJ()
{
delete vertices;
vertices = NULL;

delete normals;
normals = NULL;

delete uv;
uv = NULL;

delete faces;
faces = NULL;
}

long OBJ::GetNumVertices() const
{
return(vertices->size());
}

long OBJ::GetNumNormals() const
{
return(normals->size());
}

long OBJ::GetNumUVs() const
{
return(uv->size());
}

long OBJ::GetNumFaces() const
{
return(faces->size());
}

OBJ_vertex *OBJ::GetVertex(long index) const
{
if(index < 0 || index > vertices->size() - 1)
return(NULL);

return(&vertices->at(index));
}

OBJ_vertex *OBJ::GetNormal(long index) const
{
if(index < 0 || index > normals->size() - 1)
return(NULL);

return(&normals->at(index));
}

uv_coords *OBJ::GetUV(long index) const
{
if(index < 0 || index > uv->size() - 1)
return(NULL);

return(&uv->at(index));
}

face *OBJ::GetFace(long index) const
{
if(index < 0 || index > faces->size() - 1)
return(NULL);

return(&faces->at(index));
}

void OBJ::LoadOBJ(string file_name)
{
FILE *fs;
char c;
bool done,has_normals,has_uvs;
OBJ_vertex vert;
uv_coords uvs;
face *temp_face;
float x,y,z;
float u,v;
int vert_ind,norm_ind,uv_ind;
int read_count;

if(fopen_s(&fs,file_name.c_str(),"r") != 0)
return;

done = false;
has_normals = false;
has_uvs = false;

while(!done)
{
switch(fgetc(fs))
{
case '#': // Comment. Fall through
case 'u': // Fall through
case 's': // Fall through
case 'g': // Group. Not supported. Fall through
while(fgetc(fs) != '\n'); // Skip to the next line
break;
case EOF: // End of file reached. We be done.
done = true;
break;
case 'v': // Loading vertices is easy. Faces, not so much...
switch(fgetc(fs))// The next character determines what type of vertex we are loading
{
case ' ': // Loading vertices
fscanf_s(fs,"%f %f %f\n",&x,&y,&z);
vert.SetX(x);
vert.SetY(y);
vert.SetZ(z);
vertices->push_back(vert);
break;
case 'n': // Loading normals
has_normals = true;
fscanf_s(fs,"%f %f %f\n",&x,&y,&z);
vert.SetX(x);
vert.SetY(y);
vert.SetZ(z);
normals->push_back(vert);
break;
case 't': // Loading UVs
has_uvs = true;
fscanf_s(fs,"%f %f\n",&u,&v);
uvs.SetU(u);
uvs.SetV(v);
uv->push_back(uvs);
break;
default: // Uh oh... What are we trying to read here? Someone screwed up their OBJ exporter...
cout << "Invalid vertex type: " << "v" << c << " Should be of type \"v \", \"vn\" or \"vt\"." << endl;
return;
}
break;
case 'f':
if(has_normals && has_uvs)
{
temp_face = new face;
while(fgetc(fs) != '\n')
{
vert_ind = 0;
norm_ind = 0;
uv_ind = 0;

read_count = fscanf_s(fs,"%d/%d/%d",&vert_ind,&uv_ind,&norm_ind);
if((read_count != 3) || (vert_ind == 0) || (uv_ind == 0) || (norm_ind == 0)) // Valid indices start at 1 in a .OBJ file. Don't know why... O.o
{
delete temp_face;
temp_face = NULL;

cout << "Invalid vertex index." << endl;
return;
}

temp_face->AddVertex(vert_ind - 1); // We want the indices to start at 0, so subtract 1.
temp_face->AddNormal(norm_ind - 1);
temp_face->AddUV(uv_ind - 1);
}
faces->push_back(*temp_face);

delete temp_face;
temp_face = NULL;
}else if(has_normals && !has_uvs){
temp_face = new face;
while(fgetc(fs) != '\n')
{
vert_ind = 0;
norm_ind = 0;

read_count = fscanf_s(fs,"%d//%d",&vert_ind,&norm_ind);
if((read_count != 2) || (vert_ind == 0) || (norm_ind == 0))
{
delete temp_face;
temp_face = NULL;

cout << "Invalid vertex index." << endl;
return;
}

temp_face->AddVertex(vert_ind - 1);
temp_face->AddNormal(norm_ind - 1);
temp_face->AddUV(0);
}
faces->push_back(*temp_face);

delete temp_face;
temp_face = NULL;
}else if(!has_normals && has_uvs){
temp_face = new face;
while(fgetc(fs) != '\n')
{
vert_ind = 0;
uv_ind = 0;

read_count = fscanf_s(fs,"%d/%d/",&vert_ind,&uv_ind);
if((read_count != 2) || (vert_ind == 0) || (uv_ind == 0))
{
delete temp_face;
temp_face = NULL;

cout << "Invalid vertex index." << endl;
return;
}

temp_face->AddVertex(vert_ind - 1);
temp_face->AddNormal(0);
temp_face->AddUV(uv_ind - 1);
}
faces->push_back(*temp_face);

delete temp_face;
temp_face = NULL;
}else if(!has_normals && !has_uvs){
temp_face = new face;
while(fgetc(fs) != '\n')
{
vert_ind = 0;

read_count = fscanf_s(fs,"%d//",&vert_ind);
if((read_count != 1) || (vert_ind == 0))
{
delete temp_face;
temp_face = NULL;

cout << "Invalid vertex index." << endl;
return;
}

temp_face->AddVertex(vert_ind - 1);
temp_face->AddNormal(0);
temp_face->AddUV(0);
}
faces->push_back(*temp_face);

delete temp_face;
temp_face = NULL;
}
break;
}
}

fclose(fs);
}

void OBJ::DumpOBJ(void)
{
long i,j;

for(i = 0;i < GetNumVertices();i++)
cout << GetVertex(i)->GetX() << " " << GetVertex(i)->GetY() << " " << GetVertex(i)->GetZ() << endl;

for(i = 0;i < GetNumNormals();i++)
cout << GetNormal(i)->GetX() << " " << GetNormal(i)->GetY() << " " << GetNormal(i)->GetZ() << endl;

for(i = 0;i < GetNumUVs();i++)
cout << GetUV(i)->GetU() << " " << GetUV(i)->GetV() << endl;

for(i = 0;i < GetNumFaces();i++)
{
for(j = 0;j < GetFace(i)->GetNumVertices();j++)
cout << GetFace(i)->GetVertex(j) << "/" << GetFace(i)->GetUV(j) << "/" << GetFace(i)->GetNormal(j) << " ";
cout << endl;
}
}
[/source]

As you can tell, this will load a file even if it isn't formatted correctly. You can mix up the line order for the vertices and faces and it will still read correctly. Again, I needed a quick format to load. More advanced formats tend to require more advanced loaders and my models just were not that complex.

Also, I was just guessing with the "more than a minute" comment. I wasn't profiling this since it really wasn't that important. It *felt* like a long time.

Share this post


Link to post
Share on other sites

[quote name='Ahl' timestamp='1324068549' post='4894614']
What kind of data structure are you reading your info into? You've peaked my curiosity.


I'll do one better. Here is the code. It isn't the best, but it worked for my purpose. I've transitioned my models to a custom, binary format. I'm still using the old stdio functions and had planned to convert this to the newer C++ functions, but it really is a moot point now.

OBJ Loader.h
[source]
//Ta Codez!!!
[/source]

As you can tell, this will load a file even if it isn't formatted correctly. You can mix up the line order for the vertices and faces and it will still read correctly. Again, I needed a quick format to load. More advanced formats tend to require more advanced loaders and my models just were not that complex.

Also, I was just guessing with the "more than a minute" comment. I wasn't profiling this since it really wasn't that important. It *felt* like a long time.
[/quote]

Right on. I'm ashamed to post my code where others can see it. It's quite ugly....but it works. Getting it to work with every every model I can find has broken me of my insistence on coding everything myself from scratch. A good friend of mine calls it reinventing the wheel. Thank you .obj loader. You have taught me many lessons.

Share this post


Link to post
Share on other sites

Right on. I'm ashamed to post my code where others can see it. It's quite ugly....but it works.


I never really understood this vanity in programmers. Maybe because I'm not a professional programmer? Anyway, my thoughts on this matter are simple: "It doesn't have to be pretty, just readable and it must work."

[size=2]
Getting it to work with every every model I can find has broken me of my insistence on coding everything myself from scratch. A good friend of mine calls it reinventing the wheel. Thank you .obj loader. You have taught me many lessons.


[size=2]In my case, it was actually easier to write my own. I was using OBJ files because I could edit them easily in VS if I should have needed to and again, the loader is simple to write. I considered Assimp, but I knew that I would be using my own format at a later time and Assimp isn't exactly intuitive[size=2] to integrate into a project. Using Assimp was, for me, like killing an ant with a sledge hammer.

Share this post


Link to post
Share on other sites


I never really understood this vanity in programmers. Maybe because I'm not a professional programmer? Anyway, my thoughts on this matter are simple: "It doesn't have to be pretty, just readable and it must work."



You have shamed me into relenting.

[source]
void Model_Loader::LoadObjInfo()
{
if (Input.is_open())
{
boost::shared_ptr<Mesh> NewMesh;

NewModel.reset(new Model);

std::string Buffer;
std::string MatName;

while (Input.good())
{
getline(Input, Buffer, '\n');
Trim(&Buffer);
std::istringstream line(Buffer);
std::string line_t;
if (Buffer.substr(0, 6) == "mtllib")
{
line >> line_t >> FileName;
LoadMaterial(FileName, &MaterialMap);
}
if (Buffer.substr(0, 6) == "usemtl")
{
line >> line_t >> MatName;
if (MatName != "(null)")
{
if (NewMesh == NULL)
{
NewMesh.reset(new Mesh);
NewMesh->Materials = MaterialMap.find(MatName)->second;
}
else
{
NewModel->Meshs.push_back(NewMesh);
NewMesh.reset(new Mesh);
NewMesh->Materials = MaterialMap.find(MatName)->second;
}
}
else
{
if (NewMesh == NULL)
{
NewMesh.reset(new Mesh);
}
else
{
NewModel->Meshs.push_back(NewMesh);
boost::shared_ptr<Mesh> NewMesh(new Mesh);
}
}
}
else if (Buffer.substr(0, 2) == "vn")
{
NewNormal.reset(new vec3);
line >> line_t
>> NewNormal->x
>> NewNormal->y
>> NewNormal->z;
Normal_Vector.push_back(NewNormal);
}
else if (Buffer.substr(0, 2) == "vt")
{
NewTexcoord.reset(new vec3);
line >> line_t
>> NewTexcoord->x
>> NewTexcoord->y;
Texcoord_Vector.push_back(NewTexcoord);
}
else if (Buffer.substr(0, 1) == "v")
{
NewVertex.reset(new vec3);
line >> line_t
>> NewVertex->x
>> NewVertex->y
>> NewVertex->z;
Vertex_Vector.push_back(NewVertex);
}
else if (Buffer.substr(0, 1) == "f")
{
int iVertex;
int iTexcoord;
int iNormal;
int NumNodes = 0;

boost::shared_ptr<Node> NewNode;
boost::shared_ptr<Node> FirstNode;
boost::shared_ptr<Node> LastNode;

line >> line_t;
while (line.good())
{
NewNode.reset(new Node);
NumNodes++;

size_t found;
int NumSlashes = 0;
std::string SubLine;
line >> SubLine;
found = SubLine.find("//");
if (found != SubLine.npos)
{
SubLine.replace(SubLine.find("//"), 2, " ");
std::istringstream Values(SubLine);
Values >> iVertex >> iNormal;

NewNode->Vertex = Vertex_Vector[abs(iVertex)-1];
NewNode->Normal = Normal_Vector[abs(iNormal)-1];

NumSlashes = 999;
break;
}
else
{
while (true)
{
found = SubLine.find('/');
if (found != SubLine.npos)
{
NumSlashes += 1;
SubLine.replace(found, 1, " ");
}
else
{
break;
}
}
std::istringstream Values(SubLine);
if (NumSlashes == 0)
{
Values >> iVertex;
NewNode->Vertex = Vertex_Vector[abs(iVertex)-1];
}
if (NumSlashes == 1)
{
Values >> iVertex >> iTexcoord;
NewNode->Vertex = Vertex_Vector[abs(iVertex)-1];
}
if (NumSlashes == 2)
{
Values >> iVertex >> iTexcoord >> iNormal;
NewNode->Vertex = Vertex_Vector[abs(iVertex)-1];
NewNode->Texcoord = Texcoord_Vector[abs(iTexcoord)-1];
NewNode->Normal = Normal_Vector[abs(iNormal)-1];
}
}
if (FirstNode == NULL)
{
FirstNode = NewNode;
}
if (LastNode == NULL)
{
LastNode = NewNode;
}
else
{
NewNode->PrevNode = LastNode;
NewNode->NextNode = FirstNode;
LastNode->NextNode = NewNode;
LastNode = NewNode;
FirstNode->PrevNode = NewNode;
}
}

//Make sure our Doubly Linked List is doubly linked all the way around.
for (boost::shared_ptr<Node> Temp = FirstNode; Temp->NextNode != FirstNode; Temp = Temp->NextNode)
{
Temp->NextNode->PrevNode = Temp;
}

if (NumNodes > 3)
{
boost::shared_ptr<Node> Triangle = FirstNode;
while(true)
{
if (Triangle->NextNode->NextNode->NextNode == Triangle)
{
if (Triangle->PrevNode->Vertex != NULL) NewMesh->Vertexs.push_back(Triangle->PrevNode->Vertex);
if (Triangle->PrevNode->Normal != NULL) NewMesh->Normals.push_back(Triangle->PrevNode->Normal);
if (Triangle->PrevNode->Texcoord != NULL) NewMesh->Texcoords.push_back(Triangle->PrevNode->Texcoord);

if (Triangle->Vertex != NULL) NewMesh->Vertexs.push_back(Triangle->Vertex);
if (Triangle->Normal != NULL) NewMesh->Normals.push_back(Triangle->Normal);
if (Triangle->Texcoord != NULL) NewMesh->Texcoords.push_back(Triangle->Texcoord);

if (Triangle->NextNode->Vertex != NULL) NewMesh->Vertexs.push_back(Triangle->NextNode->Vertex);
if (Triangle->NextNode->Normal != NULL) NewMesh->Normals.push_back(Triangle->NextNode->Normal);
if (Triangle->NextNode->Texcoord != NULL) NewMesh->Texcoords.push_back(Triangle->NextNode->Texcoord);
break;
}

bool Pure_Tri = true;
for (boost::shared_ptr<Node> Point = FirstNode->NextNode->NextNode; Point->NextNode != Triangle->PrevNode; Point = Point->NextNode)
{
vec3 v0 = *(Triangle->PrevNode->Vertex) - *(Triangle->Vertex);
vec3 v1 = *(Triangle->NextNode->Vertex) - *(Triangle->Vertex);
vec3 v2 = *(Point->Vertex) - *(Point->Vertex);

float dot00 = v0.DotProduct(v0);
float dot01 = v0.DotProduct(v1);
float dot02 = v0.DotProduct(v2);
float dot11 = v1.DotProduct(v1);
float dot12 = v1.DotProduct(v2);

float invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
float u = (dot11 * dot02 - dot01 * dot12) * invDenom;
float v = (dot00 * dot12 - dot01 * dot02) * invDenom;

if (u >= 0 && v >= 0 && u + v < 1)
{
Pure_Tri = false;
break;
}
}
if (Pure_Tri == true)
{
if (Triangle->PrevNode->Vertex != NULL) NewMesh->Vertexs.push_back(Triangle->PrevNode->Vertex);
if (Triangle->PrevNode->Normal != NULL) NewMesh->Normals.push_back(Triangle->PrevNode->Normal);
if (Triangle->PrevNode->Texcoord != NULL) NewMesh->Texcoords.push_back(Triangle->PrevNode->Texcoord);

if (Triangle->Vertex != NULL) NewMesh->Vertexs.push_back(Triangle->Vertex);
if (Triangle->Normal != NULL) NewMesh->Normals.push_back(Triangle->Normal);
if (Triangle->Texcoord != NULL) NewMesh->Texcoords.push_back(Triangle->Texcoord);

if (Triangle->NextNode->Vertex != NULL) NewMesh->Vertexs.push_back(Triangle->NextNode->Vertex);
if (Triangle->NextNode->Normal != NULL) NewMesh->Normals.push_back(Triangle->NextNode->Normal);
if (Triangle->NextNode->Texcoord != NULL) NewMesh->Texcoords.push_back(Triangle->NextNode->Texcoord);

boost::shared_ptr<Node> Temp = Triangle->NextNode;
Triangle->PrevNode->NextNode = Triangle->NextNode;
Triangle->NextNode->PrevNode = Triangle->PrevNode;
Triangle = Temp;
}
else
{
Triangle = Triangle->NextNode;
}
}
}
else if (NumNodes == 3)
{
boost::shared_ptr<Node> Temp = FirstNode;
while(true)
{
if (Temp->NextNode == FirstNode)
{
break;
}
else
{
if (Temp->Vertex != NULL) NewMesh->Vertexs.push_back(Temp->Vertex);
if (Temp->Normal != NULL) NewMesh->Normals.push_back(Temp->Normal);
if (Temp->Texcoord != NULL) NewMesh->Texcoords.push_back(Temp->Texcoord);
Temp = Temp->NextNode;
}
}
}
else if (NumNodes < 3)
{
std::cout << "Less than 3 nodes!" << std::endl;
system("PAUSE");
}
}
}
if (NewMesh != NULL)
{
NewModel->Meshs.push_back(NewMesh);
}
}
}
[/source]

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
  • Advertisement
  • Popular Tags

  • Advertisement
  • Popular Now

  • Similar Content

    • By LifeArtist
      Good Evening,
      I want to make a 2D game which involves displaying some debug information. Especially for collision, enemy sights and so on ...
      First of I was thinking about all those shapes which I need will need for debugging purposes: circles, rectangles, lines, polygons.
      I am really stucked right now because of the fundamental question:
      Where do I store my vertices positions for each line (object)? Currently I am not using a model matrix because I am using orthographic projection and set the final position within the VBO. That means that if I add a new line I would have to expand the "points" array and re-upload (recall glBufferData) it every time. The other method would be to use a model matrix and a fixed vbo for a line but it would be also messy to exactly create a line from (0,0) to (100,20) calculating the rotation and scale to make it fit.
      If I proceed with option 1 "updating the array each frame" I was thinking of having 4 draw calls every frame for the lines vao, polygons vao and so on. 
      In addition to that I am planning to use some sort of ECS based architecture. So the other question would be:
      Should I treat those debug objects as entities/components?
      For me it would make sense to treat them as entities but that's creates a new issue with the previous array approach because it would have for example a transform and render component. A special render component for debug objects (no texture etc) ... For me the transform component is also just a matrix but how would I then define a line?
      Treating them as components would'nt be a good idea in my eyes because then I would always need an entity. Well entity is just an id !? So maybe its a component?
      Regards,
      LifeArtist
    • By QQemka
      Hello. I am coding a small thingy in my spare time. All i want to achieve is to load a heightmap (as the lowest possible walking terrain), some static meshes (elements of the environment) and a dynamic character (meaning i can move, collide with heightmap/static meshes and hold a varying item in a hand ). Got a bunch of questions, or rather problems i can't find solution to myself. Nearly all are deal with graphics/gpu, not the coding part. My c++ is on high enough level.
      Let's go:
      Heightmap - i obviously want it to be textured, size is hardcoded to 256x256 squares. I can't have one huge texture stretched over entire terrain cause every pixel would be enormous. Thats why i decided to use 2 specified textures. First will be a tileset consisting of 16 square tiles (u v range from 0 to 0.25 for first tile and so on) and second a 256x256 buffer with 0-15 value representing index of the tile from tileset for every heigtmap square. Problem is, how do i blend the edges nicely and make some computationally cheap changes so its not obvious there are only 16 tiles? Is it possible to generate such terrain with some existing program?
      Collisions - i want to use bounding sphere and aabb. But should i store them for a model or entity instance? Meaning i have 20 same trees spawned using the same tree model, but every entity got its own transformation (position, scale etc). Storing collision component per instance grats faster access + is precalculated and transformed (takes additional memory, but who cares?), so i stick with this, right? What should i do if object is dynamically rotated? The aabb is no longer aligned and calculating per vertex min/max everytime object rotates/scales is pretty expensive, right?
      Drawing aabb - problem similar to above (storing aabb data per instance or model). This time in my opinion per model is enough since every instance also does not have own vertex buffer but uses the shared one (so 20 trees share reference to one tree model). So rendering aabb is about taking the model's aabb, transforming with instance matrix and voila. What about aabb vertex buffer (this is more of a cosmetic question, just curious, bumped onto it in time of writing this). Is it better to make it as 8 points and index buffer (12 lines), or only 2 vertices with min/max x/y/z and having the shaders dynamically generate 6 other vertices and draw the box? Or maybe there should be just ONE 1x1x1 cube box template moved/scaled per entity?
      What if one model got a diffuse texture and a normal map, and other has only diffuse? Should i pass some bool flag to shader with that info, or just assume that my game supports only diffuse maps without fancy stuff?
      There were several more but i forgot/solved them at time of writing
      Thanks in advance
    • By RenanRR
      Hi All,
      I'm reading the tutorials from learnOpengl site (nice site) and I'm having a question on the camera (https://learnopengl.com/Getting-started/Camera).
      I always saw the camera being manipulated with the lookat, but in tutorial I saw the camera being changed through the MVP arrays, which do not seem to be camera, but rather the scene that changes:
      Vertex Shader:
      #version 330 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec2 aTexCoord; out vec2 TexCoord; uniform mat4 model; uniform mat4 view; uniform mat4 projection; void main() { gl_Position = projection * view * model * vec4(aPos, 1.0f); TexCoord = vec2(aTexCoord.x, aTexCoord.y); } then, the matrix manipulated:
      ..... glm::mat4 projection = glm::perspective(glm::radians(fov), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f); ourShader.setMat4("projection", projection); .... glm::mat4 view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp); ourShader.setMat4("view", view); .... model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f)); ourShader.setMat4("model", model);  
      So, some doubts:
      - Why use it like that?
      - Is it okay to manipulate the camera that way?
      -in this way, are not the vertex's positions that changes instead of the camera?
      - I need to pass MVP to all shaders of object in my scenes ?
       
      What it seems, is that the camera stands still and the scenery that changes...
      it's right?
       
       
      Thank you
       
    • By dpadam450
      Sampling a floating point texture where the alpha channel holds 4-bytes of packed data into the float. I don't know how to cast the raw memory to treat it as an integer so I can perform bit-shifting operations.

      int rgbValue = int(textureSample.w);//4 bytes of data packed as color
      // algorithm might not be correct and endianness might need switching.
      vec3 extractedData = vec3(  rgbValue & 0xFF000000,  (rgbValue << 8) & 0xFF000000, (rgbValue << 16) & 0xFF000000);
      extractedData /= 255.0f;
    • By Devashish Khandelwal
      While writing a simple renderer using OpenGL, I faced an issue with the glGetUniformLocation function. For some reason, the location is coming to be -1.
      Anyone has any idea .. what should I do?
  • Advertisement