Jump to content
  • Advertisement
Sign in to follow this  
wh1sp3rik

3ds max SDK - Get vertex normals

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

Hello,
I don't know, where to ask, i have tried autodesk forum, but no response, seems, their forum is dead, lol.

i hope, someone here will have experience with writing plugins for 3ds max.
My problem is, i can't get normals per vertex.

I can get normal per face, but when using smoothing groups etc, i need more normals then only one per face.

So, How can i get normal per vertex ? thank you very much for help :)

using standard Mesh class. c++, 3ds max sdk 2010

[Edited by - wh1sp3rik on August 21, 2010 4:28:34 AM]

Share this post


Link to post
Share on other sites
Advertisement
Iterate through the faces of the mesh, associating the normal of each face (and it's smoothing group) with each of the three vertexes of the face.

You will now have a list of normals per vertex which can then be averaged based on the smoothing groups or however you want to find the per vertex normals.

Share this post


Link to post
Share on other sites
Hi, i've done an exporter in the past, and i had to generate them myself because studio max dosen't have anything to export them, i used the code from a .3ds file importer and modified it a bit. Here's the code im using, it give pretty good result(you'll have to adapt it to your code of course):



class CVector3
{
public:
float x, y, z;
void Set(float i1, float i2, float i3){this->x=i1;this->y=i2;this->z=i3;};
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// This calculates a vector between 2 points and returns the result
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CVector3 _Vector(CVector3 vPoint1, CVector3 vPoint2)
{
CVector3 vVector;
vVector.x = vPoint1.x - vPoint2.x;
vVector.y = vPoint1.y - vPoint2.y;
vVector.z = vPoint1.z - vPoint2.z;
return vVector;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// This adds 2 vectors together and returns the result
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CVector3 _AddVector(CVector3 vVector1, CVector3 vVector2)
{
CVector3 vResult;
vResult.x = vVector2.x + vVector1.x;
vResult.y = vVector2.y + vVector1.y;
vResult.z = vVector2.z + vVector1.z;
return vResult;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// This divides a vector by a single number (scalar) and returns the result
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CVector3 _DivideVectorByScaler(CVector3 vVector1, float Scaler)
{
CVector3 vResult;
vResult.x = vVector1.x / Scaler;
vResult.y = vVector1.y / Scaler;
vResult.z = vVector1.z / Scaler;
return vResult;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// This returns the cross product between 2 vectors
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CVector3 _Cross(CVector3 vVector1, CVector3 vVector2)
{
CVector3 vCross;
vCross.x = ((vVector1.y * vVector2.z) - (vVector1.z * vVector2.y));
vCross.y = ((vVector1.z * vVector2.x) - (vVector1.x * vVector2.z));
vCross.z = ((vVector1.x * vVector2.y) - (vVector1.y * vVector2.x));
return vCross; // Return the cross product
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Save the vertex normals (smooth)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Model3DExport::SaveNormals(Mesh* pMesh, Matrix3 tm, CModelDataStruct* pModelData)
{
if(!Options.GenNormalsVA){return;}

UINT NumVerts = pModelData->IndexedVerticesCount;
UINT NumFaces = pModelData->FacesCount;

int Indx[3];
CVector3 vVector1, vVector2, vNormal, vPoly[3];

//Allocate memory for our normals and the shared info
CVector3 *pVertexNormals = new CVector3[NumVerts];
int *pShared = new int[NumVerts];
//Initialize our array
ZeroMemory(pVertexNormals, sizeof(CVector3) * NumVerts);
ZeroMemory(pShared, sizeof(int) * NumVerts);

///////////////////////////////////////////////////////////////////////////////
//Here we'll compute normals(this new algorithm of mine is BLAZING FAST!)...
///////////////////////////////////////////////////////////////////////////////

// Go though all of the faces of this object
for(int i = 0; i < NumFaces; i++){

//Read the 3 face vertex
for(int j = 0; j < 3; j++){
Indx[j] = pMesh->faces.v[j];
Point3 v = (tm * pMesh->verts[Indx[j]]);
vPoly[j].Set(v.x, v.z, 0.0f - v.y);
}

// Now let's calculate the face normals (Get 2 vectors and find the cross product of those 2)
vVector1 = _Vector(vPoly[0], vPoly[2]); // Get the vector of the polygon (we just need 2 sides for the normal)
vVector2 = _Vector(vPoly[2], vPoly[1]); // Get a second vector of the polygon

//This get our FACE normals
vNormal = _Cross(vVector1, vVector2); // Return the cross product of the 2 vectors (normalize vector, but not a unit vector)

//Accum the value for the 3 VERTEX normals and keep track of a shared value
for(j = 0; j < 3; j++){
pVertexNormals[Indx[j]] = _AddVector(pVertexNormals[Indx[j]], vNormal);
pShared[Indx[j]]++;
}
}

///////////////////////////////////////////////////////////////////////////////////////

// Now Get The Vertex Normals and save them
for(i = 0; i < NumVerts; i++){
pVertexNormals = _DivideVectorByScaler(pVertexNormals, float(-pShared));
pVertexNormals = _Normalize(pVertexNormals);
memcpy(&pModelData->pNormalsArray[VA_INDEXED], &pVertexNormals.x, sizeof(float3));
}

///////////////////////////////////////////////////////////////////////////////////////

// Delete temp buffers
SAFE_DELETE_ARRAY(pShared);
SAFE_DELETE_ARRAY(pVertexNormals);

if(Options.ForceSmoothNormals){
ConvertToNonIndexed((BYTE*)pModelData->pNormalsArray[VA_NON_INDEXED], (BYTE*)pModelData->pNormalsArray[VA_INDEXED], sizeof(float3), pModelData);
} else {
SaveFacesNormals(pMesh, tm, pModelData);
}
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Save the face normals
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Model3DExport::SaveFacesNormals(Mesh* pMesh, Matrix3 tm, CModelDataStruct* pModelData)
{
if(!Options.GenNormalsVA){return;}

UINT NumVerts = pModelData->VerticesCount;
UINT NumFaces = pModelData->FacesCount;

CVector3 vVector1, vVector2, vNormal, vPoly[3];
int Indx[3];

// Go though all of the faces of this object
for(int i = 0; i < NumFaces; i++){

//Read the 3 face vertex
for(int j = 0; j < 3; j++){
Indx[j] = pMesh->faces.v[j];
Point3 v = (tm * pMesh->verts[Indx[j]]);
vPoly[j].Set(v.x, v.z, 0.0f - v.y);
}

// Now let's calculate the face normals (Get 2 vectors and find the cross product of those 2)
vVector1 = _Vector(vPoly[0], vPoly[2]); // Get the vector of the polygon (we just need 2 sides for the normal)
vVector2 = _Vector(vPoly[2], vPoly[1]); // Get a second vector of the polygon

//This get our FACE normals
vNormal = _Cross(vVector1, vVector2); // Return the cross product of the 2 vectors (normalize vector, but not a unit vector)

vNormal = _DivideVectorByScaler(vNormal, -1.0f);
vNormal = _Normalize(vNormal);

//Save them in our FACE normals array
memcpy(&pModelData->pNormalsArray[VA_NON_INDEXED][(i * 3) ], &vNormal.x, sizeof(float3));
memcpy(&pModelData->pNormalsArray[VA_NON_INDEXED][(i * 3)+1], &vNormal.x, sizeof(float3));
memcpy(&pModelData->pNormalsArray[VA_NON_INDEXED][(i * 3)+2], &vNormal.x, sizeof(float3));
}
}
[\source]






The code might seem messy but it's really fast and give very nice result.
(The original code was slow has hell...)

Share this post


Link to post
Share on other sites
Ascii scene exporter (or not ascii??) in MAX (.ASE) exports vertex normals. But I don't know how it arranges the stuff, maybe it's not "VBO friendly".

EDITED

[Edited by - szecs on August 21, 2010 12:21:44 PM]

Share this post


Link to post
Share on other sites
that's not a problem, how it's arranged, because i just build a array or vertices, normals, uvs without indices and then i will make own indices.

Your code is like mine.. You can just call GetFaceNormal for that ;-) there is a list of normals without indices and they are averaged by 3ds max without any smoohting group.

I think think about it. Now i would liek to try IGame interface, because there are wrapper all functions i need and if it's not suitable, i will go this way you suggested, thank you very much.

Share this post


Link to post
Share on other sites
I recommend using the FBX SDK. The documentation is pretty sparse but once you get it working it is pretty powerful, and also contains tangents and binormals (and a number of other vertex attributes). Check out the code here for getting normals.

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!