Jump to content
  • Advertisement
Sign in to follow this  
BlackRyder

3DS and normals

This topic is 4801 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

some1 here knows if 3DS saves the compution of the face normals. and if 3ds does saves it in the file what is the CHUNK ID? 10x in Advance BlackRyder

Share this post


Link to post
Share on other sites
Advertisement
Don't know, 3ds is such an old format, so im not even shure they thought about it then, maybe they added it on later, in witch case older models might not have it.
It might be worth to check out http://www.wotsit.org/ just to be shure.
Either way, it's probobly better if you calcylate them yourself at load time.
It's fast, easy and you might even get better results if you do it right.

Share this post


Link to post
Share on other sites
i am computing the normals at loading but i got some crappy results maybe it worth if someone here could check it out for me:

calculating a face normal:


inline Vector3D Object::computeFaceNormal(const Face &face)
{
Vector3D u(vertex_list.at(face[0]),vertex_list.at(face[1]));
Vector3D v(vertex_list.at(face[0]),vertex_list.at(face[2]));

return u.crossProduct(v);
}
Vector3D Vector3D::crossProduct(const Vector3D &v)
{
Vector3D result;

result.x = (y*v.z) - (z*v.y);
result.y = (z*v.x) - (x*v.z);
result.z = (x*v.y) - (y*v.x);

return result;
}




Share this post


Link to post
Share on other sites
looks ok, but i can't be shure.
a few things can happen to create crappy results.
1. the normal can get inverted
2. the normal might have the wrong magnitude

So normalize your normals to a magnitude of 1 or -1 depending on witch one looks the best.

But this will only get you half way, the normals will make your models look faceted.

So to make the normals smoother you must blend your normals with it's neighbours.
For every vertic on every face you test the facenormal with every neighbouring faces facenormal using a dot product.
if the result is larger than 0.71 then add that normal to the vertic normal.
And finaly normalize all the normals one last time to a magnitude of 1.

Share this post


Link to post
Share on other sites
your last algorithem is like O(n^2) you test every vertic to check the whole
conectivity.
isnt it faster to produce the normal list offline?
and load it when ever you need it...

Share this post


Link to post
Share on other sites
it's allways faster to do that.
it's allways better to have your own format,instead of using another one that doesn't contain all the stuff you need.

But i did run this code once for every frame, it actuarly worked fairly well, but it didn't run as fast is i wanted to.

Share this post


Link to post
Share on other sites
take a look at the code and comment it


Vector3D Object::computeVertexBlendedNormal(unsigned int vertexNum,vector<Vector3D> &facesNormalList)
{
Face face; //Holds the current tested faces
unsigned int faceNum; //Holds the current face number that we test.
Vector3D vertexNormal; //Holds the result blended normal
Vector3D faceNormal; //Holds the current face normal
Vector3D blendNormal; //Holds the result blended normal
bool first=true; //Holds indication if this is the first face that hold the vertex


for(faceNum=0;faceNum<face_list.size();faceNum++)
{
face = face_list.at(faceNum);
//if this is a neighbor face
if((face[0]==vertexNum)||(face[1]==vertexNum)||(face[2]==vertexNum))
{
faceNormal = facesNormalList.at(faceNum);
if(first)
{
blendedNormal = faceNormal;
vertexNormal = faceNormal;
first = false;
}
else
{
if(vertexNormal.dotProduct(faceNormal)>=0.71)
{
blendNormal =vertexNormal+faceNormal;
}
}
}
}

blendNormal.normalize();
return blendNormal;

}




[Edited by - BlackRyder on September 11, 2005 5:32:50 AM]

Share this post


Link to post
Share on other sites
um more like this perhaps

note: currentfaceNum should be the current face this normal is attatched to, this is important.
Allso remember that each face has 4 normals, the face normal and the individual vertex normals, witch are the blended ones, i cant tell if you have it this way, but you should.


