Some Problems with BitmapTex and retrieving normals from models

 
 
 
Posted by:thiago.pastor
Data created:18 January 2011

hi all,

How to convert between the ITexmap and IBitmapTex ?

i tried the normal way using (IBitmapTex) texmap but get a null pointer

the only way it worked was doing 

IBitmapTex bitmap = map.RefTarget as IBitmapTex;

but, i dont know if this is the right way

More one thing about this;

iam using 

int axis = map.TheUVGen.Axis;

and iam getting the result 0 in the axis (and i should get 1 for my model -- i looked at the texture coords values, and they are in the X and Z components, so i should get 1 there ), 

in the original API i can compare the result (axis) with those constants below

//#define AXIS_UV 0 01

                            //#define AXIS_VW 1 12
                            //#define AXIS_WU 2 20

 

#define AXIS_UV 0

#define AXIS_VW 1 

#define AXIS_WU 2

 

but in Max.net i cant acess those (was it converted to a Enum ? Or  i need to look at the original apis for the correct value) -- the defines was converted to .net ?

-----

I need to get the normals of a model, and im using 

 

IRVertex vertx = mesh.GetRVert(i);

                IPoint3 vert = vertx.Rn.Normal;

 

 

or 

mesh.GetNormal(i)

but in some cases i am getting a strange IPoint3 vert

in some cases doing vert.x throw exception  (the property x in not constructed)

the way i found to make it work was using a mesh.BuildNormals before all, after that everything works normally.

I need to call this function ? did im changing the model ? Is there a better way ?

Thanks in advance ? 

Max.Net is really helping me !!! ;)

 

 

 

 

More one thing, sometimes i need to check some flags values, I need to put the Hexa values by hand in the comparation or is there some Enums or Defines to help.

Thanks

 

Hello,

How to convert between the ITexmap and IBitmapTex ?

A simple cast, as you have shown, or even something like var bitmapTex = (IBitmapTex)map; should work. BitmapTex derives from Texmap and therefore will upcast from it if you have the correct object.

I haven't tried much else of what you described, however, I would look up the values of the defines from Max SDK docs and try to use those. There is a chance that the enums in max.net are wrong (I did most of them by hand).

Marsel Khadiyev (Software Developer, EPHERE Inc.)

other thing.

some models has more than one normal per vertex, and i need to access them

in the original API, i would use

 

IRVertex vertx = mesh.GetRVert((int)i0);
                IPoint3 vert = vertx.Rn.Normal;

IRVertex vertx = mesh.GetRVert((int)i0);

IPoint3 vert = vertx.Ern[i].Normal;

but in max.net vertx.Ern[i] is NOT an array, i just can access ONE normal. Is this correct ? how can access the others ?

 

 

I'll need to specify that as being an array for the converter. Will try to do that for next build.

Marsel Khadiyev (Software Developer, EPHERE Inc.)

To get the Vertex Normals you have to work throu all faces and their smoothing groups. i created a exporter with max.net where i used an example from the c++ 3ds exporter to create those vertex normals.

here are some code snippets to get you the right track ^^

You will notice that i use Vector3D instead of working with ipoint3 from the wrapper. this as one main reason. mathematical operation are not working correctly with ipoint3. Only Vector3D is creating the correct result.

Vector4 is a class that holds 4 float values.

public class VNormal // used for generating and holding the vertex normal arrays
    {
        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();
            }
        }
    }

public List<VNormal> ComputeVertexNormals(IMesh imMesh) // computes the vertex normals
        {
            IList<IFace> FaceList = imMesh.Faces;
            IList<IPoint3> VertList = imMesh.Verts;

            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++)
            {
                vnorms[i] = new VNormal();
            }

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

                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;
        }

public MeshData GenerateMeshStream(EntityNode EntityNodeArg)
        {
            List<Vector4> lstMeshVertPositions = new List<Vector4>();
            List<Vector4> lstMeshVertNormals = new List<Vector4>();
            List<Vector4> lstMeshVertUV1 = new List<Vector4>();
            List<Vector4> lstMeshVertUV2 = new List<Vector4>();
            List<uint> lstMeshVertMatID = new List<uint>();

            IMatrix3 WorldParentTM = EntityNodeArg.iinNode.GetParentTM(0);
            WorldParentTM.Invert();

            IMatrix3 WorldObjectTM = EntityNodeArg.GetObjectTMAfterWSM();
            IMatrix3 LocalTM = WorldObjectTM.Multiply(WorldParentTM);

            bool bFoundNoSmoothing = false;

            if (EntityNodeArg.ExportedMaxTriMesh != null) // this is a triangle base mesh, we dont work with the poly version.
            {
                bool bIsNegScaled = EntityNodeArg.TMNegParity();

                IList<IPoint3> lstVertices = EntityNodeArg.ExportedMaxTriMesh.Verts;
                IList<IFace> lstFaces = EntityNodeArg.ExportedMaxTriMesh.Faces;


                List<VNormal> lstVNormals = this.ComputeVertexNormals(EntityNodeArg.ExportedMaxTriMesh);

                for (int i = 0; i < EntityNodeArg.ExportedMaxTriMesh.NumFaces_; i++)
                {
                    ExtMeshFace efCurrentFace = new ExtMeshFace(lstFaces[i], bIsNegScaled);

                    List<Vector4> CurrentVertPositions = new List<Vector4>();
                    CurrentVertPositions.Add(VectorHelper.ConvVec4(lstVertices[(int)efCurrentFace.V0]));
                    CurrentVertPositions.Add(VectorHelper.ConvVec4(lstVertices[(int)efCurrentFace.V1]));
                    CurrentVertPositions.Add(VectorHelper.ConvVec4(lstVertices[(int)efCurrentFace.V2]));
                    lstMeshVertPositions.AddRange(CurrentVertPositions);

                    List<Vector4> CurrentVertNormals = new List<Vector4>();
                    if (efCurrentFace.SmGroup != 0)
                    {
                        CurrentVertNormals.Add(VectorHelper.ConvVec4(lstVNormals[(int)efCurrentFace.V0].GetNormal(efCurrentFace.SmGroup)));
                        CurrentVertNormals.Add(VectorHelper.ConvVec4(lstVNormals[(int)efCurrentFace.V1].GetNormal(efCurrentFace.SmGroup)));
                        CurrentVertNormals.Add(VectorHelper.ConvVec4(lstVNormals[(int)efCurrentFace.V2].GetNormal(efCurrentFace.SmGroup)));
                    }
                    else
                    {
                        Vector3D FaceNormal = VectorHelper.GetFaceNormal(lstVertices[(int)efCurrentFace.V0], lstVertices[(int)efCurrentFace.V1], lstVertices[(int)efCurrentFace.V2]);
                        CurrentVertNormals.Add(VectorHelper.ConvVec4(FaceNormal));
                        CurrentVertNormals.Add(VectorHelper.ConvVec4(FaceNormal));
                        CurrentVertNormals.Add(VectorHelper.ConvVec4(FaceNormal));

                        bFoundNoSmoothing = true;
                    }


                    lstMeshVertNormals.AddRange(CurrentVertNormals);

                    uint MatID = (uint)lstFaces[i].MatID;
                    lstMeshVertMatID.Add(MatID);
                    lstMeshVertMatID.Add(MatID);
                    lstMeshVertMatID.Add(MatID);

             }
        }

 

hope this is helping with handling vertex normals

 


Mario Röske
Technical Artist
Piranha-Bytes