IRVertex problem accessing multiple normals

 
 
 
Posted by:zarusz
Data created:28 November 2010

Hello,

I am trying to port my existing max export plugin written in C++ to C# using MAX.NET wrapper.

In IRVertex I have encountered a problem accessing multiple normals.

According to the C++ RVertex definition (taken from maxsdk):

class RVertex: public MaxHeapOperators {
//...
        DWORD        rFlags;     
        int            pos[3];    
        RNormal        rn;           
        RNormal     *ern;        
    };                   

The ern is an array of RNormal of length calculated from (rFlags & SPECIFIED_NORMAL), wheras in MAX.NET the IRVertex.Ern is a single IRNormal just like IRVertex.Rn.

In my opition the Ern should be an array just like the original C++ RVertex.

I would like to wish this would be fixed in the near future.

Thanks in advance.

Hi Tomasz,

This is something that needs to be manually specified for the translator. I will try and straighten it out for the next build.

Marsel Khadiyev (Software Developer, EPHERE Inc.)

Hello Marsel,

I am glad to hear that.

Many thanks for help on this.

 

access the normals of a vertex over the rnormal is somewhat buggd inside max. there is a different appraoch mentioned inside the maxsdk help. basicly its a simple help utility that loops through all faces, build their facenormal and checks with the smoothing group. if the smoothing groups are different between faces it will generate a new normal verctor for the vertex,

here is a code snipped

this is the vertex normal class to handle the normals

public class VNormal
    {
        private Vector3D norm;
        private UInt32 smooth;
        private VNormal next;
        private bool init;

        public VNormal()
        {
            this.smooth = 0;
            this.next = null;
            this.init = false;
            this.norm = new Vector3D();
        }

        public VNormal(ref Vector3D n, UInt32 s)
        {
            this.next = null;
            this.init = true;
            this.norm = n;
            this.smooth = s;
        }

        public void AddNormal(ref Vector3D n, UInt32 s)
        {
            if ((s & this.smooth) == 0 && this.init)
            {
                if (this.next != null)
                {
                    this.next.AddNormal(ref n, s);
                }
                else
                {
                    this.next = new VNormal(ref n, s);
                }
            }
            else
            {
                this.norm += n;
                this.smooth |= s;
                this.init = true;
            }
        }

        public Vector3D GetNormal(UInt32 s)
        {
            if ((this.smooth & s) != 0 || this.next == null)
            {
                this.norm.Normalize();
                return this.norm;
            }
            else
            {
                return this.next.GetNormal(s);
            }
        }

        public void Normalize()
        {
            VNormal ptr = this.next;
            VNormal prev = this;

            while (ptr != null)
            {
                if ((ptr.smooth & this.smooth) != 0)
                {
                    this.norm += ptr.norm;
                    prev.next = ptr.next;
                    ptr.next = null;
                    ptr = prev.next;
                }
                else
                {
                    prev = ptr;
                    ptr = ptr.next;
                }
            }

            this.norm.Normalize();

            if (this.next != null)
            {
                this.next.Normalize();
            }
        }
    }

this function generates a list<vnormal> from a trimesh

public static List<VNormal> ComputeVertexNormals(IMesh imMesh)
        {
            IList<IFace> FaceList = imMesh.Faces;
            List<Vector3D> VertListVec3D = new List<Vector3D>();

            List<Vector3D> fnorms = new List<Vector3D>(new Vector3D[imMesh.NumFaces_]);
            List<VNormal> vnorms = new List<VNormal>(new VNormal[imMesh.NumVerts_]);

            // Compute face and vertex surface normals
            for (int i = 0; i < imMesh.NumVerts_; i++)
            {
                VertListVec3D.Add(ConvertVec3D(imMesh.GetVert(i)));
                vnorms[i] = new VNormal();
            }

            for (int i = 0; i < imMesh.NumFaces_; i++)
            {
                // Calculate the surface normal                
                Vector3D CurrentFaceNormal = GetFaceNormal(FaceList[i], VertListVec3D);

                for (int j = 0; j < 3; j++)
                {
                    vnorms[(int)FaceList[i].V[j]].AddNormal(ref CurrentFaceNormal, FaceList[i].SmGroup_);
                }

                CurrentFaceNormal.Normalize();
                fnorms[i] = CurrentFaceNormal;
            }

            for (int i = 0; i < imMesh.NumVerts_; i++)
            {
                vnorms[i].Normalize();
            }

            return vnorms;
        }

and here we generate the vnromals and access them

List<VNormal> lstVNormals = VectorHelper.ComputeVertexNormals(m_MaxTriMesh);

if (efCurrentFace.SmGroup != 0) // if no smooting group generate vnromals via facenormal
 {
      Vector3D VNormal_V0 = lstVNormals[(int)efCurrentFace.V0].GetNormal(efCurrentFace.SmGroup);
      Vector3D VNormal_V1 = lstVNormals[(int)efCurrentFace.V1].GetNormal(efCurrentFace.SmGroup);
      Vector3D VNormal_V2 = lstVNormals[(int)efCurrentFace.V2].GetNormal(efCurrentFace.SmGroup);
 }
 else
 {
       Vector3D FaceNormal = VectorHelper.GetFaceNormal(efCurrentFace, lstVertices);

        Vector3D VNormal_V0 = FaceNormal;
        Vector3D VNormal_V1 = FaceNormal;
         Vector3D VNormal_V2 = FaceNormal;

           bFoundNoSmoothing = true;
 }

don't use the ipoint3 for fir direct use. if you make crossproduct, add, multiply operations with them you get wrong results. when i read the vert data i convert them directly to Vector3D and work with this instead of ipoint3. but you can convert them back very easily. basicly they are the same but you can do math operations directly with them.


Mario Röske
Technical Artist
Piranha-Bytes