Notifications
Clear all

[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.

12 Replies

\maxsdk\samples\mesh\editablepoly\EditNormals.cpp

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.

added an edit to the example for when you need to create the normals

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

Page 1 / 2