Notifications
Clear all

[Closed] [SDK] Exporting Explicit Normals (EditNormals Modifier)…

I imagine theres no difference, and no it doesn’t access specified normals (my function that is), but when you create a “new” specified normals on a mesh it’s how it will set the normals. Which CheckNormals ? theres 4 of them Mesh, MeshNormalSpec, MNMesh and MNNormalSpec. It only works on the object it’s called upon. the meshNormSpec version will have no effect on the Mesh rverts and likewise the Mesh version has no effect on Specified Normals.

1 Reply
(@archangel35757)
Joined: 11 months ago

Posts: 0

I was referring to the CheckNormals() you cited in your two MNNormalSpec calls…

I’m just trying to wrap my head around this to fix the exporter (and not break it in some other manner).

So originally, the Softimage coders did not consider smoothing groups (their export option “Vertex normals (ignore smooth groups)” is essence assigned everything to smooth group 1). Their second option “Face normals” ignores any smoothing and simply results in a faceted mesh.

So I need to add export options that retains all smoothing groups and any/all specified/explicit normals. I understand I must add a new method to compute the vertex normals using all smooth group info (either your method or the VNormal method from the SDK). But the modelers want to specifically use the Edit Normals modifier so they can set specified or explicit normals. So when it comes to actually getting all the normals (unspecified, specified, explicit) from the mesh (during the export process) I take it I have to create a pointer to the mesh normals interface (class MNNormalSpec) and then iterate thru that to get out all normals (unspecified, specified, explicit)? And yes, I still need to study those classes in more detail… I’m just looking for the general process flow– thanks!

Ok… so I managed to get the unspecified- , specified- , and explicit normals to export using the method below in my class CdotXSIMapper (which converts 3ds Max data to the dotXSI format).

      CdotXSIMapper member variables:
       m_pFaceNormals
       m_pNormalIndices
       m_iActualNormals
        
       ...hold the data that gets written to the dotXSI template format.
        
       Here is the method that exports the vertex normals:
bool	CdotXSIMapper::CalculateExplicitVertexNormals ( INode *in_pNode )
  {
          	//
          	// Since this operation can take a while, change the progress caption
          	//
          
          	UpdateProgressBar ( L"Converting Scene... [ Calculating Vertex Normals ]" );
          
          	if ( m_pFaceNormals != NULL )
          	{
          		delete [] m_pFaceNormals;
          	}
          
          	if ( m_pNormalIndices != NULL )
          	{
          		delete [] m_pNormalIndices;
          	}
          
          	if ( !m_pExportOptions->bTriangulate )
          	{
          		return CalculateVertexNormalsFromPolygons( in_pNode );
          	}
          
          	Tab<Point3> tempNormals;
          	Tab<Point3> vnorms;
          	BOOL l_bNeedDel = FALSE;
          	ObjectState os = in_pNode->EvalWorldState ( 0 );
          	Mesh *l_pMesh = ((TriObject*)os.obj)->GetRenderMesh( 0, in_pNode, nullView, l_bNeedDel );
          
          	l_pMesh->checkNormals(TRUE);
          
          	//Get pointer to explicit normals
          	MeshNormalSpec* nspec = l_pMesh->GetSpecifiedNormals();
          
          	if ( nspec )
          	{
          		nspec->SetParent(l_pMesh);
          		nspec->CheckNormals();
          	}
          
          	vnorms.SetCount( (l_pMesh->getNumFaces() * 3) );  //initially set to max possible value
          
          	m_pNormalIndices = new int [ l_pMesh->getNumFaces() * 3 ];
          
          	//Initialize vnorms to zero
          	for (int i = 0; i < vnorms.Count(); i++)
          	{
          		vnorms[i] = Point3(0.0f,0.0f,0.0f);
          	}
          
          	assert ( l_pMesh != NULL );
          
          	for (int i = 0; i < l_pMesh->getNumFaces(); i++)
          	{
          		Face *face = &l_pMesh->faces[i];
          		DWORD fsmg = face->getSmGroup();
          		MtlID fmtl = face->getMatID();
          		DWORD *fverts = face->getAllVerts();
          
          		for ( int k = 0; k < 3; k++ )
          		{
          			RVertex &rvert = l_pMesh->getRVert(fverts[k]);
          
          			// Find correct normal
          			if ( nspec /*rvert.rFlags & SPECIFIED_NORMAL*/ )
          			{
          				//vnorms[(i*3)+k] = rvert.rn.getNormal(); //this does not work to get specified/explicit normals 
          				vnorms[(i*3)+k] = nspec->GetNormal(i, k); //this does work
          			}
          			else if ( fsmg == 0 )
          			{
          				vnorms[(i*3)+k] = l_pMesh->getFaceNormal(i);
          			}
          			else
          			{
          				int numNormals = (int)(rvert.rFlags & NORCT_MASK);
          
          				if (numNormals == 1)
          					vnorms[(i*3)+k] = rvert.rn.getNormal();
          				else
          				{
          					// We have multiple normals at this vertex. So we have to pick the correct normal
          					for ( int n = 0; n < numNormals; n++)
          					{
          						RNormal &rn = rvert.ern[n];
          						if ( fsmg & rn.getSmGroup() && fmtl == rn.getMtlIndex() )
          						{
          							vnorms[(i*3)+k] = rn.getNormal();
          							break;
          						}
          					}
          				}
          			}
          		
          			// Populate indice values
          			m_pNormalIndices[(i*3)+k] = (i*3)+k;
          
          		}
          	}
          
          	//
          	// Reduce count by removing duplicate vertex normals
          	//
          
          	for ( int i = 0; i < vnorms.Count(); i++ )
          	{
          		BOOL bAppend = TRUE;
          
          		if ( i == 0 )
          			tempNormals.Append(1,&vnorms[i],0);  //automatically add first normal
          		else
          		{
          			for ( int j = 0; j < tempNormals.Count(); j++ )
          			{
          				if ( vnorms[i] == tempNormals[j] )
          				{
          					//the normal already exists in temp normal list- do not append!
          					//fix normal index to point to correct temp normal index
          					m_pNormalIndices[i] = j;
          
          					bAppend = FALSE;
          
          					break;
          				}
          			}
          
          			if ( bAppend )
          			{
          				//we have a unique normal- append to temp normal list
          				int num = tempNormals.Append(1,&vnorms[i],0);
          
             			 //fix normal index to point to correct temp normal index
          				m_pNormalIndices[i] = num;
          			}
          			
          		}
          
          	}
          
          	m_pFaceNormals	= new Point3 [ tempNormals.Count() ];
          
          	m_iActualNormals = tempNormals.Count();
          
          	//
          	// Initialize all normals to zero
          	//
          
          	for (int z=0; z < m_iActualNormals; z++)
          	{
          		m_pFaceNormals[z] = Point3(0.0f,0.0f,0.0f);
          	}
          
          	//
          	// Perform max2xsi coordinate transformation, normalize, and assign to m_pFaceNormals
          	//
          
          	for (int i = 0; i < m_iActualNormals; i++)
          	{
          		ConvertToYUp ( tempNormals[i] );
          		tempNormals[i] = Normalize( tempNormals[i]);
          		m_pFaceNormals[i] = tempNormals[i];
          
          	}
          
          	return true;
          
  }
  
      [b]My question is...[/b] why didn't the SPECIFIED_NORMAL flag work?  And have I created any flawed logic above?  Or done things grossly incorrect?
Page 2 / 2