/// <summary> /// Cargar estructura de esqueleto /// </summary> private TgcSkeletalBone[] loadSkeleton(TgcSkeletalMeshData meshData) { //Crear huesos TgcSkeletalBone[] bones = new TgcSkeletalBone[meshData.bones.Length]; for (int i = 0; i < bones.Length; i++) { TgcSkeletalBoneData boneData = meshData.bones[i]; TgcSkeletalBone bone = new TgcSkeletalBone(i, boneData.name, new Vector3(boneData.startPosition[0], boneData.startPosition[1], boneData.startPosition[2]), new Quaternion(boneData.startRotation[0], boneData.startRotation[1], boneData.startRotation[2], boneData.startRotation[3]) ); bones[i] = bone; } //Cargar padres en huesos for (int i = 0; i < bones.Length; i++) { TgcSkeletalBoneData boneData = meshData.bones[i]; if (boneData.parentId == -1) { bones[i].ParentBone = null; } else { bones[i].ParentBone = bones[boneData.parentId]; } } return(bones); }
/// <summary> /// Carga un modelo a partir del string del XML /// </summary> /// <param name="xmlString">contenido del XML</param> /// <param name="mediaPath">Path a partir del cual hay que buscar las Texturas</param> /// <returns>Modelo cargado</returns> public TgcSkeletalMesh loadMeshFromString(string xmlString, string mediaPath) { TgcSkeletalParser parser = new TgcSkeletalParser(); TgcSkeletalMeshData meshData = parser.parseMeshFromString(xmlString); return(loadMesh(meshData, mediaPath)); }
/// <summary> /// Crea un mesh sin texturas, solo con VertexColors /// </summary> /// <param name="meshData"></param> private TgcSkeletalMesh crearMeshSoloColor(TgcSkeletalMeshData meshData) { //Crear Mesh Mesh mesh = new Mesh(meshData.coordinatesIndices.Length / 3, meshData.coordinatesIndices.Length, MeshFlags.Managed, VertexColorVertexElements, device); //Cargar VertexBuffer using (VertexBuffer vb = mesh.VertexBuffer) { GraphicsStream data = vb.Lock(0, 0, LockFlags.None); for (int j = 0; j < meshData.coordinatesIndices.Length; j++) { VertexColorVertex v = new VertexColorVertex(); //vertices int coordIdx = meshData.coordinatesIndices[j] * 3; v.Position = new Vector3( meshData.verticesCoordinates[coordIdx], meshData.verticesCoordinates[coordIdx + 1], meshData.verticesCoordinates[coordIdx + 2] ); //color int colorIdx = meshData.colorIndices[j]; v.Color = meshData.verticesColors[colorIdx]; data.Write(v); } vb.Unlock(); } //Cargar indexBuffer en forma plana using (IndexBuffer ib = mesh.IndexBuffer) { short[] indices = new short[meshData.coordinatesIndices.Length]; for (int i = 0; i < indices.Length; i++) { indices[i] = (short)i; } ib.SetData(indices, 0, LockFlags.None); } //Cargar esqueleto TgcSkeletalBone[] bones = loadSkeleton(meshData); TgcSkeletalVertexWeight[] verticesWeights = loadVerticesWeights(meshData, bones); //Cargar datos de meshData que interesan mantener como originales TgcSkeletalMesh.OriginalData origData = new TgcSkeletalMesh.OriginalData(); origData.coordinatesIndices = meshData.coordinatesIndices; origData.verticesCoordinates = meshData.verticesCoordinates; origData.colorIndices = meshData.colorIndices; origData.verticesColors = meshData.verticesColors; origData.texCoordinatesIndices = null; origData.textureCoordinates = null; //Crear mesh de TGC TgcSkeletalMesh tgcMesh = meshFactory.createNewMesh(mesh, meshData.name, TgcSkeletalMesh.MeshRenderType.VERTEX_COLOR, origData, bones, verticesWeights); return(tgcMesh); }
/// <summary> /// Cargar Weights de vertices /// </summary> /// <param name="meshData"></param> /// <returns></returns> private TgcSkeletalVertexWeight[] loadVerticesWeights(TgcSkeletalMeshData meshData, TgcSkeletalBone[] bones) { //Crear un array de Weights para cada uno de los vertices de la malla TgcSkeletalVertexWeight[] weights = new TgcSkeletalVertexWeight[meshData.verticesCoordinates.Length / 3]; float[] vertexWeightTotals = new float[weights.Length]; for (int i = 0; i < weights.Length; i++) { weights[i] = new TgcSkeletalVertexWeight(); vertexWeightTotals[i] = 0; } //Cargar los weights de cada vertice int weightsCount = meshData.verticesWeights.Length / 3; for (int i = 0; i < weightsCount; i++) { int vertexIdx = (int)meshData.verticesWeights[i * 3]; int boneIdx = (int)meshData.verticesWeights[i * 3 + 1]; float weightVal = meshData.verticesWeights[i * 3 + 2]; TgcSkeletalBone bone = bones[boneIdx]; TgcSkeletalVertexWeight.BoneWeight weight = new TgcSkeletalVertexWeight.BoneWeight(bone, weightVal); weights[vertexIdx].Weights.Add(weight); //acumular total de weight para ese vertice, para luego poder normalizar vertexWeightTotals[vertexIdx] += weightVal; } //Normalizar weights de cada vertice for (int i = 0; i < weights.Length; i++) { TgcSkeletalVertexWeight vertexWeight = weights[i]; float vTotal = vertexWeightTotals[i]; //Normalizar cada valor segun el total acumulado en el vertice foreach (TgcSkeletalVertexWeight.BoneWeight w in vertexWeight.Weights) { w.Weight = w.Weight / vTotal; } } return(weights); }
/// <summary> /// Crea un mesh con uno o varios DiffuseMap /// </summary> /// <returns></returns> private TgcSkeletalMesh crearMeshDiffuseMap(TgcSkeletalLoaderMaterialAux[] materialsArray, TgcSkeletalMeshData meshData) { //Crear Mesh Mesh mesh = new Mesh(meshData.coordinatesIndices.Length / 3, meshData.coordinatesIndices.Length, MeshFlags.Managed, DiffuseMapVertexElements, device); //Cargar esqueleto TgcSkeletalBone[] bones = loadSkeleton(meshData); TgcSkeletalVertexWeight[] verticesWeights = loadVerticesWeights(meshData, bones); //Cargar VertexBuffer using (VertexBuffer vb = mesh.VertexBuffer) { GraphicsStream data = vb.Lock(0, 0, LockFlags.None); for (int j = 0; j < meshData.coordinatesIndices.Length; j++) { DiffuseMapVertex v = new DiffuseMapVertex(); //vertices int coordIdx = meshData.coordinatesIndices[j] * 3; v.Position = new Vector3( meshData.verticesCoordinates[coordIdx], meshData.verticesCoordinates[coordIdx + 1], meshData.verticesCoordinates[coordIdx + 2] ); //texture coordinates diffuseMap int texCoordIdx = meshData.texCoordinatesIndices[j] * 2; v.Tu = meshData.textureCoordinates[texCoordIdx]; v.Tv = meshData.textureCoordinates[texCoordIdx + 1]; //color int colorIdx = meshData.colorIndices[j]; v.Color = meshData.verticesColors[colorIdx]; //normal if (meshData.verticesNormals != null) { v.Normal = new Vector3( meshData.verticesNormals[coordIdx], meshData.verticesNormals[coordIdx + 1], meshData.verticesNormals[coordIdx + 2] ); } else { v.Normal = new Vector3(0, 0, 0); } //tangent if (meshData.verticesTangents != null) { v.Tangent = new Vector3( meshData.verticesTangents[coordIdx], meshData.verticesTangents[coordIdx + 1], meshData.verticesTangents[coordIdx + 2] ); } else { v.Tangent = new Vector3(0, 0, 0); } //binormal if (meshData.verticesBinormals != null) { v.Binormal = new Vector3( meshData.verticesBinormals[coordIdx], meshData.verticesBinormals[coordIdx + 1], meshData.verticesBinormals[coordIdx + 2] ); } else { v.Binormal = new Vector3(0, 0, 0); } //BlendWeights y BlendIndices TgcSkeletalVertexWeight vWeight = verticesWeights[meshData.coordinatesIndices[j]]; vWeight.createVector4WeightsAndIndices(out v.BlendWeights, out v.BlendIndices); data.Write(v); } vb.Unlock(); } //Cargar IndexBuffer en forma plana using (IndexBuffer ib = mesh.IndexBuffer) { short[] indices = new short[meshData.coordinatesIndices.Length]; for (int j = 0; j < indices.Length; j++) { indices[j] = (short)j; } ib.SetData(indices, 0, LockFlags.None); } //Configurar Material y Textura para un solo SubSet TgcSkeletalLoaderMaterialAux matAux = materialsArray[meshData.materialId]; Material[] meshMaterials; TgcTexture[] meshTextures; if (matAux.subMaterials == null) { meshMaterials = new Material[] { matAux.materialId }; meshTextures = new TgcTexture[] { matAux.texture }; } //Configurar Material y Textura para varios SubSet else { //Cargar attributeBuffer con los id de las texturas de cada triángulo int[] attributeBuffer = mesh.LockAttributeBufferArray(LockFlags.None); Array.Copy(meshData.materialsIds, attributeBuffer, attributeBuffer.Length); mesh.UnlockAttributeBuffer(attributeBuffer); //Cargar array de Materials y Texturas meshMaterials = new Material[matAux.subMaterials.Length]; meshTextures = new TgcTexture[matAux.subMaterials.Length]; for (int m = 0; m < matAux.subMaterials.Length; m++) { meshMaterials[m] = matAux.subMaterials[m].materialId; meshTextures[m] = matAux.subMaterials[m].texture; } } //Crear mesh de TGC TgcSkeletalMesh tgcMesh = meshFactory.createNewMesh(mesh, meshData.name, TgcSkeletalMesh.MeshRenderType.DIFFUSE_MAP, bones); tgcMesh.Materials = meshMaterials; tgcMesh.DiffuseMaps = meshTextures; return tgcMesh; }
/// <summary> /// Cargar Weights de vertices /// </summary> /// <param name="meshData"></param> /// <returns></returns> private TgcSkeletalVertexWeight[] loadVerticesWeights(TgcSkeletalMeshData meshData, TgcSkeletalBone[] bones) { int maxWeights = 4; TgcSkeletalVertexWeight.BoneWeight.GreaterComparer weightComparer = new TgcSkeletalVertexWeight.BoneWeight.GreaterComparer(); //Crear un array de Weights para cada uno de los vertices de la malla TgcSkeletalVertexWeight[] weights = new TgcSkeletalVertexWeight[meshData.verticesCoordinates.Length / 3]; for (int i = 0; i < weights.Length; i++) { weights[i] = new TgcSkeletalVertexWeight(); } //Cargar los weights de cada vertice int weightsCount = meshData.verticesWeights.Length / 3; for (int i = 0; i < weightsCount; i++) { int vertexIdx = (int)meshData.verticesWeights[i * 3]; int boneIdx = (int)meshData.verticesWeights[i * 3 + 1]; float weightVal = meshData.verticesWeights[i * 3 + 2]; TgcSkeletalBone bone = bones[boneIdx]; TgcSkeletalVertexWeight.BoneWeight weight = new TgcSkeletalVertexWeight.BoneWeight(bone, weightVal); weights[vertexIdx].Weights.Add(weight); } //Normalizar weights de cada vertice for (int i = 0; i < weights.Length; i++) { TgcSkeletalVertexWeight vertexWeight = weights[i]; //Se soportan hasta 4 weights por vertice. Si hay mas se quitan y se reparten las influencias entre el resto de los huesos if (vertexWeight.Weights.Count > maxWeights) { //Ordenar por weight de menor a mayor y luego revertir, para que quede de mayor a menor peso vertexWeight.Weights.Sort(weightComparer); vertexWeight.Weights.Reverse(); //Quitar los ultimos los weight que superan 4 while (vertexWeight.Weights.Count > maxWeights) { vertexWeight.Weights.RemoveAt(vertexWeight.Weights.Count - 1); } } //Sumar el total de todos los weights de este vertice float weightTotal = 0; foreach (TgcSkeletalVertexWeight.BoneWeight w in vertexWeight.Weights) { weightTotal += w.Weight; } //Normalizar cada valor segun el total acumulado en el vertice foreach (TgcSkeletalVertexWeight.BoneWeight w in vertexWeight.Weights) { w.Weight = w.Weight / weightTotal; } } return weights; }
/// <summary> /// Cargar estructura de esqueleto /// </summary> private TgcSkeletalBone[] loadSkeleton(TgcSkeletalMeshData meshData) { //Crear huesos TgcSkeletalBone[] bones = new TgcSkeletalBone[meshData.bones.Length]; for (int i = 0; i < bones.Length; i++) { TgcSkeletalBoneData boneData = meshData.bones[i]; TgcSkeletalBone bone = new TgcSkeletalBone(i, boneData.name, new Vector3(boneData.startPosition[0], boneData.startPosition[1], boneData.startPosition[2]), new Quaternion(boneData.startRotation[0], boneData.startRotation[1], boneData.startRotation[2], boneData.startRotation[3]) ); bones[i] = bone; } //Cargar padres en huesos for (int i = 0; i < bones.Length; i++) { TgcSkeletalBoneData boneData = meshData.bones[i]; if (boneData.parentId == -1) { bones[i].ParentBone = null; } else { bones[i].ParentBone = bones[boneData.parentId]; } } return bones; }
/// <summary> /// Carga un Modelo a partir de un objeto TgcSkeletalMeshData ya parseado /// </summary> /// <param name="meshData">Objeto con datos ya parseados</param> /// <param name="mediaPath">Path a partir del cual hay que buscar las Texturas</param> /// <returns>Modelo cargado</returns> public TgcSkeletalMesh loadMesh(TgcSkeletalMeshData meshData, string mediaPath) { //Cargar Texturas TgcSkeletalLoaderMaterialAux[] materialsArray = new TgcSkeletalLoaderMaterialAux[meshData.materialsData.Length]; for (int i = 0; i < meshData.materialsData.Length; i++) { TgcMaterialData materialData = meshData.materialsData[i]; string texturesPath = mediaPath + meshData.texturesDir + "\\"; //Crear StandardMaterial if (materialData.type.Equals(TgcMaterialData.StandardMaterial)) { materialsArray[i] = createTextureAndMaterial(materialData, texturesPath); } //Crear MultiMaterial else if (materialData.type.Equals(TgcMaterialData.MultiMaterial)) { TgcSkeletalLoaderMaterialAux matAux = new TgcSkeletalLoaderMaterialAux(); materialsArray[i] = matAux; matAux.subMaterials = new TgcSkeletalLoaderMaterialAux[materialData.subMaterials.Length]; for (int j = 0; j < materialData.subMaterials.Length; j++) { matAux.subMaterials[j] = createTextureAndMaterial(materialData.subMaterials[j], texturesPath); } } } //Crear Mesh TgcSkeletalMesh tgcMesh = null; //Crear mesh que no tiene Material, con un color simple if (meshData.materialId == -1) { tgcMesh = crearMeshSoloColor(meshData); } //Crear mesh con DiffuseMap else { tgcMesh = crearMeshDiffuseMap(materialsArray, meshData); } //Crear BoundingBox, aprovechar lo que viene del XML o crear uno por nuestra cuenta if (meshData.pMin != null && meshData.pMax != null) { tgcMesh.BoundingBox = new TgcBoundingBox( TgcParserUtils.float3ArrayToVector3(meshData.pMin), TgcParserUtils.float3ArrayToVector3(meshData.pMax) ); } else { tgcMesh.createBoundingBox(); } tgcMesh.Enabled = true; return tgcMesh; }
/// <summary> /// Levanta la informacion del mesh a partir de un XML /// </summary> /// <param name="xmlString">contenido del XML</param> /// <returns></returns> public TgcSkeletalMeshData parseMeshFromString(string xmlString) { XmlDocument dom = new XmlDocument(); dom.LoadXml(xmlString); XmlElement root = dom.DocumentElement; TgcSkeletalMeshData meshData = new TgcSkeletalMeshData(); //Ver si tiene exportacion de texturas XmlNode texturesExportNode = root.GetElementsByTagName("texturesExport")[0]; bool texturesExportEnabled = bool.Parse(texturesExportNode.Attributes["enabled"].InnerText); if (texturesExportEnabled) { meshData.texturesDir = texturesExportNode.Attributes["dir"].InnerText; } //Parsear Texturas XmlNodeList materialNodes = root.GetElementsByTagName("materials")[0].ChildNodes; meshData.materialsData = new TgcMaterialData[materialNodes.Count]; int i = 0; foreach (XmlElement matNode in materialNodes) { //determinar tipo de Material TgcMaterialData material = new TgcMaterialData(); material.type = matNode.Attributes["type"].InnerText; //Standard Material if (material.type.Equals(TgcMaterialData.StandardMaterial)) { parseStandardMaterial(material, matNode); } //Multi Material else if (material.type.Equals(TgcMaterialData.MultiMaterial)) { material.name = matNode.Attributes["name"].InnerText; XmlNodeList subMaterialsNodes = matNode.GetElementsByTagName("subM"); material.subMaterials = new TgcMaterialData[subMaterialsNodes.Count]; for (int j = 0; j < subMaterialsNodes.Count; j++) { TgcMaterialData subMaterial = new TgcMaterialData(); parseStandardMaterial(subMaterial, (XmlElement)subMaterialsNodes[j]); material.subMaterials[j] = subMaterial; } } meshData.materialsData[i++] = material; } //Parsear Mesh XmlElement meshNode = (XmlElement)root.GetElementsByTagName("mesh")[0]; //parser y convertir valores meshData.name = meshNode.Attributes["name"].InnerText; meshData.materialId = int.Parse(meshNode.Attributes["matId"].InnerText); meshData.color = TgcParserUtils.parseFloat3Array(meshNode.Attributes["color"].InnerText); //TODO: formatear bien visibility string visibilityStr = meshNode.Attributes["visibility"].InnerText; //boundingBox, si esta XmlNodeList boundingBoxNodes = root.GetElementsByTagName("boundingBox"); if (boundingBoxNodes != null && boundingBoxNodes.Count == 1) { XmlNode boundingBoxNode = boundingBoxNodes[0]; meshData.pMin = TgcParserUtils.parseFloat3Array(boundingBoxNode.Attributes["min"].InnerText); meshData.pMax = TgcParserUtils.parseFloat3Array(boundingBoxNode.Attributes["max"].InnerText); } int count; //parsear coordinatesIdx XmlNode coordinatesIdxNode = meshNode.GetElementsByTagName("coordinatesIdx")[0]; count = int.Parse(coordinatesIdxNode.Attributes["count"].InnerText); meshData.coordinatesIndices = TgcParserUtils.parseIntStream(coordinatesIdxNode.InnerText, count); //parsear textCoordsIdx XmlNode textCoordsIdxNode = meshNode.GetElementsByTagName("textCoordsIdx")[0]; count = int.Parse(textCoordsIdxNode.Attributes["count"].InnerText); meshData.texCoordinatesIndices = TgcParserUtils.parseIntStream(textCoordsIdxNode.InnerText, count); //parsear colorsIdx XmlNode colorsIdxNode = meshNode.GetElementsByTagName("colorsIdx")[0]; count = int.Parse(colorsIdxNode.Attributes["count"].InnerText); meshData.colorIndices = TgcParserUtils.parseIntStream(colorsIdxNode.InnerText, count); //parsear matIds if (meshData.materialsData.Length > 0) { XmlNode matIdsNode = meshNode.GetElementsByTagName("matIds")[0]; count = int.Parse(matIdsNode.Attributes["count"].InnerText); meshData.materialsIds = TgcParserUtils.parseIntStream(matIdsNode.InnerText, count); } //parsear vertices XmlNode verticesNode = meshNode.GetElementsByTagName("vertices")[0]; count = int.Parse(verticesNode.Attributes["count"].InnerText); meshData.verticesCoordinates = TgcParserUtils.parseFloatStream(verticesNode.InnerText, count); //parsear texCoords XmlNode texCoordsNode = meshNode.GetElementsByTagName("texCoords")[0]; count = int.Parse(texCoordsNode.Attributes["count"].InnerText); meshData.textureCoordinates = TgcParserUtils.parseFloatStream(texCoordsNode.InnerText, count); //parsear colors XmlNode colorsNode = meshNode.GetElementsByTagName("colors")[0]; count = int.Parse(colorsNode.Attributes["count"].InnerText); float[] colorsArray = TgcParserUtils.parseFloatStream(colorsNode.InnerText, count); //convertir a format TV meshData.verticesColors = new int[count / 3]; for (int j = 0; j < meshData.verticesColors.Length; j++) { meshData.verticesColors[j] = Color.FromArgb( (int)colorsArray[j * 3], (int)colorsArray[j * 3 + 1], (int)colorsArray[j * 3 + 2]).ToArgb(); } //parsear esqueleto XmlNode skeletonNode = meshNode.GetElementsByTagName("skeleton")[0]; TgcSkeletalBoneData[] bonesData = new TgcSkeletalBoneData[skeletonNode.ChildNodes.Count]; int boneCount = 0; foreach (XmlElement boneNode in skeletonNode.ChildNodes) { TgcSkeletalBoneData boneData = new TgcSkeletalBoneData(); boneData.id = int.Parse(boneNode.Attributes["id"].InnerText); boneData.name = boneNode.Attributes["name"].InnerText; boneData.parentId = int.Parse(boneNode.Attributes["parentId"].InnerText); boneData.startPosition = TgcParserUtils.parseFloat3Array(boneNode.Attributes["pos"].InnerText); boneData.startRotation = TgcParserUtils.parseFloat4Array(boneNode.Attributes["rotQuat"].InnerText); bonesData[boneCount++] = boneData; } meshData.bones = bonesData; //parsear Weights XmlNode weightsNode = meshNode.GetElementsByTagName("weights")[0]; count = int.Parse(weightsNode.Attributes["count"].InnerText); meshData.verticesWeights = TgcParserUtils.parseFloatStream(weightsNode.InnerText, count); return(meshData); }
/// <summary> /// Cargar Weights de vertices /// </summary> /// <param name="meshData"></param> /// <returns></returns> private TgcSkeletalVertexWeight[] loadVerticesWeights(TgcSkeletalMeshData meshData, TgcSkeletalBone[] bones) { //Crear un array de Weights para cada uno de los vertices de la malla TgcSkeletalVertexWeight[] weights = new TgcSkeletalVertexWeight[meshData.verticesCoordinates.Length / 3]; float[] vertexWeightTotals = new float[weights.Length]; for (int i = 0; i < weights.Length; i++) { weights[i] = new TgcSkeletalVertexWeight(); vertexWeightTotals[i] = 0; } //Cargar los weights de cada vertice int weightsCount = meshData.verticesWeights.Length / 3; for (int i = 0; i < weightsCount; i++) { int vertexIdx = (int)meshData.verticesWeights[i * 3]; int boneIdx = (int)meshData.verticesWeights[i * 3 + 1]; float weightVal = meshData.verticesWeights[i * 3 + 2]; TgcSkeletalBone bone = bones[boneIdx]; TgcSkeletalVertexWeight.BoneWeight weight = new TgcSkeletalVertexWeight.BoneWeight(bone, weightVal); weights[vertexIdx].Weights.Add(weight); //acumular total de weight para ese vertice, para luego poder normalizar vertexWeightTotals[vertexIdx] += weightVal; } //Normalizar weights de cada vertice for (int i = 0; i < weights.Length; i++) { TgcSkeletalVertexWeight vertexWeight = weights[i]; float vTotal = vertexWeightTotals[i]; //Normalizar cada valor segun el total acumulado en el vertice foreach (TgcSkeletalVertexWeight.BoneWeight w in vertexWeight.Weights) { w.Weight = w.Weight / vTotal; } } return weights; }
/// <summary> /// Crea un mesh sin texturas, solo con VertexColors /// </summary> /// <param name="meshData"></param> private TgcSkeletalMesh crearMeshSoloColor(TgcSkeletalMeshData meshData) { //Crear Mesh Mesh mesh = new Mesh(meshData.coordinatesIndices.Length / 3, meshData.coordinatesIndices.Length, MeshFlags.Managed, VertexColorVertexElements, device); //Cargar esqueleto TgcSkeletalBone[] bones = loadSkeleton(meshData); TgcSkeletalVertexWeight[] verticesWeights = loadVerticesWeights(meshData, bones); //Cargar VertexBuffer using (VertexBuffer vb = mesh.VertexBuffer) { GraphicsStream data = vb.Lock(0, 0, LockFlags.None); for (int j = 0; j < meshData.coordinatesIndices.Length; j++) { VertexColorVertex v = new VertexColorVertex(); //vertices int coordIdx = meshData.coordinatesIndices[j] * 3; v.Position = new Vector3( meshData.verticesCoordinates[coordIdx], meshData.verticesCoordinates[coordIdx + 1], meshData.verticesCoordinates[coordIdx + 2] ); //color int colorIdx = meshData.colorIndices[j]; v.Color = meshData.verticesColors[colorIdx]; //normal if (meshData.verticesNormals != null) { v.Normal = new Vector3( meshData.verticesNormals[coordIdx], meshData.verticesNormals[coordIdx + 1], meshData.verticesNormals[coordIdx + 2] ); } else { v.Normal = new Vector3(0, 0, 0); } //tangent if (meshData.verticesTangents != null) { v.Tangent = new Vector3( meshData.verticesTangents[coordIdx], meshData.verticesTangents[coordIdx + 1], meshData.verticesTangents[coordIdx + 2] ); } else { v.Tangent = new Vector3(0, 0, 0); } //binormal if (meshData.verticesBinormals != null) { v.Binormal = new Vector3( meshData.verticesBinormals[coordIdx], meshData.verticesBinormals[coordIdx + 1], meshData.verticesBinormals[coordIdx + 2] ); } else { v.Binormal = new Vector3(0, 0, 0); } //BlendWeights y BlendIndices TgcSkeletalVertexWeight vWeight = verticesWeights[meshData.coordinatesIndices[j]]; vWeight.createVector4WeightsAndIndices(out v.BlendWeights, out v.BlendIndices); data.Write(v); } vb.Unlock(); } //Cargar indexBuffer en forma plana using (IndexBuffer ib = mesh.IndexBuffer) { short[] indices = new short[meshData.coordinatesIndices.Length]; for (int i = 0; i < indices.Length; i++) { indices[i] = (short)i; } ib.SetData(indices, 0, LockFlags.None); } //Crear mesh de TGC TgcSkeletalMesh tgcMesh = meshFactory.createNewMesh(mesh, meshData.name, TgcSkeletalMesh.MeshRenderType.VERTEX_COLOR, bones); return(tgcMesh); }
/// <summary> /// Crea un mesh con uno o varios DiffuseMap /// </summary> /// <returns></returns> private TgcSkeletalMesh crearMeshDiffuseMap(TgcSkeletalLoaderMaterialAux[] materialsArray, TgcSkeletalMeshData meshData) { //Crear Mesh Mesh mesh = new Mesh(meshData.coordinatesIndices.Length / 3, meshData.coordinatesIndices.Length, MeshFlags.Managed, DiffuseMapVertexElements, device); //Cargar VertexBuffer using (VertexBuffer vb = mesh.VertexBuffer) { GraphicsStream data = vb.Lock(0, 0, LockFlags.None); for (int j = 0; j < meshData.coordinatesIndices.Length; j++) { DiffuseMapVertex v = new DiffuseMapVertex(); //vertices int coordIdx = meshData.coordinatesIndices[j] * 3; v.Position = new Vector3( meshData.verticesCoordinates[coordIdx], meshData.verticesCoordinates[coordIdx + 1], meshData.verticesCoordinates[coordIdx + 2] ); //texture coordinates diffuseMap int texCoordIdx = meshData.texCoordinatesIndices[j] * 2; v.Tu = meshData.textureCoordinates[texCoordIdx]; v.Tv = meshData.textureCoordinates[texCoordIdx + 1]; //color int colorIdx = meshData.colorIndices[j]; v.Color = meshData.verticesColors[colorIdx]; data.Write(v); } vb.Unlock(); } //Cargar IndexBuffer en forma plana using (IndexBuffer ib = mesh.IndexBuffer) { short[] indices = new short[meshData.coordinatesIndices.Length]; for (int j = 0; j < indices.Length; j++) { indices[j] = (short)j; } ib.SetData(indices, 0, LockFlags.None); } //Configurar Material y Textura para un solo SubSet TgcSkeletalLoaderMaterialAux matAux = materialsArray[meshData.materialId]; Material[] meshMaterials; TgcTexture[] meshTextures; if (matAux.subMaterials == null) { meshMaterials = new Material[] { matAux.materialId }; meshTextures = new TgcTexture[] { matAux.texture }; } //Configurar Material y Textura para varios SubSet else { //Cargar attributeBuffer con los id de las texturas de cada triángulo int[] attributeBuffer = mesh.LockAttributeBufferArray(LockFlags.None); Array.Copy(meshData.materialsIds, attributeBuffer, attributeBuffer.Length); mesh.UnlockAttributeBuffer(attributeBuffer); //Cargar array de Materials y Texturas meshMaterials = new Material[matAux.subMaterials.Length]; meshTextures = new TgcTexture[matAux.subMaterials.Length]; for (int m = 0; m < matAux.subMaterials.Length; m++) { meshMaterials[m] = matAux.subMaterials[m].materialId; meshTextures[m] = matAux.subMaterials[m].texture; } } //Cargar esqueleto TgcSkeletalBone[] bones = loadSkeleton(meshData); TgcSkeletalVertexWeight[] verticesWeights = loadVerticesWeights(meshData, bones); //Cargar datos de meshData que interesan mantener como originales TgcSkeletalMesh.OriginalData origData = new TgcSkeletalMesh.OriginalData(); origData.coordinatesIndices = meshData.coordinatesIndices; origData.verticesCoordinates = meshData.verticesCoordinates; origData.colorIndices = meshData.colorIndices; origData.verticesColors = meshData.verticesColors; origData.texCoordinatesIndices = meshData.texCoordinatesIndices; origData.textureCoordinates = meshData.textureCoordinates; //Crear mesh de TGC TgcSkeletalMesh tgcMesh = meshFactory.createNewMesh(mesh, meshData.name, TgcSkeletalMesh.MeshRenderType.DIFFUSE_MAP, origData, bones, verticesWeights); tgcMesh.Materials = meshMaterials; tgcMesh.DiffuseMaps = meshTextures; return(tgcMesh); }
/// <summary> /// Carga un Modelo a partir de un objeto TgcSkeletalMeshData ya parseado /// </summary> /// <param name="meshData">Objeto con datos ya parseados</param> /// <param name="mediaPath">Path a partir del cual hay que buscar las Texturas</param> /// <returns>Modelo cargado</returns> public TgcSkeletalMesh loadMesh(TgcSkeletalMeshData meshData, string mediaPath) { //Cargar Texturas TgcSkeletalLoaderMaterialAux[] materialsArray = new TgcSkeletalLoaderMaterialAux[meshData.materialsData.Length]; for (int i = 0; i < meshData.materialsData.Length; i++) { TgcMaterialData materialData = meshData.materialsData[i]; string texturesPath = mediaPath + meshData.texturesDir + "\\"; //Crear StandardMaterial if (materialData.type.Equals(TgcMaterialData.StandardMaterial)) { materialsArray[i] = createTextureAndMaterial(materialData, texturesPath); } //Crear MultiMaterial else if (materialData.type.Equals(TgcMaterialData.MultiMaterial)) { TgcSkeletalLoaderMaterialAux matAux = new TgcSkeletalLoaderMaterialAux(); materialsArray[i] = matAux; matAux.subMaterials = new TgcSkeletalLoaderMaterialAux[materialData.subMaterials.Length]; for (int j = 0; j < materialData.subMaterials.Length; j++) { matAux.subMaterials[j] = createTextureAndMaterial(materialData.subMaterials[j], texturesPath); } } } //Crear Mesh TgcSkeletalMesh tgcMesh = null; //Crear mesh que no tiene Material, con un color simple if (meshData.materialId == -1) { tgcMesh = crearMeshSoloColor(meshData); } //Crear mesh con DiffuseMap else { tgcMesh = crearMeshDiffuseMap(materialsArray, meshData); } //Crear BoundingBox, aprovechar lo que viene del XML o crear uno por nuestra cuenta if (meshData.pMin != null && meshData.pMax != null) { tgcMesh.BoundingBox = new TgcBoundingBox( TgcParserUtils.float3ArrayToVector3(meshData.pMin), TgcParserUtils.float3ArrayToVector3(meshData.pMax) ); } else { tgcMesh.createBoundingBox(); } tgcMesh.Enabled = true; return(tgcMesh); }
/// <summary> /// Crea un mesh sin texturas, solo con VertexColors /// </summary> /// <param name="meshData"></param> private TgcSkeletalMesh crearMeshSoloColor(TgcSkeletalMeshData meshData) { //Crear Mesh Mesh mesh = new Mesh(meshData.coordinatesIndices.Length / 3, meshData.coordinatesIndices.Length, MeshFlags.Managed, VertexColorVertexElements, device); //Cargar esqueleto TgcSkeletalBone[] bones = loadSkeleton(meshData); TgcSkeletalVertexWeight[] verticesWeights = loadVerticesWeights(meshData, bones); //Cargar VertexBuffer using (VertexBuffer vb = mesh.VertexBuffer) { GraphicsStream data = vb.Lock(0, 0, LockFlags.None); for (int j = 0; j < meshData.coordinatesIndices.Length; j++) { VertexColorVertex v = new VertexColorVertex(); //vertices int coordIdx = meshData.coordinatesIndices[j] * 3; v.Position = new Vector3( meshData.verticesCoordinates[coordIdx], meshData.verticesCoordinates[coordIdx + 1], meshData.verticesCoordinates[coordIdx + 2] ); //color int colorIdx = meshData.colorIndices[j]; v.Color = meshData.verticesColors[colorIdx]; //normal if (meshData.verticesNormals != null) { v.Normal = new Vector3( meshData.verticesNormals[coordIdx], meshData.verticesNormals[coordIdx + 1], meshData.verticesNormals[coordIdx + 2] ); } else { v.Normal = new Vector3(0, 0, 0); } //tangent if (meshData.verticesTangents != null) { v.Tangent = new Vector3( meshData.verticesTangents[coordIdx], meshData.verticesTangents[coordIdx + 1], meshData.verticesTangents[coordIdx + 2] ); } else { v.Tangent = new Vector3(0, 0, 0); } //binormal if (meshData.verticesBinormals != null) { v.Binormal = new Vector3( meshData.verticesBinormals[coordIdx], meshData.verticesBinormals[coordIdx + 1], meshData.verticesBinormals[coordIdx + 2] ); } else { v.Binormal = new Vector3(0, 0, 0); } //BlendWeights y BlendIndices TgcSkeletalVertexWeight vWeight = verticesWeights[meshData.coordinatesIndices[j]]; vWeight.createVector4WeightsAndIndices(out v.BlendWeights, out v.BlendIndices); data.Write(v); } vb.Unlock(); } //Cargar indexBuffer en forma plana using (IndexBuffer ib = mesh.IndexBuffer) { short[] indices = new short[meshData.coordinatesIndices.Length]; for (int i = 0; i < indices.Length; i++) { indices[i] = (short)i; } ib.SetData(indices, 0, LockFlags.None); } //Crear mesh de TGC TgcSkeletalMesh tgcMesh = meshFactory.createNewMesh(mesh, meshData.name, TgcSkeletalMesh.MeshRenderType.VERTEX_COLOR, bones); return tgcMesh; }
/// <summary> /// Crea un mesh sin texturas, solo con VertexColors /// </summary> /// <param name="meshData"></param> private TgcSkeletalMesh crearMeshSoloColor(TgcSkeletalMeshData meshData) { //Crear Mesh Mesh mesh = new Mesh(meshData.coordinatesIndices.Length / 3, meshData.coordinatesIndices.Length, MeshFlags.Managed, VertexColorVertexElements, device); //Cargar VertexBuffer using (VertexBuffer vb = mesh.VertexBuffer) { GraphicsStream data = vb.Lock(0, 0, LockFlags.None); for (int j = 0; j < meshData.coordinatesIndices.Length; j++) { VertexColorVertex v = new VertexColorVertex(); //vertices int coordIdx = meshData.coordinatesIndices[j] * 3; v.Position = new Vector3( meshData.verticesCoordinates[coordIdx], meshData.verticesCoordinates[coordIdx + 1], meshData.verticesCoordinates[coordIdx + 2] ); //color int colorIdx = meshData.colorIndices[j]; v.Color = meshData.verticesColors[colorIdx]; data.Write(v); } vb.Unlock(); } //Cargar indexBuffer en forma plana using (IndexBuffer ib = mesh.IndexBuffer) { short[] indices = new short[meshData.coordinatesIndices.Length]; for (int i = 0; i < indices.Length; i++) { indices[i] = (short)i; } ib.SetData(indices, 0, LockFlags.None); } //Cargar esqueleto TgcSkeletalBone[] bones = loadSkeleton(meshData); TgcSkeletalVertexWeight[] verticesWeights = loadVerticesWeights(meshData, bones); //Cargar datos de meshData que interesan mantener como originales TgcSkeletalMesh.OriginalData origData = new TgcSkeletalMesh.OriginalData(); origData.coordinatesIndices = meshData.coordinatesIndices; origData.verticesCoordinates = meshData.verticesCoordinates; origData.colorIndices = meshData.colorIndices; origData.verticesColors = meshData.verticesColors; origData.texCoordinatesIndices = null; origData.textureCoordinates = null; //Crear mesh de TGC TgcSkeletalMesh tgcMesh = meshFactory.createNewMesh(mesh, meshData.name, TgcSkeletalMesh.MeshRenderType.VERTEX_COLOR, origData, bones, verticesWeights); return tgcMesh; }
/// <summary> /// Levanta la informacion del mesh a partir de un XML /// </summary> /// <param name="xmlString">contenido del XML</param> /// <returns></returns> public TgcSkeletalMeshData parseMeshFromString(string xmlString) { XmlDocument dom = new XmlDocument(); dom.LoadXml(xmlString); XmlElement root = dom.DocumentElement; TgcSkeletalMeshData meshData = new TgcSkeletalMeshData(); //Ver si tiene exportacion de texturas XmlNode texturesExportNode = root.GetElementsByTagName("texturesExport")[0]; bool texturesExportEnabled = bool.Parse(texturesExportNode.Attributes["enabled"].InnerText); if (texturesExportEnabled) { meshData.texturesDir = texturesExportNode.Attributes["dir"].InnerText; } //Parsear Texturas XmlNodeList materialNodes = root.GetElementsByTagName("materials")[0].ChildNodes; meshData.materialsData = new TgcMaterialData[materialNodes.Count]; int i = 0; foreach (XmlElement matNode in materialNodes) { //determinar tipo de Material TgcMaterialData material = new TgcMaterialData(); material.type = matNode.Attributes["type"].InnerText; //Standard Material if (material.type.Equals(TgcMaterialData.StandardMaterial)) { parseStandardMaterial(material, matNode); } //Multi Material else if (material.type.Equals(TgcMaterialData.MultiMaterial)) { material.name = matNode.Attributes["name"].InnerText; XmlNodeList subMaterialsNodes = matNode.GetElementsByTagName("subM"); material.subMaterials = new TgcMaterialData[subMaterialsNodes.Count]; for (int j = 0; j < subMaterialsNodes.Count; j++) { TgcMaterialData subMaterial = new TgcMaterialData(); parseStandardMaterial(subMaterial, (XmlElement)subMaterialsNodes[j]); material.subMaterials[j] = subMaterial; } } meshData.materialsData[i++] = material; } //Parsear Mesh XmlElement meshNode = (XmlElement)root.GetElementsByTagName("mesh")[0]; //parser y convertir valores meshData.name = meshNode.Attributes["name"].InnerText; meshData.materialId = int.Parse(meshNode.Attributes["matId"].InnerText); meshData.color = TgcParserUtils.parseFloat3Array(meshNode.Attributes["color"].InnerText); //TODO: formatear bien visibility string visibilityStr = meshNode.Attributes["visibility"].InnerText; //boundingBox, si esta XmlNodeList boundingBoxNodes = root.GetElementsByTagName("boundingBox"); if (boundingBoxNodes != null && boundingBoxNodes.Count == 1) { XmlNode boundingBoxNode = boundingBoxNodes[0]; meshData.pMin = TgcParserUtils.parseFloat3Array(boundingBoxNode.Attributes["min"].InnerText); meshData.pMax = TgcParserUtils.parseFloat3Array(boundingBoxNode.Attributes["max"].InnerText); } int count; //parsear coordinatesIdx XmlNode coordinatesIdxNode = meshNode.GetElementsByTagName("coordinatesIdx")[0]; count = int.Parse(coordinatesIdxNode.Attributes["count"].InnerText); meshData.coordinatesIndices = TgcParserUtils.parseIntStream(coordinatesIdxNode.InnerText, count); //parsear textCoordsIdx XmlNode textCoordsIdxNode = meshNode.GetElementsByTagName("textCoordsIdx")[0]; count = int.Parse(textCoordsIdxNode.Attributes["count"].InnerText); meshData.texCoordinatesIndices = TgcParserUtils.parseIntStream(textCoordsIdxNode.InnerText, count); //parsear colorsIdx XmlNode colorsIdxNode = meshNode.GetElementsByTagName("colorsIdx")[0]; count = int.Parse(colorsIdxNode.Attributes["count"].InnerText); meshData.colorIndices = TgcParserUtils.parseIntStream(colorsIdxNode.InnerText, count); //parsear matIds if (meshData.materialsData.Length > 0) { XmlNode matIdsNode = meshNode.GetElementsByTagName("matIds")[0]; count = int.Parse(matIdsNode.Attributes["count"].InnerText); meshData.materialsIds = TgcParserUtils.parseIntStream(matIdsNode.InnerText, count); } //parsear vertices XmlNode verticesNode = meshNode.GetElementsByTagName("vertices")[0]; count = int.Parse(verticesNode.Attributes["count"].InnerText); meshData.verticesCoordinates = TgcParserUtils.parseFloatStream(verticesNode.InnerText, count); //parsear texCoords XmlNode texCoordsNode = meshNode.GetElementsByTagName("texCoords")[0]; count = int.Parse(texCoordsNode.Attributes["count"].InnerText); meshData.textureCoordinates = TgcParserUtils.parseFloatStream(texCoordsNode.InnerText, count); //parsear colors XmlNode colorsNode = meshNode.GetElementsByTagName("colors")[0]; count = int.Parse(colorsNode.Attributes["count"].InnerText); float[] colorsArray = TgcParserUtils.parseFloatStream(colorsNode.InnerText, count); //convertir a format TV meshData.verticesColors = new int[count / 3]; for (int j = 0; j < meshData.verticesColors.Length; j++) { meshData.verticesColors[j] = Color.FromArgb( (int)colorsArray[j * 3], (int)colorsArray[j * 3 + 1], (int)colorsArray[j * 3 + 2]).ToArgb(); } //parsear normals, si hay XmlNodeList normalsNodes = meshNode.GetElementsByTagName("normals"); if (normalsNodes != null && normalsNodes.Count == 1) { XmlNode normalsNode = normalsNodes[0]; count = int.Parse(normalsNode.Attributes["count"].InnerText); meshData.verticesNormals = TgcParserUtils.parseFloatStream(normalsNode.InnerText, count); } //parsear tangents, si hay XmlNodeList tangentsNodes = meshNode.GetElementsByTagName("tangents"); if (tangentsNodes != null && tangentsNodes.Count == 1) { XmlNode tangentsNode = tangentsNodes[0]; count = int.Parse(tangentsNode.Attributes["count"].InnerText); meshData.verticesTangents = TgcParserUtils.parseFloatStream(tangentsNode.InnerText, count); } //parsear binormals, si hay XmlNodeList binormalsNodes = meshNode.GetElementsByTagName("binormals"); if (binormalsNodes != null && binormalsNodes.Count == 1) { XmlNode binormalsNode = binormalsNodes[0]; count = int.Parse(binormalsNode.Attributes["count"].InnerText); meshData.verticesBinormals = TgcParserUtils.parseFloatStream(binormalsNode.InnerText, count); } //parsear esqueleto XmlNode skeletonNode = meshNode.GetElementsByTagName("skeleton")[0]; TgcSkeletalBoneData[] bonesData = new TgcSkeletalBoneData[skeletonNode.ChildNodes.Count]; int boneCount = 0; foreach (XmlElement boneNode in skeletonNode.ChildNodes) { TgcSkeletalBoneData boneData = new TgcSkeletalBoneData(); boneData.id = int.Parse(boneNode.Attributes["id"].InnerText); boneData.name = boneNode.Attributes["name"].InnerText; boneData.parentId = int.Parse(boneNode.Attributes["parentId"].InnerText); boneData.startPosition = TgcParserUtils.parseFloat3Array(boneNode.Attributes["pos"].InnerText); boneData.startRotation = TgcParserUtils.parseFloat4Array(boneNode.Attributes["rotQuat"].InnerText); bonesData[boneCount++] = boneData; } meshData.bones = bonesData; //parsear Weights XmlNode weightsNode = meshNode.GetElementsByTagName("weights")[0]; count = int.Parse(weightsNode.Attributes["count"].InnerText); meshData.verticesWeights = TgcParserUtils.parseFloatStream(weightsNode.InnerText, count); return meshData; }
/// <summary> /// Cargar Weights de vertices /// </summary> /// <param name="meshData"></param> /// <returns></returns> private TgcSkeletalVertexWeight[] loadVerticesWeights(TgcSkeletalMeshData meshData, TgcSkeletalBone[] bones) { int maxWeights = 4; TgcSkeletalVertexWeight.BoneWeight.GreaterComparer weightComparer = new TgcSkeletalVertexWeight.BoneWeight.GreaterComparer(); //Crear un array de Weights para cada uno de los vertices de la malla TgcSkeletalVertexWeight[] weights = new TgcSkeletalVertexWeight[meshData.verticesCoordinates.Length / 3]; for (int i = 0; i < weights.Length; i++) { weights[i] = new TgcSkeletalVertexWeight(); } //Cargar los weights de cada vertice int weightsCount = meshData.verticesWeights.Length / 3; for (int i = 0; i < weightsCount; i++) { int vertexIdx = (int)meshData.verticesWeights[i * 3]; int boneIdx = (int)meshData.verticesWeights[i * 3 + 1]; float weightVal = meshData.verticesWeights[i * 3 + 2]; TgcSkeletalBone bone = bones[boneIdx]; TgcSkeletalVertexWeight.BoneWeight weight = new TgcSkeletalVertexWeight.BoneWeight(bone, weightVal); weights[vertexIdx].Weights.Add(weight); } //Normalizar weights de cada vertice for (int i = 0; i < weights.Length; i++) { TgcSkeletalVertexWeight vertexWeight = weights[i]; //Se soportan hasta 4 weights por vertice. Si hay mas se quitan y se reparten las influencias entre el resto de los huesos if (vertexWeight.Weights.Count > maxWeights) { //Ordenar por weight de menor a mayor y luego revertir, para que quede de mayor a menor peso vertexWeight.Weights.Sort(weightComparer); vertexWeight.Weights.Reverse(); //Quitar los ultimos los weight que superan 4 while (vertexWeight.Weights.Count > maxWeights) { vertexWeight.Weights.RemoveAt(vertexWeight.Weights.Count - 1); } } //Sumar el total de todos los weights de este vertice float weightTotal = 0; foreach (TgcSkeletalVertexWeight.BoneWeight w in vertexWeight.Weights) { weightTotal += w.Weight; } //Normalizar cada valor segun el total acumulado en el vertice foreach (TgcSkeletalVertexWeight.BoneWeight w in vertexWeight.Weights) { w.Weight = w.Weight / weightTotal; } } return(weights); }