/// <summary> /// Collects all the vertiex and index information for the model /// </summary> public void ExtractVertexData() { // only needed once per frame, at most if (AllData != null) return; AllData = new MeshPartData[mModel.Meshes.Count]; for (int i = 0; i < mModel.Meshes.Count; i++) AllData[i] = new MeshPartData(mModel.Meshes[i]); }
public override NodeContent Import(string filename, ContentImporterContext context) { JsonSerializer jsonSerializer = new JsonSerializer(); JsonReader jsonReader = new JsonTextReader(new StreamReader(filename)); jsonSerializer.MissingMemberHandling = MissingMemberHandling.Ignore; jsonSerializer.NullValueHandling = NullValueHandling.Ignore; jsonSerializer.Converters.Add(new G3DTypeConverter()); // Deserialize the G3D file into our own data model ModelData jsonModelData = jsonSerializer.Deserialize <ModelData>(jsonReader); // We'll keep references to generated geometry to reference them later when // reading nodes and bones. Dictionary <string, MeshPartData> meshPartDataCollection = new Dictionary <string, MeshPartData>(); Dictionary <string, MaterialContent> materialContentCollection = new Dictionary <string, MaterialContent>(); Dictionary <string, MeshContent> meshContentCollection = new Dictionary <string, MeshContent>(); // Root of the model string rootContentName = FilenameToName(filename); ContentIdentity rootContentIdentity = new ContentIdentity(filename, GetType().Name); NodeContent rootContent = new NodeContent { Identity = rootContentIdentity, Name = rootContentName, Transform = Matrix.Identity }; // Loop through materials to import them foreach (MaterialData materialData in jsonModelData.materials) { //SkinnedMaterialContent materialContent = new SkinnedMaterialContent() BasicMaterialContent materialContent = new BasicMaterialContent() { Name = materialData.id, Identity = rootContentIdentity, Alpha = materialData.opacity, SpecularPower = materialData.shininess, DiffuseColor = materialData.diffuse, EmissiveColor = materialData.emissive, SpecularColor = materialData.specular, }; if (materialData.textures != null) { foreach (TextureData textureData in materialData.textures) { ExternalReference <TextureContent> textureExternalReference = new ExternalReference <TextureContent>(textureData.fileName, rootContentIdentity); materialContent.Textures.Add(textureData.id, textureExternalReference); } } materialContentCollection[materialData.id] = materialContent; } // Read mesh data int meshIndex = 0; foreach (MeshData meshData in jsonModelData.meshes) { meshData.id = "mesh_" + (meshIndex++); MeshContent meshContent = new MeshContent() { Name = meshData.id }; rootContent.Children.Add(meshContent); meshContentCollection.Add(meshData.id, meshContent); // Store the offset for every vertex channel contained in the mesh int vertexSize = 0; int positionOffset = 0; // Cache the offset of the POSITION attribute as it will be used right next foreach (VertexAttribute attr in meshData.attributes) { attr.offset = vertexSize; if (attr.usage == VertexAttribute.POSITION) { positionOffset = vertexSize; } vertexSize += attr.numComponents; } // Store final vertex size (the amount of floats in the vertex array that correspond to // a single vertex with all it's attributes) meshData.vertexSize = vertexSize; // Adds vertex positions to mesh for (int i = 0; i < meshData.vertices.Length; i += vertexSize) { meshContent.Positions.Add(new Vector3(meshData.vertices[i + positionOffset] , meshData.vertices[i + positionOffset + 1] , meshData.vertices[i + positionOffset + 2])); } // Keep a reference to all this mesh'es parts to later attach to materials foreach (MeshPartData part in meshData.parts) { part.parent = meshData; meshPartDataCollection.Add(part.id, part); } } // Loop through nodes to associate geometry with material foreach (NodeData nodeData in jsonModelData.nodes) { if (nodeData.parts != null && nodeData.parts.Length > 0) { foreach (NodePartData nodePartData in nodeData.parts) { MaterialContent equivalentMaterial = materialContentCollection[nodePartData.materialId]; MeshPartData equivalentMeshPart = meshPartDataCollection[nodePartData.meshPartId]; MeshContent equivalentMeshContent = meshContentCollection[equivalentMeshPart.parent.id]; // Build geometry data (collection of primitives) for that mesh part // We only support triangles, other OpenGL types include triangle strips // or triangle fans, we skip those types. if (!"TRIANGLES".Equals(equivalentMeshPart.type)) { continue; } // Here we create our mesh part (called GeometryContent in XNA) // and save it for later in a named dictionary, since attatching // this mesh part's material comes at a later stage GeometryContent geometryContent = new GeometryContent { Name = equivalentMeshPart.id, Material = equivalentMaterial }; equivalentMeshContent.Geometry.Add(geometryContent); // Adds position indices to this geometry and form our triangles vertexIndices.Clear(); foreach (int vertexIndex in equivalentMeshPart.indices) { // If it's the first time we're adding this index, add it // to the Vertices list. if (!geometryContent.Indices.Contains(vertexIndex)) { geometryContent.Vertices.Add(vertexIndex); vertexIndices.Add(vertexIndex); } // Here we are composing triangles, each three indicies form a triangle. geometryContent.Indices.Add(vertexIndex); } // Adds vertex channels to this geometry content foreach (VertexAttribute attr in equivalentMeshPart.parent.attributes) { switch (attr.usage) { case VertexAttribute.NORMAL: case VertexAttribute.BINORMAL: case VertexAttribute.TANGENT: case VertexAttribute.COLOR: { Vector3[] vertexChannelData = AsVector3(vertexIndices, equivalentMeshPart.parent.vertices, equivalentMeshPart.parent.vertexSize, attr.offset); geometryContent.Vertices.Channels.Add(VertexAttribute.GetXNAName(attr), vertexChannelData); } break; case VertexAttribute.BONE_WEIGHT: //{ // Vector2[] vertexChannelData = AsVector2(vertexIndices, equivalentMeshPart.parent.vertices, equivalentMeshPart.parent.vertexSize, attr.offset); // geometryContent.Vertices.Channels.Add(VertexAttribute.GetXNAName(attr), vertexChannelData); //} break; case VertexAttribute.TEX_COORD: { Vector2[] vertexChannelData = AsVector2(vertexIndices, equivalentMeshPart.parent.vertices, equivalentMeshPart.parent.vertexSize, attr.offset); geometryContent.Vertices.Channels.Add(VertexAttribute.GetXNAName(attr), vertexChannelData); } break; } } } } } return(rootContent); }