protected unsafe TriMeshFacesAndPositions GetTriMeshFacesAndPositions(IMesh mesh) { VertexChannel channel = new VertexChannel(); channel.m_type = VertexChannelType.Positions; channel.m_vertices = new Point3[mesh.NumVerts]; fixed (Point3* vertexData = channel.m_vertices) { CopyMemory((IntPtr)vertexData, mesh.GetVertPtr(0).Handle, (uint)(sizeof(Point3) * mesh.NumVerts)); } var faces = new Face[mesh.NumFaces]; fixed (Face* faceData = faces) { CopyMemory((IntPtr)faceData, mesh.Faces[0].Handle, (uint)(sizeof(Face) * mesh.NumFaces)); } /* Split the face data into seperate arrays. Put the face indices in one with the channel, the others to one side to filter into groups later if the user wants */ TriMeshFacesAndPositions faces_data = new TriMeshFacesAndPositions(); faces_data.face_flags = new short[faces.Length]; faces_data.face_materialIds = new short[faces.Length]; channel.m_faces = new Indices3[faces.Length]; for (int i = 0; i < faces.Length; i++) { short materialid = (short)((faces[i].flags & 0xFFFF0000) >> 16); //in Max the high word of the flags member contains the material id. short flags = (short)(faces[i].flags & 0x0000FFFF); faces_data.face_flags[i] = flags; faces_data.face_materialIds[i] = materialid; channel.m_faces[i] = faces[i].v; } faces_data.positions_channel = channel; return faces_data; }
protected unsafe VertexChannel GetTriMeshNormals(IMesh mesh) { VertexChannel channel = new VertexChannel(); channel.m_type = VertexChannelType.Normals; /* The MeshNormalSpec class is intended to store user specified normals. We can use it however to have max calculate the * normals in the typical way and provide easy access to them. */ IMeshNormalSpec normalspec = mesh.SpecifiedNormals; bool normalsAlreadySpecified = (normalspec.NormalArray != null); if (!normalsAlreadySpecified) { mesh.SpecifyNormals(); } normalspec.CheckNormals(); channel.m_vertices = new Point3[normalspec.NumNormals]; fixed (Point3* normalData = channel.m_vertices) { CopyMemory((IntPtr)normalData, normalspec.NormalArray.Handle, (uint)(sizeof(Point3) * normalspec.NumNormals)); } int numnormalfaces = normalspec.NumFaces; channel.m_faces = new Indices3[numnormalfaces]; for (int i = 0; i < numnormalfaces; i++) { IMeshNormalFace f = normalspec.Face(i); channel.m_faces[i] = *(Indices3*)f.NormalIDArray; } if (!normalsAlreadySpecified) { mesh.ClearSpecifiedNormals(); } return channel; }
protected FaceTripletGroup CreateFaceTripletGroup(FaceGroup faces, VertexChannel p, VertexChannel n, VertexChannel t, VertexChannel y) { List<Triplet> triplets = new List<Triplet>(); var fp = p.m_faces; var fn = n.m_faces; var ft = t.m_faces; var fy = y.m_faces; if (ChangeCoordinateSystem) { foreach (var i in faces.m_faceIndices) { triplets.Add(new Triplet { v = fp[i].i3, n = fn[i].i3, t = ft[i].i3, y = fy[i].i3 }); triplets.Add(new Triplet { v = fp[i].i2, n = fn[i].i2, t = ft[i].i2, y = fy[i].i2 }); triplets.Add(new Triplet { v = fp[i].i1, n = fn[i].i1, t = ft[i].i1, y = fy[i].i1 }); } } else { /* If the coordinate system has changed, swap the winding order */ foreach (var i in faces.m_faceIndices) { triplets.Add(new Triplet { v = fp[i].i1, n = fn[i].i1, t = ft[i].i1, y = fy[i].i1 }); triplets.Add(new Triplet { v = fp[i].i2, n = fn[i].i2, t = ft[i].i2, y = fy[i].i2 }); triplets.Add(new Triplet { v = fp[i].i3, n = fn[i].i3, t = ft[i].i3, y = fy[i].i3 }); } } return new FaceTripletGroup { MaterialId = faces.m_materialId, Triplets = triplets.ToArray() }; }
protected unsafe IEnumerable<VertexChannel> GetTriMeshMapChannels(IMesh mesh) { /* 3ds Max SDK Programmer's Guide > 3ds Max SDK Features > Rendering > Textures Maps > Mapping Channels */ /* There are up to 99 user maps in each mesh: * -2 Alpha * -1 Illum * 0 vertex colour * 1 default texcoords * 1 - 99 user uvw maps * Maps can be inspected for a mesh using the Edit > Channel Info... dialog in max. * When maps are added using the modifier stack they are always sequential. I.e. if you add just one uvw unwrap, and set it to map 5, four other preceeding channels will be created. */ List<VertexChannel> channels = new List<VertexChannel>(); //no unsafe code in iterators /* The two hidden maps are not counted in the getNumMaps() return value */ for (int i = 0; i < mesh.NumMaps; i++) { var map = mesh.Map(i); if (map.IsUsed) { VertexChannel channel = new VertexChannel(); channel.m_vertices = new Point3[map.Vnum]; fixed (Point3* dataptr = channel.m_vertices) { CopyMemory((IntPtr)dataptr, map.Tv.Handle, (uint)(sizeof(Point3) * map.Vnum)); } // channel.m_faces = new TVFace[map.Fnum]; //the indices3 struct is identical to the tvface struct but they are different in the sdk. for efficiency we just indices3 directly here. channel.m_faces = new Indices3[map.Fnum]; fixed (Indices3* dataptr = channel.m_faces) { CopyMemory((IntPtr)dataptr, map.Tf.Handle, (uint)(sizeof(Indices3) * map.Fnum)); } channel.m_type = (VertexChannelType)i; channels.Add(channel); } } return channels; }
protected IEnumerable<FaceTripletGroup> CreateFaceTripletGroups(IEnumerable<FaceGroup> facegroups, VertexChannel fp, VertexChannel fn, VertexChannel tn, VertexChannel yn) { foreach (var fg in facegroups) { yield return CreateFaceTripletGroup(fg, fp, fn, tn, yn); } }