[Closed] SDK: modyfing vertex normals
Hi.
I’m trying to manually set the direction of vertex normal. Let’s say that I want to render a hemi-sphere looking like a flat plane (changing its shading only, not the geometry), so I want to set each vertex normal not to be computed from surrounding faces, but fixed at [0,0,1] (pointing upwards). Which classes and methods should I use? Can you give me any clues or examples?
I’m trying to achieve the same result as here with the Edit Normals modifier, but using my own modifier:
Thanks.
Thanks, that was very useful. For now I’m able to modify the normals when my modifier is above the previously added Edit_Normals modifier, I’m obtaining the normals array with:
MeshNormalSpec *meshNorm = mesh.GetSpecifiedNormals();
Point3* normalArray = meshNorm->GetNormalArray();
So I assume the normalArray contains some specified Point3 directions, and each face corner contains the index. Unfortunately I don’t know how to make it without the Edit_Normals modifier below, I’ve set the SetNumNormals, set the normal of each face corner with meshNorm->SetNormal() and call the meshNorm->SetAllExplicit(true) after that, but I can’t see any result in the viewport. How to create the explicit normals properly?
are you trying to setting them to [0,0,1] by any chance ? that will leave them unchanged because they’ll be in local object coordinates and they are probably already [0,0,1].
No, for now I’m trying to set the normals to some random directions:
MeshNormalSpec *meshNorm = (MeshNormalSpec *) mesh.GetInterface(MESH_NORMAL_SPEC_INTERFACE);
meshNorm->SetNumNormals(mesh.numFaces * 3);
Point3* normalsArray = new Point3[meshNorm->GetNumNormals()];
for (int n = 0; n < meshNorm->GetNumNormals(); n++)
{
normalsArray[n].x = (((float) rand() / (RAND_MAX)) * 2.0f) - 1.0f;
normalsArray[n].y = (((float) rand() / (RAND_MAX)) * 2.0f) - 1.0f;
normalsArray[n].z = (((float) rand() / (RAND_MAX)) * 2.0f) - 1.0f;
normalsArray[n] = normalsArray[n].Normalize();
}
int nIndex = 0;
for (int f=0; f<mesh.numFaces; f++)
{
meshNorm->SetNormal(f, 0, normalsArray[nIndex]);
nIndex++;
meshNorm->SetNormal(f, 1, normalsArray[nIndex]);
nIndex++;
meshNorm->SetNormal(f, 2, normalsArray[nIndex]);
nIndex++;
}
meshNorm->SetAllExplicit(true);
Unfortunately I don’t see any result in the viewport.
try this
MeshNormalSpec* nspec = mesh->GetSpecifiedNormals();
if(nspec && !nspec->GetFlag(MESH_NORMAL_NORMALS_BUILT))
{
mesh->SpecifyNormals();
nspec = mesh->GetSpecifiedNormals();
}
if(nspec)
{
nspec->ClearFlag(MESH_NORMAL_NORMALS_BUILT);
nspec->CheckNormals();
Point3* normals = nspec->GetNormalArray();
for (int n = 0; n < meshNorm->GetNumNormals(); ++n)
{
normals [n].x = (((float) rand() / (RAND_MAX)) * 2.0f) - 1.0f;
normals [n].y = (((float) rand() / (RAND_MAX)) * 2.0f) - 1.0f;
normals [n].z = (((float) rand() / (RAND_MAX)) * 2.0f) - 1.0f;
normals [n] = normals [n].Normalize();
}
nspec->SetAllExplicit(true);
}
Doesn’t seem to work. I can see the modified normals only with the Edit_Normals modifier below.
That didn’t work at first because the nspec variable isn’t NULL even if the normals aren’t specified, but works like a charm after I commented the if(nspec) line, thank you so much for your help!!!
another edit
it has to be said it’s not the way that EditNormals handles it in. You should really copy the way they do it in EditNormals e.g maintaining your own version of specified normals in a local mod data structure and copying in the pipe normals, editing them and copying them back. Also if you want to display your normals in the viewport you’ll have to you own copy of the mesh and specified normals for the display calls otherwize max will crash
something like this…
if(!lmd->TriNormals)
{
lmd->TriNormals = new MeshNormalSpec();
MeshNormalSpec *pipenormals = (MeshNormalSpec *) triobj->GetMesh().GetInterface(MESH_NORMAL_SPEC_INTERFACE);
if (pipenormals) lmd->TriNormals->CopySpecified(*pipenormals);
lmd->InvalidateTopoCache();
}
if(!lmd->GetTopoValid (t))
{
lmd->TriNormals->ClearFlag (MESH_NORMAL_NORMALS_BUILT);
lmd->TriNormals->SetParent(&triobj->GetMesh());
lmd->TriNormals->CheckNormals ();
lmd->TriNormals->SetParent(NULL);
lmd->SetTopoValid(triobj->ChannelValidity(t, TOPO_CHAN_NUM));
lmd->SetGeomValid(triobj->ChannelValidity(t, GEOM_CHAN_NUM));
}
if (!lmd->GetGeomValid(t)
{
lmd->TriNormals->ClearFlag (MESH_NORMAL_NORMALS_COMPUTED);
lmd->TriNormals->SetParent(&triobj->GetMesh());
lmd->TriNormals->CheckNormals ();
lmd->TriNormals->SetParent (NULL);
lmd->SetGeomValid(triobj->ChannelValidity(t, GEOM_CHAN_NUM));
}
// edit our copy of the pipeline normals
Point3* normals = lmd->TriNormals->GetNormalArray();
for (int n = 0; n < lmd->TriNormals->GetNumNormals(); ++n)
{
normals [n].x = (((float) rand() / (RAND_MAX)) * 2.0f) - 1.0f;
normals [n].y = (((float) rand() / (RAND_MAX)) * 2.0f) - 1.0f;
normals [n].z = (((float) rand() / (RAND_MAX)) * 2.0f) - 1.0f;
normals [n] = normals [n].Normalize();
}
lmd->TriNormals->SetAllExplicit(true);
// Copy our normals over to pipeline mesh:
MeshNormalSpec *pipenormals = (MeshNormalSpec *) triobj->GetMesh().GetInterface (MESH_NORMAL_SPEC_INTERFACE);
if (pipenormals)
{
*pipenormals = *lmd->TriNormals;
pipenormals->SetParent(&triobj->GetMesh());
}
you’ll have to search through EditNormals.cpp to see where it invalidates the geometry and topology forcing rebuilding of the normals