Sign in to follow this  
nitinjavakid

Smooth polygon required

Recommended Posts

It looks like your faces are detached. What's the source of the model? What do you know about its format?

In any case, you need per-vertex normals rather than per-face as you have now. The first step is to un-detach the faces (I can't be much more specific about that since I don't know what format you're working with). The next step will then be to compute vertex normals from the face normals; how to do this is currently being discussed in a thread in the 'graphics programming' forum (or at least was as of a couple of days ago.

Share this post


Link to post
Share on other sites
Quote:
Original post by nitinjavakid
I am a using Quake 3 model
Hm, I don't think that tells us enough to be very helpful. IIRC, the vertex normals for Q3 models are stored as compressed spherical coordinates and must be converted on load. Are you doing this step? How are you rendering the model - immediate mode, or arrays of some sort?

Anyway, we probably need a bit more info.

Share this post


Link to post
Share on other sites
Actually I am storing the vertices and all animation info in a vector.

here is the code for storing data from file and for drawing it



#include "N3DObject.h"
#include <map>
#include <string>
#include <math.h>
#ifndef _MD3OBJECT_H

typedef struct
{
short int x,y,z;
short int normal;
}m3dvertex;

struct md3fileheader
{
int m_iId; //Must be IDP3 (860898377)
int m_iVersion; //Must be 15
char m_cFilename[68]; //Full filename
int m_iNumFrames; //Number of animation keyframes
int m_iNumTags; //Number of tags
int m_iNumMeshes; //Number of sub-meshes
int m_iMaxSkins; //Maximum number of skins for model
int m_iHeaderSize; //Size of this header
int m_iTagOffset; //File offset for tags
int m_iMeshOffset; //End of tags
int m_iFileSize; //Size of file
};

struct md3meshheader
{
char m_cMeshId[4]; //Mesh ID
char m_cName[68]; //Mesh name
int m_iNumMeshFrames; //Number of animation frames in mesh
int m_iNumSkins; //Number of skins for this mesh
int m_iNumVerts; //Number of vertices
int m_iNumTriangles; //Number of triangles
int m_iTriOffset; //Offset for the triangles
int m_iHeaderSize; //Size of this header
int m_iUVOffset; //Texture coordinate offset
int m_iVertexOffset; //Offset for the vertices
int m_iMeshSize; //Total size of the mesh
};

typedef struct
{
nvertex position;
float matrix[9];
}md3tag;

typedef struct
{
std::vector <md3tag>tags;
}md3tagframe;

typedef struct
{
std::vector <nvertex> vertices;
std::map<std::string,md3tag> tags;
} md3keyframe;

typedef struct
{
md3meshheader header;
std::vector <md3keyframe> keyframes;
std::vector <ntexcoord> texcoords;
std::vector <ntriangle> triangles;
GLuint texture;
} md3mesh;
typedef struct
{
unsigned int from;
unsigned int to;
unsigned int loops;
unsigned int fps;
}md3animinfo;

typedef struct
{
nvertex minvertex;
nvertex maxvertex;
nvertex origin;
float radius;
char name[16];
} md3boneframe;

class MD3Model;
class MD3Object:public N3DObject
{
public:
md3fileheader header;
std::vector <md3boneframe> boneframes;
std::vector <md3mesh> meshes;
std::map <std::string,md3tagframe>tagframes;
std::map <std::string,MD3Object*> attachments;
double curkeyframe;

MD3Object(const char *filename,const char *skin);
void draw();
void notifyAll();
void attach(MD3Object *pmodel,const std::string &);
};

class MD3Model:public N3DObject
{
public:
std::map <std::string,MD3Object *> objects;
std::map <std::string,md3animinfo> animations;

MD3Model();
~MD3Model();
void loadFromFolder(const char *,const char *);
void draw();
void addObject(const std::string &,MD3Object*);
};
void MD3Init();
void ReduceToUnit(float vector[3]);
void calcNormal(float v[3][3], float out[3]);

#define _MD3OBJECT_H
#endif

MD3Object::MD3Object(const char *filename,const char *skin):N3DObject()
{
bool skinpresent = false;
unsigned int temptexture=0;
if(strcmpi(skin + (strlen(skin)-4),"skin")==0)
{
skinpresent = true;
}
else
{
temptexture = ilutGLLoadImage((char *)skin);
skinpresent = false;
}

unsigned int counter;
curkeyframe = 0.01;

FILE *file;
file = fopen(filename,"rb");

if(!file)
{
cout<<"\nUnable to access file";
return;
}
char *skinch;
if(skinpresent)
{
FILE *skinfile;
skinfile = fopen(skin,"r");
if(!skinfile)
{
cout<<"\nUnable to access skin file";
}
else
{
skinch = new char[sizeof(char)*filelength(fileno(skinfile)) + 1];
fread(skinch,sizeof(char)*filelength(fileno(skinfile)),1,skinfile);
skinch[sizeof(char)*filelength(fileno(skinfile))] = 0;
fclose(skinfile);
}
}

//Reading file
fread(&header,sizeof(header),1,file);
if(header.m_iId!=860898377 || header.m_iVersion!=15)
{
cout<<"\nInvalid file format";
return;
}


//Bone frames
fseek(file,header.m_iHeaderSize,SEEK_SET);
for(counter=0;counter<header.m_iNumFrames;++counter)
{
md3boneframe tempframe;
fread(&tempframe,sizeof(tempframe),1,file);
boneframes.push_back(tempframe);
}

//Meshes
fseek(file,header.m_iMeshOffset,SEEK_SET);

for(counter=0;counter<header.m_iNumMeshes;++counter)
{
md3mesh temp;

long temppos = ftell(file);

fread(&temp.header,sizeof(temp.header),1,file);
//printf("%s\n",temp.header.m_cName);
//loading texture
if(skinpresent)
{
if(skinch!=NULL)
{
char *tempstr = strstr(skinch,temp.header.m_cName);

std::string texfilename;
temp.texture = 0;
if(tempstr)
{
char tempfilename[2048];
texfilename = skin;
if(texfilename.find_last_of("\\")>0)
texfilename = texfilename.substr(0,texfilename.find_last_of("\\")) + "\\";
else if(texfilename.find_last_of("/")>0)
texfilename = texfilename.substr(0,texfilename.find_last_of("/")) + "/";

if(strchr(tempstr,'\n'))
strncpy(tempfilename,strchr(tempstr,',')+1,strchr(tempstr,'\n')-strchr(tempstr,',')+1);
else
strcpy(tempfilename,strchr(tempstr,',')+1);

if(strrchr(tempfilename,'/')>0)
texfilename += strrchr(tempfilename,'/') +1;
else if(strrchr(tempfilename,'\\')>0)
texfilename += strrchr(tempfilename,'\\') +1;
else
texfilename += tempfilename;

texfilename = texfilename.substr(0,texfilename.find("\n"));


//strcpy(tempfilename,texfilename.c_str());
// printf("%s\n",tempfilename);
temp.texture = ilutGLLoadImage(const_cast<char *> (texfilename.c_str()));
}
else
{
printf("texture for mesh %s needs to be specified in skin file\n",temp.header.m_cName);
}
}
//loaded
}
else
{
temp.texture = temptexture;
}
//keyframes
fseek(file,temp.header.m_iVertexOffset + temppos,SEEK_SET);
for(int i=0;i<temp.header.m_iNumMeshFrames;++i)
{
md3keyframe keyframe;
for(int j=0;j<temp.header.m_iNumVerts;++j)
{
m3dvertex tempvertex;
fread(&tempvertex,sizeof(tempvertex),1,file);

nvertex tempnv;
tempnv.x = tempvertex.x/ 64.0;
tempnv.y = tempvertex.y/64.0;
tempnv.z = tempvertex.z/64.0;
keyframe.vertices.push_back(tempnv);
}
temp.keyframes.push_back(keyframe);
}

//triangles
fseek(file,temp.header.m_iTriOffset + temppos,SEEK_SET);
for(i=0;i<temp.header.m_iNumTriangles;++i)
{
ntriangle temptriangle;
fread(&temptriangle,sizeof(ntriangle),1,file);
temp.triangles.push_back(temptriangle);
}

//texcoords
fseek(file,temp.header.m_iUVOffset + temppos,SEEK_SET);
for(i=0;i<temp.header.m_iNumVerts;++i)
{
ntexcoord temptexcoord;
fread(&temptexcoord,sizeof(ntexcoord),1,file);
temp.texcoords.push_back(temptexcoord);
}
meshes.push_back(temp);
fseek(file,temppos + temp.header.m_iMeshSize, SEEK_SET);
}

//Tags
fseek(file,header.m_iTagOffset,SEEK_SET);
for(counter=0;counter<header.m_iNumFrames;++counter)
{
for(int i=0;i<header.m_iNumTags;++i)
{
char name[64];
fread(name,sizeof(char)*64,1,file);
md3tag temptag;
fread(&temptag,sizeof(temptag),1,file);
tagframes[name].tags.push_back(temptag);
}
}
fclose(file);
if(skinpresent)
{
try{
delete [] skinch;
}catch(...)
{
}
}
}


void MD3Object::draw()
{
if(visible)
{
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glMultMatrixd(matrix);

float interpolation = curkeyframe - floor(curkeyframe);
if(curkeyframe==0.0) curkeyframe =0.1;

glEnable(GL_TEXTURE_2D);
for(int i=0;i<meshes.size();++i)
{
glBindTexture(GL_TEXTURE_2D,meshes[i].texture);
glBegin(GL_TRIANGLES);
for(int j=0;j<meshes[i].triangles.size();++j)
{
float triangle[3][3];
ntexcoord coord[3];
for(int k=0;k<3;++k)
{
if(curkeyframe>=meshes[i].header.m_iNumMeshFrames-1) curkeyframe = header.m_iNumFrames-1;
nvertex temp1;
nvertex temp2;
if(curkeyframe!=0)
{
temp1 = meshes[i].keyframes[(int)ceil(curkeyframe) - 1].vertices[meshes[i].triangles[j].vertices[k]];
temp2 = meshes[i].keyframes[(int)ceil(curkeyframe)].vertices[meshes[i].triangles[j].vertices[k]];
}
else
{
temp1 = meshes[i].keyframes[0].vertices[meshes[i].triangles[j].vertices[k]];
temp2 = meshes[i].keyframes[0].vertices[meshes[i].triangles[j].vertices[k]];
}
coord[k] = meshes[i].texcoords[meshes[i].triangles[j].vertices[k]];
float x = temp1.x + (temp2.x-temp1.x)*interpolation;
float y = temp1.y + (temp2.y-temp1.y)*interpolation;
float z = temp1.z + (temp2.z-temp1.z)*interpolation;

triangle[k][0] = x;
triangle[k][1] = y;
triangle[k][2] = z;
}
float out[3];
calcNormal(triangle,out);
glNormal3fv(out);
for(k=0;k<3;k++)
{
glTexCoord2f(coord[k].u,coord[k].v);
glVertex3fv(triangle[k]);
}
}
glEnd();
}
glDisable(GL_TEXTURE_2D);
glPopMatrix();
}
}

Share this post


Link to post
Share on other sites
A quick look at your code indicates that you're ignoring the vertex normals stored with the model and instead calculating the normals on the fly on a per-triangle basis. The faceted shading that you're getting is exactly what you should expect in this case.

If you want smooth shading you will have to:

a) Read the normals from the model file along with the other data, decompress them, and store them with the vertex data.

b) Issue a normal per vertex when you render. I think this can still be done via immediate mode; you'll just have to make a call to glNormal3*() at the appropriate place.

Just to get you started, here's an example of what I mean. Instead of this:
glNormal3fv(out);
for(k=0;k<3;k++)
{
glTexCoord2f(coord[k].u,coord[k].v);
glVertex3fv(triangle[k]);
}
You need something like this:
for(k=0;k<3;k++)
{
glNormal3f(coord[k].nx,coord[k].ny,coord[k].nz);
glTexCoord2f(coord[k].u,coord[k].v);
glVertex3fv(triangle[k]);
}

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this