Vector3D Object::computeVertexBlendedNormal(unsigned int currentfaceNum,unsigned int vertexNum,vector<Vector3D> &facesNormalList)
{
Face face; //Holds the current tested faces
unsigned int faceNum; //Holds the current face number that we test.
Vector3D vertexNormal; //Holds the result blended normal
Vector3D faceNormal; //Holds the current face normal
Vector3D blendNormal; //Holds the result blended normal
bool first=true; //Holds indication if this is the first face that hold the vertex

vertexNormal = facesNormalList.at(currentfaceNum);

for(faceNum=0;faceNum<face_list.size();faceNum++)
{
face = face_list.at(faceNum);
//if this is a neighbor face
if((face[0]==vertexNum)||(face[1]==vertexNum)||(face[2]==vertexNum))
{
faceNormal = facesNormalList.at(faceNum);
if(vertexNormal.dotProduct(faceNormal)>=0.71)
{
if(first)
{
blendedNormal = faceNormal;
first = false;
} else {
blendNormal +=faceNormal;
}
}
}
}

blendNormal.normalize();
return blendNormal;

}


Share this post


Link to post
Share on other sites
at first the facesNormalList has only the face normal
because at first each vertex has the same normal as its face normal
that is why i had the "first" indication because i take the first face that contains the vertex as the vertexNormal to work with and test according to it.

please correct me if i am wrong

Share this post


Link to post
Share on other sites
Well, you have to use the normal it had first(the face normal), before you started testing, .

But that doesn't mean that it will be the one that you encounter first in the list, it might be the second one or third or whatever.

let me post some of my code(witch BTW is old and uggly), it might explain things a bit better.
POLS.p_data is the polygon structure where each p_data is a polygon.
.v_ref is the vertex references of the polygon.
.p_n is the face normal of the polygon.
.n[ ] is the vertex normals of the polygon.
there is allso a .v_uv, but it's not use here.
i,j,k are integers.




float tn[3]; //temp normal storage
int num,vn;

i=0;
while(i<cfmdfile->POLS.p_num)
{

k=0;
while(k<3)
{
j=0;

num=0;
tn[0]=0;
tn[1]=0;
tn[2]=0;

// first find and add all normals who share this point to tn
while(j<cfmdfile->POLS.p_num)
{
if (cfmdfile->POLS.p_data[j].v_ref[0]==cfmdfile->POLS.p_data.v_ref[k])
{
if (dotproduct(cfmdfile->POLS.p_data[j].p_n,cfmdfile->POLS.p_data.p_n)>0.71f)
{
tn[0]+=cfmdfile->POLS.p_data[j].p_n[0];
tn[1]+=cfmdfile->POLS.p_data[j].p_n[1];
tn[2]+=cfmdfile->POLS.p_data[j].p_n[2];
}

}

if (cfmdfile->POLS.p_data[j].v_ref[1]==cfmdfile->POLS.p_data.v_ref[k])
{
if (dotproduct(cfmdfile->POLS.p_data[j].p_n,cfmdfile->POLS.p_data.p_n)>0.71f)
{
tn[0]+=cfmdfile->POLS.p_data[j].p_n[0];
tn[1]+=cfmdfile->POLS.p_data[j].p_n[1];
tn[2]+=cfmdfile->POLS.p_data[j].p_n[2];
}

}

if (cfmdfile->POLS.p_data[j].v_ref[2]==cfmdfile->POLS.p_data.v_ref[k])
{
if (dotproduct(cfmdfile->POLS.p_data[j].p_n,cfmdfile->POLS.p_data.p_n)>0.71f)
{
tn[0]+=cfmdfile->POLS.p_data[j].p_n[0];
tn[1]+=cfmdfile->POLS.p_data[j].p_n[1];
tn[2]+=cfmdfile->POLS.p_data[j].p_n[2];
}

}


j++;
}

//normalize the values
m=magnitude(tn);
tn[0]=tn[0]/m;
tn[1]=tn[1]/m;
tn[2]=tn[2]/m;






// Second, place it where it belongs
cfmdfile->POLS.p_data.n[k][0]=tn[0];
cfmdfile->POLS.p_data.n[k][1]=tn[1];
cfmdfile->POLS.p_data.n[k][2]=tn[2];



k++;
}
i++;
}




Share this post


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

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!