PDA

View Full Version : Question regarding Maya Obj Normals


myism
04-23-2007, 06:25 AM
I am writing a cpp/cg application that involves reading obj files exported from maya. In order to draw the imported model via glDrawElement (i.e. allows only one indices array) I rearranged the normal and uv arrays as follows:
void Obj::rearrangeData()
{
vector<float> tmpUV;
vector<float> tmpN;

int size = faces.size();
int normalSize = normal.size();
int uvSize = uv.size();
int psize = pos.size();

tmpUV.assign(uv.begin(), uv.end());
tmpN.assign(normal.begin(), normal.end());

normal.clear();
normal.resize(psize);
uv.clear();
uv.resize(psize*2/3);


for (int i = 0; i < size; i++) {
for (int j = 0; j < 3; j++) {

int iP = ((ObjFace)faces[i]).v[j].indexP - 1;
int iN = ((ObjFace)faces[i]).v[j].indexN - 1;
int iUV = ((ObjFace)faces[i]).v[j].indexUV - 1;

indices.push_back(iP);

uv[iP*2] = tmpUV[iUV*2];
uv[iP*2+1] = tmpUV[iUV*2+1];

normal[iP*3] = tmpN[iN*3];
normal[iP*3+1] = tmpN[iN*3+1];
normal[iP*3+2] = tmpN[iN*3+2];
}
}
//checkNormal(tmpN);
}

However, when I tried to draw the model in my own application, the normals are way off.

Screenshot with lighting and texture on:
http://mengyang.org/Documents/lightinghead_bad.jpg

Screenshot with only texture (it implies the UVs are correct):
http://mengyang.org/Documents/Karen_Texture.jpg

Screenshot for the diffuse lighting map only:
http://mengyang.org/Documents/lightingmap_bad.jpg
Here's the thing that really confuses me:

In order to test the rearranged data, I write the exact model data that I used to draw the geometry back to another obj file, import the file into Maya, and the model, normals and UV's just look correct.

I also tested the DrawGeometry function in my application on other simple geometry such as a sphere, it works fine, i.e. the cg and opengl part should be OK. I suspect the problem is due to the rearrangement of Normals or something like that.

Robert Bateman
04-24-2007, 03:16 PM
You know there will be more normals than points right? And you know that you cannot simply use the same point indices for normal indices right? This just exapands everything out to use a flattened array of data and then glDrawArrays. If you wish to use glDrawElements, then you will have to generate entirely new data arrays and new indices for the vertices.


void Obj::rearrangeData(vector<float>& outputVertexBuffer)
{
for (int i = 0; i < faces.size(); i++) {
for (int j = 0; j < 3; j++) {

int iP = ((ObjFace)faces[i]).v[j].indexP - 1;
int iN = ((ObjFace)faces[i]).v[j].indexN - 1;
int iUV = ((ObjFace)faces[i]).v[j].indexUV - 1;

outputVertexBuffer.push_back( pos[ iP*3 + 0 ] );
outputVertexBuffer.push_back( pos[ iP*3 + 1 ] );
outputVertexBuffer.push_back( pos[ iP*3 + 2 ] );

outputVertexBuffer.push_back( normal[ iN*3 + 0 ] );
outputVertexBuffer.push_back( normal[ iN*3 + 1 ] );
outputVertexBuffer.push_back( normal[ iN*3 + 2 ] );

outputVertexBuffer.push_back( uv[ iUV*2 + 0 ] );
outputVertexBuffer.push_back( uv[ iUV*2 + 1 ] );
}
}
}

Obj someObj;

// load stuff

vector<float> outputVertexBuffer

Obj.rearrangeData(outputVertexBuffer);

glVertexPointer(3,GL_FLOAT,8*sizeof(float),&(outputVertexBuffer[0]));
glNormalPointer(GL_FLOAT,8*sizeof(float),&(outputVertexBuffer[3]));
glTexCoordPointer(2,GL_FLOAT,8*sizeof(float),&(outputVertexBuffer[6]));


glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);

glDrawArrays(GL_TRIANGLES,0,outputVertexBuffer.size()/8);

glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);


To do an indexed set of elems you'll have to generate the new indices, ie :


struct VInf
{
int n;
int t;
int index;
VInf(int _n,int _t,int _index) : n(_n), t(_t), index(_index) {}
VInf(const VInf& vi) : n(vi.n), t(vi.t), index(vi.index) {}
};
typedef std::vector<VInf> VInfArray;

class VInfMap : public std::vector<VInfArray>
{
int maxindex;
public:

VInfMap() : std::vector<VInfArray>(), maxindex(0) {}

int insert_elem(int v,int n,int t)
{
VInfArray& element_info = (*this)[v];
for(int i=0;i!=element_info.size();++i)
{
if( n == element_info[i].n && t == element_info[i].t )
{
return element_info[i].index;
}
}
element_info.push_back( VInf(n,t,maxindex) );
return maxindex++;
}
}



void Obj::rearrangeData(vector<float>& outputVertexBuffer,vector<int>& outputIndexBuffer)
{
VInfMap temp;

outputIndexBuffer.resize( faces.size()*3 );

temp.resize(pos.size()/3);

vector<int>::iterator index = outputIndexBuffer.begin();

for (int i = 0; i < faces.size(); i++) {
for (int j = 0; j < 3; j++) {

int iP = ((ObjFace)faces[i]).v[j].indexP - 1;
int iN = ((ObjFace)faces[i]).v[j].indexN - 1;
int iUV = ((ObjFace)faces[i]).v[j].indexUV - 1;

*index = temp.insert_elem( iP, iN, iUV );
if((*index)>=(outputVertexBuffer.size()/8))
{
outputVertexBuffer.push_back( pos[ iP*3 + 0 ] );
outputVertexBuffer.push_back( pos[ iP*3 + 1 ] );
outputVertexBuffer.push_back( pos[ iP*3 + 2 ] );

outputVertexBuffer.push_back( normal[ iN*3 + 0 ] );
outputVertexBuffer.push_back( normal[ iN*3 + 1 ] );
outputVertexBuffer.push_back( normal[ iN*3 + 2 ] );

outputVertexBuffer.push_back( uv[ iUV*2 + 0 ] );
outputVertexBuffer.push_back( uv[ iUV*2 + 1 ] );
}
}
}
}



Obj someObj;

// load stuff

vector<float> outputVertexBuffer
vector<int> outputIndexBuffer

Obj.rearrangeData(outputVertexBuffer,outputIndexBuffer);

glVertexPointer(3,GL_FLOAT,8*sizeof(float),&(outputVertexBuffer[0]));
glNormalPointer(GL_FLOAT,8*sizeof(float),&(outputVertexBuffer[3]));
glTexCoordPointer(2,GL_FLOAT,8*sizeof(float),&(outputVertexBuffer[6]));


glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);

glDrawElements(GL_TRIANGLES,0,outputIndexBuffer.size()/3,&(outputIndexBuffer[0]));

glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);

CGTalk Moderation
04-24-2007, 03:16 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.