/// <summary> /// Unifica N Mallas en una sola, adaptando sus coordendas de textura y Materials. /// Actualmente no se puede hacer con Mallas que tengan LightMaps. /// </summary> /// <param name="meshName">Nuevo nombre de malla</param> /// <param name="meshesExport">Array de mallas a unificar</param> /// <returns>Datos de nueva malla unificada</returns> public MeshExport appendAllMeshes(string meshName, MeshExport[] meshesExport) { MeshExport finalMesh = meshesExport[0]; for (int i = 1; i < meshesExport.Length; i++) { finalMesh = appendMeshes(meshName, finalMesh, meshesExport[i]); } return finalMesh; }
/// <summary> /// Graba una escena a XML, en base a información de varios TgcMesh. /// También crea una carpeta Textures relativa al XML y copia ahí todas las texturas utilizadas por las Mallas. /// Lo mismo para LightMaps. /// </summary> /// <param name="sceneName">Nombre de la escena</param> /// <param name="sceneBoundingBox">BoundingBox de toda la escena</param> /// <param name="meshesExport">Array de datos de Mallas que se quieren exportar</param> /// <param name="saveFolderPath">Carpeta en la que se quiera guardar el XML</param> /// <returns>Resultado de exportacion</returns> public ExportResult saveSceneToXml(string sceneName, TgcBoundingBox sceneBoundingBox, MeshExport[] meshesExport, string saveFolderPath) { ExportResult result = new ExportResult(); try { //Ver si la escena tiene Lightmaps bool hasLightmaps = true; foreach (MeshExport mExp in meshesExport) { if (mExp.MeshData.lightmap == null) { hasLightmaps = false; break; } } //Crear XML XmlDocument doc = new XmlDocument(); XmlNode root = doc.CreateElement("tgcScene"); //name XmlElement nameNode = doc.CreateElement("name"); nameNode.InnerText = sceneName; root.AppendChild(nameNode); //texturesExport XmlElement texturesExportNode = doc.CreateElement("texturesExport"); texturesExportNode.SetAttribute("enabled", true.ToString()); texturesExportNode.SetAttribute("dir", DEFAULT_TEXTURES_DIR); root.AppendChild(texturesExportNode); //lightmapExport XmlElement lightmapExportNode = doc.CreateElement("lightmapExport"); lightmapExportNode.SetAttribute("enabled", hasLightmaps.ToString()); lightmapExportNode.SetAttribute("dir", DEFAULT_LIGHTMAPS_DIR); root.AppendChild(lightmapExportNode); //sceneBoundingBox XmlElement sceneBoundingBoxNode = doc.CreateElement("sceneBoundingBox"); sceneBoundingBoxNode.SetAttribute("min", TgcParserUtils.printVector3(sceneBoundingBox.PMin)); sceneBoundingBoxNode.SetAttribute("max", TgcParserUtils.printVector3(sceneBoundingBox.PMax)); root.AppendChild(sceneBoundingBoxNode); //materials XmlElement materialsNode = doc.CreateElement("materials"); List<MeshExport> unifiedMaterialsData = new List<MeshExport>(); foreach (MeshExport mExp in meshesExport) { if (mExp.MaterialsData != null) { //Buscar si ya exportamos un Material igual int existingMatId = searchSameMaterial(mExp, unifiedMaterialsData); //Nuevo Material if (existingMatId == -1) { //Standardmaterial if (mExp.MaterialsData.Length == 1) { //Crear Material XmlElement mNode = createMaterialXmlNode(doc, mExp.MaterialsData[0], "m"); materialsNode.AppendChild(mNode); } //Multimaterial else { //Crear Multimaterial XmlElement mNode = doc.CreateElement("m"); mNode.SetAttribute("name", TgcMaterialData.MultiMaterial); mNode.SetAttribute("type", TgcMaterialData.MultiMaterial); //Crear SubMaterials foreach (TgcMaterialData materialData in mExp.MaterialsData) { XmlElement subMNode = createMaterialXmlNode(doc, materialData, "subM"); mNode.AppendChild(subMNode); } materialsNode.AppendChild(mNode); } //Actualizar indice de material del mesh unifiedMaterialsData.Add(mExp); mExp.MeshData.materialId = unifiedMaterialsData.Count - 1; } //Material repetido else { mExp.MeshData.materialId = existingMatId; } } } materialsNode.SetAttribute("count", unifiedMaterialsData.Count.ToString()); root.AppendChild(materialsNode); //meshes XmlElement meshesNode = doc.CreateElement("meshes"); meshesNode.SetAttribute("count", meshesExport.Length.ToString()); foreach (MeshExport mExp in meshesExport) { TgcMeshData meshData = mExp.MeshData; //mesh XmlElement meshNode = doc.CreateElement("mesh"); meshNode.SetAttribute("name", meshData.name); meshNode.SetAttribute("layer", meshData.layerName); meshNode.SetAttribute("type", TgcMeshData.ORIGINAL); meshNode.SetAttribute("matId", meshData.materialId.ToString()); meshNode.SetAttribute("color", meshData.color != null ? TgcParserUtils.printFloat3Array(meshData.color) : TgcParserUtils.printFloat3Array(new float[]{1,1,1})); meshNode.SetAttribute("visibility", meshData.alphaBlending ? "0" : "1.0"); meshNode.SetAttribute("lightmap", meshData.lightmap != null ? meshData.lightmap : ""); //boundingBox XmlElement boundingBoxNode = doc.CreateElement("boundingBox"); boundingBoxNode.SetAttribute("min", TgcParserUtils.printFloat3Array(meshData.pMin)); boundingBoxNode.SetAttribute("max", TgcParserUtils.printFloat3Array(meshData.pMax)); meshNode.AppendChild(boundingBoxNode); //Malla original if (meshData.instanceType.Equals(TgcMeshData.ORIGINAL)) { //coordinatesIdx XmlElement coordinatesIdxNode = doc.CreateElement("coordinatesIdx"); coordinatesIdxNode.SetAttribute("count", meshData.coordinatesIndices.Length.ToString()); coordinatesIdxNode.InnerText = TgcParserUtils.printIntStream(meshData.coordinatesIndices); meshNode.AppendChild(coordinatesIdxNode); //textCoordsIdx XmlElement textCoordsIdxNode = doc.CreateElement("textCoordsIdx"); textCoordsIdxNode.SetAttribute("count", meshData.texCoordinatesIndices.Length.ToString()); textCoordsIdxNode.InnerText = TgcParserUtils.printIntStream(meshData.texCoordinatesIndices); meshNode.AppendChild(textCoordsIdxNode); //colorsIdx XmlElement colorsIdxNode = doc.CreateElement("colorsIdx"); colorsIdxNode.SetAttribute("count", meshData.colorIndices.Length.ToString()); colorsIdxNode.InnerText = TgcParserUtils.printIntStream(meshData.colorIndices); meshNode.AppendChild(colorsIdxNode); //matIds XmlElement matIdsNode = doc.CreateElement("matIds"); matIdsNode.SetAttribute("count", meshData.materialsIds.Length.ToString()); matIdsNode.InnerText = TgcParserUtils.printIntStream(meshData.materialsIds); meshNode.AppendChild(matIdsNode); //textCoordsLightMapIdx XmlElement textCoordsLightMapIdxNode = doc.CreateElement("textCoordsLightMapIdx"); textCoordsLightMapIdxNode.SetAttribute("count", meshData.texCoordinatesIndicesLightMap.Length.ToString()); textCoordsLightMapIdxNode.InnerText = TgcParserUtils.printIntStream(meshData.texCoordinatesIndicesLightMap); meshNode.AppendChild(textCoordsLightMapIdxNode); //vertices XmlElement verticesNode = doc.CreateElement("vertices"); verticesNode.SetAttribute("count", meshData.verticesCoordinates.Length.ToString()); verticesNode.InnerText = TgcParserUtils.printFloatStream(meshData.verticesCoordinates); meshNode.AppendChild(verticesNode); //normals XmlElement normalsNode = doc.CreateElement("normals"); normalsNode.SetAttribute("count", meshData.verticesNormals.Length.ToString()); normalsNode.InnerText = TgcParserUtils.printFloatStream(meshData.verticesNormals); meshNode.AppendChild(normalsNode); //texCoords XmlElement texCoordsNode = doc.CreateElement("texCoords"); texCoordsNode.SetAttribute("count", meshData.textureCoordinates.Length.ToString()); texCoordsNode.InnerText = TgcParserUtils.printFloatStream(meshData.textureCoordinates); meshNode.AppendChild(texCoordsNode); //colors XmlElement colorsNode = doc.CreateElement("colors"); colorsNode.SetAttribute("count", meshData.verticesColors.Length.ToString()); colorsNode.InnerText = TgcParserUtils.printIntStream(meshData.verticesColors); meshNode.AppendChild(colorsNode); //texCoordsLightMap XmlElement texCoordsLightMapNode = doc.CreateElement("texCoordsLightMap"); texCoordsLightMapNode.SetAttribute("count", meshData.textureCoordinatesLightMap.Length.ToString()); texCoordsLightMapNode.InnerText = TgcParserUtils.printFloatStream(meshData.textureCoordinatesLightMap); meshNode.AppendChild(texCoordsLightMapNode); } //Malla instancia else { meshNode.Attributes["type"].InnerText = TgcMeshData.INSTANCE; //originalMesh XmlElement originalMeshNode = doc.CreateElement("originalMesh"); originalMeshNode.InnerText = meshData.originalMesh.ToString(); meshNode.AppendChild(originalMeshNode); //transform XmlElement transformNode = doc.CreateElement("transform"); transformNode.SetAttribute("pos", TgcParserUtils.printFloat3Array(meshData.position)); transformNode.SetAttribute("rotQuat", TgcParserUtils.printFloat4Array(meshData.rotation)); transformNode.SetAttribute("scale", TgcParserUtils.printFloat3Array(meshData.scale)); meshNode.AppendChild(transformNode); } //userProps if (meshData.userProperties != null) { XmlElement userPropsNode = doc.CreateElement("userProps"); userPropsNode.SetAttribute("count", meshData.userProperties.Count.ToString()); foreach (KeyValuePair<string,string> entry in meshData.userProperties) { XmlElement propNode = doc.CreateElement(entry.Key); propNode.InnerText = entry.Value; userPropsNode.AppendChild(propNode); } meshNode.AppendChild(userPropsNode); } meshesNode.AppendChild(meshNode); } root.AppendChild(meshesNode); //Guardar XML, borrar si ya existe doc.AppendChild(root); string sceneFileName = sceneName + "-TgcScene.xml"; string sceneFilePath = saveFolderPath + "\\" + sceneFileName; result.filePath = sceneFilePath; if (File.Exists(sceneFilePath)) { File.Delete(sceneFilePath); } doc.Save(sceneFilePath); //Crear directorio de texturas string texturesDir = saveFolderPath + "\\" + DEFAULT_TEXTURES_DIR; if (!Directory.Exists(texturesDir)) { //Directory.Delete(texturesDir, true); Directory.CreateDirectory(texturesDir); } //Copiar todos los DiffuseMap a la carpeta de texturas foreach (MeshExport mExp in meshesExport) { if (mExp.diffuseMapsAbsolutePath != null) { for (int i = 0; i < mExp.diffuseMapsAbsolutePath.Length; i++) { try { copyFile(mExp.diffuseMapsAbsolutePath[i], texturesDir + "\\" + mExp.MaterialsData[i].fileName); } catch (Exception tEx) { result.secondaryErrors = true; result.errors.Add("Error al copiar textura: " + mExp.diffuseMapsAbsolutePath[i] + ". " + tEx.Message); } } } } //Crear directorio de lightmaps, borrar si ya existe if (hasLightmaps) { string lightmapsDir = saveFolderPath + "\\" + DEFAULT_LIGHTMAPS_DIR; if (Directory.Exists(lightmapsDir)) { Directory.Delete(lightmapsDir, true); } Directory.CreateDirectory(lightmapsDir); //Copiar todos los lightmaps a la carpeta de lightmaps foreach (MeshExport mExp in meshesExport) { try { copyFile(mExp.lightmapAbsolutePath, lightmapsDir + "\\" + mExp.MeshData.lightmap); } catch (Exception tEx) { result.secondaryErrors = true; result.errors.Add("Error al copiar lightmap: " + mExp.lightmapAbsolutePath + ". " + tEx.Message); } } } return result; } catch (Exception ex) { result.result = false; result.errors.Add("Hubo un error inesperado al crear XML de escena: " + sceneName + ". " + ex.Message); return result; } }
/// <summary> /// Unifica dos Mallas en una, adaptando sus coordendas de textura y Materials. /// Actualmente no se puede hacer con Mallas que tengan LightMaps. /// </summary> /// <param name="meshName">Nuevo nombre de malla</param> /// <param name="mExp1">Datos de malla 1</param> /// <param name="mExp2">Datos de malla 2</param> /// <returns>Datos de nueva malla unificada</returns> public MeshExport appendMeshes(string meshName, MeshExport mExp1, MeshExport mExp2) { //Chequear que sea mismo tipo de malla if (mExp1.MeshRenderType != mExp2.MeshRenderType) { throw new Exception("Se intentó juntar dos Mallas de formato distintos: " + mExp1.MeshData.name + " y " + mExp2.MeshData.name); } //Por ahora no se pueden unificar LightMaps if (mExp1.MeshRenderType == TgcMesh.MeshRenderType.DIFFUSE_MAP_AND_LIGHTMAP) { throw new Exception("Actualmente no esta soportado juntar dos Mallas que tienen LightMaps: " + mExp1.MeshData.name + " y " + mExp2.MeshData.name); } //General MeshExport meshExpAppended = new MeshExport(); meshExpAppended.MeshData = new TgcMeshData(); meshExpAppended.MeshData.name = meshName; meshExpAppended.MeshData.layerName = mExp1.MeshData.layerName; meshExpAppended.lightmapAbsolutePath = null; meshExpAppended.MeshData.lightmap = null; meshExpAppended.MeshData.color = mExp1.MeshData.color; meshExpAppended.MeshData.alphaBlending = mExp1.MeshData.alphaBlending | mExp2.MeshData.alphaBlending; meshExpAppended.MeshData.instanceType = TgcMeshData.ORIGINAL; //BoundingBox que une ambas List<TgcBoundingBox> bboxes = new List<TgcBoundingBox>(); bboxes.Add(new TgcBoundingBox(TgcParserUtils.float3ArrayToVector3(mExp1.MeshData.pMin), TgcParserUtils.float3ArrayToVector3(mExp1.MeshData.pMax))); bboxes.Add(new TgcBoundingBox(TgcParserUtils.float3ArrayToVector3(mExp2.MeshData.pMin), TgcParserUtils.float3ArrayToVector3(mExp2.MeshData.pMax))); TgcBoundingBox appendenBbox = TgcBoundingBox.computeFromBoundingBoxes(bboxes); meshExpAppended.MeshData.pMin = TgcParserUtils.vector3ToFloat3Array(appendenBbox.PMin); meshExpAppended.MeshData.pMax = TgcParserUtils.vector3ToFloat3Array(appendenBbox.PMax); //coordinatesIndices meshExpAppended.MeshData.coordinatesIndices = new int[mExp1.MeshData.coordinatesIndices.Length + mExp2.MeshData.coordinatesIndices.Length]; Array.Copy(mExp1.MeshData.coordinatesIndices, 0, meshExpAppended.MeshData.coordinatesIndices, 0, mExp1.MeshData.coordinatesIndices.Length); Array.Copy(mExp2.MeshData.coordinatesIndices, 0, meshExpAppended.MeshData.coordinatesIndices, mExp1.MeshData.coordinatesIndices.Length, mExp2.MeshData.coordinatesIndices.Length); //verticesCoordinates meshExpAppended.MeshData.verticesCoordinates = new float[mExp1.MeshData.verticesCoordinates.Length + mExp2.MeshData.verticesCoordinates.Length]; Array.Copy(mExp1.MeshData.verticesCoordinates, 0, meshExpAppended.MeshData.verticesCoordinates, 0, mExp1.MeshData.verticesCoordinates.Length); Array.Copy(mExp2.MeshData.verticesCoordinates, 0, meshExpAppended.MeshData.verticesCoordinates, mExp1.MeshData.verticesCoordinates.Length, mExp2.MeshData.verticesCoordinates.Length); //Ajustar indices de coordinatesIndices del segundo mesh for (int i = mExp1.MeshData.coordinatesIndices.Length; i < meshExpAppended.MeshData.coordinatesIndices.Length; i++) { meshExpAppended.MeshData.coordinatesIndices[i] += mExp1.MeshData.verticesCoordinates.Length / 3; } //texCoordinatesIndices meshExpAppended.MeshData.texCoordinatesIndices = new int[mExp1.MeshData.texCoordinatesIndices.Length + mExp2.MeshData.texCoordinatesIndices.Length]; Array.Copy(mExp1.MeshData.texCoordinatesIndices, 0, meshExpAppended.MeshData.texCoordinatesIndices, 0, mExp1.MeshData.texCoordinatesIndices.Length); Array.Copy(mExp2.MeshData.texCoordinatesIndices, 0, meshExpAppended.MeshData.texCoordinatesIndices, mExp1.MeshData.texCoordinatesIndices.Length, mExp2.MeshData.texCoordinatesIndices.Length); //textureCoordinates meshExpAppended.MeshData.textureCoordinates = new float[mExp1.MeshData.textureCoordinates.Length + mExp2.MeshData.textureCoordinates.Length]; Array.Copy(mExp1.MeshData.textureCoordinates, 0, meshExpAppended.MeshData.textureCoordinates, 0, mExp1.MeshData.textureCoordinates.Length); Array.Copy(mExp2.MeshData.textureCoordinates, 0, meshExpAppended.MeshData.textureCoordinates, mExp1.MeshData.textureCoordinates.Length, mExp2.MeshData.textureCoordinates.Length); //Ajustar indices de textureCoordinates del segundo mesh for (int i = mExp1.MeshData.texCoordinatesIndices.Length; i < meshExpAppended.MeshData.texCoordinatesIndices.Length; i++) { meshExpAppended.MeshData.texCoordinatesIndices[i] += mExp1.MeshData.textureCoordinates.Length / 2 ; } //colorIndices meshExpAppended.MeshData.colorIndices = new int[mExp1.MeshData.colorIndices.Length + mExp2.MeshData.colorIndices.Length]; Array.Copy(mExp1.MeshData.colorIndices, 0, meshExpAppended.MeshData.colorIndices, 0, mExp1.MeshData.colorIndices.Length); Array.Copy(mExp2.MeshData.colorIndices, 0, meshExpAppended.MeshData.colorIndices, mExp1.MeshData.colorIndices.Length, mExp2.MeshData.colorIndices.Length); //verticesColors meshExpAppended.MeshData.verticesColors = new int[mExp1.MeshData.verticesColors.Length + mExp2.MeshData.verticesColors.Length]; Array.Copy(mExp1.MeshData.verticesColors, 0, meshExpAppended.MeshData.verticesColors, 0, mExp1.MeshData.verticesColors.Length); Array.Copy(mExp2.MeshData.verticesColors, 0, meshExpAppended.MeshData.verticesColors, mExp1.MeshData.verticesColors.Length, mExp2.MeshData.verticesColors.Length); //Ajustar indices de verticesColors del segundo mesh for (int i = mExp1.MeshData.colorIndices.Length; i < meshExpAppended.MeshData.colorIndices.Length; i++) { meshExpAppended.MeshData.colorIndices[i] += mExp1.MeshData.verticesColors.Length / 3; } //texCoordinatesIndicesLightMap meshExpAppended.MeshData.texCoordinatesIndicesLightMap = new int[mExp1.MeshData.texCoordinatesIndicesLightMap.Length + mExp2.MeshData.texCoordinatesIndicesLightMap.Length]; Array.Copy(mExp1.MeshData.texCoordinatesIndicesLightMap, 0, meshExpAppended.MeshData.texCoordinatesIndicesLightMap, 0, mExp1.MeshData.texCoordinatesIndicesLightMap.Length); Array.Copy(mExp2.MeshData.texCoordinatesIndicesLightMap, 0, meshExpAppended.MeshData.texCoordinatesIndicesLightMap, mExp1.MeshData.texCoordinatesIndicesLightMap.Length, mExp2.MeshData.texCoordinatesIndicesLightMap.Length); //textureCoordinatesLightMap meshExpAppended.MeshData.textureCoordinatesLightMap = new float[mExp1.MeshData.textureCoordinatesLightMap.Length + mExp2.MeshData.textureCoordinatesLightMap.Length]; Array.Copy(mExp1.MeshData.textureCoordinatesLightMap, 0, meshExpAppended.MeshData.textureCoordinatesLightMap, 0, mExp1.MeshData.textureCoordinatesLightMap.Length); Array.Copy(mExp2.MeshData.textureCoordinatesLightMap, 0, meshExpAppended.MeshData.textureCoordinatesLightMap, mExp1.MeshData.textureCoordinatesLightMap.Length, mExp2.MeshData.textureCoordinatesLightMap.Length); //Ajustar indices de textureCoordinatesLightMap del segundo mesh for (int i = mExp1.MeshData.texCoordinatesIndicesLightMap.Length; i < meshExpAppended.MeshData.texCoordinatesIndicesLightMap.Length; i++) { meshExpAppended.MeshData.texCoordinatesIndicesLightMap[i] += mExp1.MeshData.textureCoordinatesLightMap.Length / 2; } //verticesNormals meshExpAppended.MeshData.verticesNormals = new float[mExp1.MeshData.verticesNormals.Length + mExp2.MeshData.verticesNormals.Length]; Array.Copy(mExp1.MeshData.verticesNormals, 0, meshExpAppended.MeshData.verticesNormals, 0, mExp1.MeshData.verticesNormals.Length); Array.Copy(mExp2.MeshData.verticesNormals, 0, meshExpAppended.MeshData.verticesNormals, mExp1.MeshData.verticesNormals.Length, mExp2.MeshData.verticesNormals.Length); //Material if (mExp1.MeshRenderType == TgcMesh.MeshRenderType.VERTEX_COLOR) { meshExpAppended.diffuseMapsAbsolutePath = null; meshExpAppended.MaterialsData = null; meshExpAppended.MeshData.materialId = -1; meshExpAppended.MeshData.materialsIds = new int[0]; meshExpAppended.MeshRenderType = TgcMesh.MeshRenderType.VERTEX_COLOR; } else if (mExp1.MeshRenderType == TgcMesh.MeshRenderType.DIFFUSE_MAP) { meshExpAppended.MeshRenderType = TgcMesh.MeshRenderType.DIFFUSE_MAP; //materialsIds: crear con la cantidad de triangulos total meshExpAppended.MeshData.materialsIds = new int[meshExpAppended.MeshData.coordinatesIndices.Length / 3]; //copiar materialsIds del mesh 1, expandir si es necesario int triCountMesh1 = mExp1.MeshData.coordinatesIndices.Length / 3; int triCountMesh2 = mExp2.MeshData.coordinatesIndices.Length / 3; if (mExp1.MeshData.materialsIds.Length == 1) { for (int i = 0; i < triCountMesh1; i++) { meshExpAppended.MeshData.materialsIds[i] = 0; } } else { Array.Copy(mExp1.MeshData.materialsIds, 0, meshExpAppended.MeshData.materialsIds, 0, mExp1.MeshData.materialsIds.Length); } //copiar materialsIds del mesh 2, expandir si es necesario if (mExp2.MeshData.materialsIds.Length == 1) { for (int i = triCountMesh1; i < meshExpAppended.MeshData.materialsIds.Length; i++) { meshExpAppended.MeshData.materialsIds[i] = 0; } } else { Array.Copy(mExp2.MeshData.materialsIds, 0, meshExpAppended.MeshData.materialsIds, triCountMesh1, mExp2.MeshData.materialsIds.Length); } //Ver si tienen el mismo material List<MeshExport> unifiedMaterialsData = new List<MeshExport>(); unifiedMaterialsData.Add(mExp1); int existingMatId = searchSameMaterial(mExp2, unifiedMaterialsData); //TODO: Con Multimaterial esta comparacion no anda muy bien. Habria que analizar Textura por Textura en vez de un todo o nada //Son materials identicos if (existingMatId == 0) { //MaterialsData meshExpAppended.MaterialsData = new TgcMaterialData[mExp1.MaterialsData.Length]; Array.Copy(mExp1.MaterialsData, 0, meshExpAppended.MaterialsData, 0, mExp1.MaterialsData.Length); //paths absolutos de DiffuseMaps meshExpAppended.diffuseMapsAbsolutePath = new string[mExp1.diffuseMapsAbsolutePath.Length]; Array.Copy(mExp1.diffuseMapsAbsolutePath, 0, meshExpAppended.diffuseMapsAbsolutePath, 0, mExp1.diffuseMapsAbsolutePath.Length); } //Juntar ambos materials en uno solo Multimaterial else { //MaterialsData meshExpAppended.MaterialsData = new TgcMaterialData[mExp1.MaterialsData.Length + mExp2.MaterialsData.Length]; Array.Copy(mExp1.MaterialsData, 0, meshExpAppended.MaterialsData, 0, mExp1.MaterialsData.Length); Array.Copy(mExp2.MaterialsData, 0, meshExpAppended.MaterialsData, mExp1.MaterialsData.Length, mExp2.MaterialsData.Length); //Aplicar offset a materialsIds del segundo Mesh meshExpAppended.MeshData.materialId = 0; for (int i = triCountMesh1; i < meshExpAppended.MeshData.materialsIds.Length; i++) { meshExpAppended.MeshData.materialsIds[i] += mExp1.MaterialsData.Length; } //Unificar paths absolutos de DiffuseMaps meshExpAppended.diffuseMapsAbsolutePath = new string[mExp1.diffuseMapsAbsolutePath.Length + mExp2.diffuseMapsAbsolutePath.Length]; Array.Copy(mExp1.diffuseMapsAbsolutePath, 0, meshExpAppended.diffuseMapsAbsolutePath, 0, mExp1.diffuseMapsAbsolutePath.Length); Array.Copy(mExp2.diffuseMapsAbsolutePath, 0, meshExpAppended.diffuseMapsAbsolutePath, mExp1.diffuseMapsAbsolutePath.Length, mExp2.diffuseMapsAbsolutePath.Length); } } return meshExpAppended; }
/// <summary> /// Exporta los datos de todas los TgcMesh de una escena. Los exporta a un formato de objetos plano /// </summary> /// <param name="scene">Escena a exportar</param> /// <returns>Datos de la mallas en objetos</returns> public MeshExport[] exportSceneData(TgcScene scene) { MeshExport[] meshesExport = new MeshExport[scene.Meshes.Count]; for (int i = 0; i < scene.Meshes.Count; i++) { meshesExport[i] = exportMeshData(scene.Meshes[i], scene.Meshes); } return meshesExport; }
/// <summary> /// Graba una escena entera del tipo TgcScene a un archivo XML de tipo "-TgcScene.xml", que luego /// puede ser cargado con el TgcSceneLoader /// Antes de generar el XML, unifica todas las mallas en una sola, adaptando sus coordendas de textura y Materials. /// Actualmente no se puede hacer con Mallas que tengan LightMaps. /// </summary> /// <param name="scene">Escena a exportar</param> /// <param name="saveFolderPath">Carpeta en la que se quiera guardar el XML</param> /// <returns>Resultado de exportacion</returns> public ExportResult exportAndAppendSceneToXml(TgcScene scene, string saveFolderPath) { MeshExport meshExportFinal = exportAndAppendSceneData(scene); MeshExport[] meshesExport = new MeshExport[] { meshExportFinal }; return saveSceneToXml(scene.SceneName, createSceneBoundingBox(meshesExport), meshesExport, saveFolderPath); }
/// <summary> /// Toma los datos de un TgcMesh y los exporta a un formato de objetos plano /// </summary> /// <param name="tgcMesh">Malla a exportar</param> /// <returns>Datos de la malla en objetos</returns> public MeshExport exportMeshData(TgcMesh tgcMesh, List<TgcMesh> sceneMeshes) { try { MeshExport meshExport = new MeshExport(); TgcMeshData meshData = new TgcMeshData(); meshExport.MeshData = meshData; meshExport.MaterialsData = null; meshExport.diffuseMapsAbsolutePath = null; //General meshExport.MeshData.name = tgcMesh.Name; meshExport.MeshData.layerName = tgcMesh.Layer; meshExport.MeshRenderType = tgcMesh.RenderType; meshExport.MeshData.pMin = TgcParserUtils.vector3ToFloat3Array(tgcMesh.BoundingBox.PMin); meshExport.MeshData.pMax = TgcParserUtils.vector3ToFloat3Array(tgcMesh.BoundingBox.PMax); meshExport.MeshData.userProperties = tgcMesh.UserProperties; meshExport.MeshData.alphaBlending = tgcMesh.AlphaBlendEnable; //Exportar malla original if (tgcMesh.ParentInstance == null) { meshExport.MeshData.instanceType = TgcMeshData.ORIGINAL; //Exportar segun el tipo de Mesh switch (tgcMesh.RenderType) { case TgcMesh.MeshRenderType.VERTEX_COLOR: exportMeshVertexColor(tgcMesh, meshExport, meshData); break; case TgcMesh.MeshRenderType.DIFFUSE_MAP: exportMeshDiffuseMap(tgcMesh, meshExport, meshData); break; case TgcMesh.MeshRenderType.DIFFUSE_MAP_AND_LIGHTMAP: exportMeshDiffuseMapAndLightmap(tgcMesh, meshExport, meshData); break; } } //Exportar malla instancia else { meshExport.MeshData.instanceType = TgcMeshData.INSTANCE; //Buscar indice de original TgcMesh parentInstance = tgcMesh.ParentInstance; int parentIdx = -1; for (int i = 0; i < sceneMeshes.Count; i++) { if(parentInstance.Equals(sceneMeshes[i])) { parentIdx = i; break; } } meshExport.MeshData.originalMesh = parentIdx; //TODO: la rotación no se exporta correctamente cuando la malla original esta rotada //Posicion, rotacion y escala con diferencia de la malla original meshExport.MeshData.position = TgcParserUtils.vector3ToFloat3Array(tgcMesh.Position - parentInstance.Position); Quaternion rotQuat = Quaternion.RotationYawPitchRoll(tgcMesh.Rotation.Y, tgcMesh.Rotation.X, tgcMesh.Rotation.Z); Quaternion parentRotQuat = Quaternion.RotationYawPitchRoll(parentInstance.Rotation.Y, parentInstance.Rotation.X, parentInstance.Rotation.Z); meshExport.MeshData.rotation = TgcParserUtils.quaternionToFloat4Array(rotQuat - parentRotQuat); Vector3 scale = new Vector3( tgcMesh.Scale.X / parentInstance.Scale.X, tgcMesh.Scale.Y / parentInstance.Scale.Y, tgcMesh.Scale.Z / parentInstance.Scale.Z ); meshExport.MeshData.scale = TgcParserUtils.vector3ToFloat3Array(scale); } return meshExport; } catch (Exception ex) { throw new Exception("Error al intentar obtener datos de Mesh para exportar. MeshName: " + tgcMesh.Name, ex); } }
/// <summary> /// Busca si existe un Material similar a este. /// Devuelve el indice encontrado o -1 /// </summary> private int searchSameMaterial(MeshExport meshExport, List<MeshExport> unifiedMaterialsData) { for (int i = 0; i < unifiedMaterialsData.Count; i++) { MeshExport mExp = unifiedMaterialsData[i]; if (mExp != meshExport && mExp.MaterialsData.Length == meshExport.MaterialsData.Length) { //Standardmaterial if (meshExport.MaterialsData.Length == 1) { if (equalsMaterial(mExp.MaterialsData[0], meshExport.MaterialsData[0])) { return i; } } //Multimaterial else { for (int j = 0; j < meshExport.MaterialsData.Length; j++) { if (!equalsMaterial(mExp.MaterialsData[j], meshExport.MaterialsData[j])) { return -1; } } return i; } } } return -1; }
/// <summary> /// Exportar datos de Mesh de tipo TgcMesh.MeshRenderType.VERTEX_COLOR /// </summary> private void exportMeshVertexColor(TgcMesh tgcMesh, MeshExport meshExport, TgcMeshData meshData) { //Marcar todo lo que no tiene meshData.lightmap = null; meshData.texCoordinatesIndices = new int[0]; meshData.textureCoordinates = new float[0]; meshData.texCoordinatesIndicesLightMap = new int[0]; meshData.textureCoordinatesLightMap = new float[0]; meshExport.MaterialsData = null; meshExport.diffuseMapsAbsolutePath = null; meshExport.lightmapAbsolutePath = null; meshData.materialId = -1; meshData.materialsIds = new int[0]; //Color general Color defaultColor = Color.White; ColorValue defaultColorValue = ColorValue.FromColor(defaultColor); meshData.color = new float[] { defaultColorValue.Red, defaultColorValue.Green, defaultColorValue.Blue }; //Obtener datos del VertexBuffer TgcSceneLoader.VertexColorVertex[] vbData = (TgcSceneLoader.VertexColorVertex[])tgcMesh.D3dMesh.LockVertexBuffer( typeof(TgcSceneLoader.VertexColorVertex), LockFlags.ReadOnly, tgcMesh.D3dMesh.NumberVertices); tgcMesh.D3dMesh.UnlockVertexBuffer(); short[] indices = (short[])tgcMesh.D3dMesh.LockIndexBuffer(typeof(short), LockFlags.ReadOnly, tgcMesh.D3dMesh.NumberFaces * 3); tgcMesh.D3dMesh.UnlockIndexBuffer(); //Armar buffer de vertices, normales y coordenadas de textura, buscando similitudes de valores List<int> coordinatesIndices = new List<int>(); List<int> colorIndices = new List<int>(); List<Vector3> verticesCoordinates = new List<Vector3>(); List<int> verticesColors = new List<int>(); List<Vector3> verticesNormals = new List<Vector3>(); for (int i = 0; i < indices.Length; i++) { TgcSceneLoader.VertexColorVertex vertexData = vbData[indices[i]]; Vector3 position = Vector3.TransformCoordinate(vertexData.Position, tgcMesh.Transform); int coordIdx = addVertex(coordinatesIndices, verticesCoordinates, position); addNormal(verticesNormals, coordIdx, vertexData.Normal); addColor(colorIndices, verticesColors, vertexData.Color); } //Cargar array de vertices meshData.coordinatesIndices = coordinatesIndices.ToArray(); meshData.verticesCoordinates = new float[verticesCoordinates.Count * 3]; for (int i = 0; i < verticesCoordinates.Count; i++) { Vector3 v = verticesCoordinates[i]; meshData.verticesCoordinates[i * 3] = v.X; meshData.verticesCoordinates[i * 3 + 1] = v.Y; meshData.verticesCoordinates[i * 3 + 2] = v.Z; } //Cargar array de normales meshData.verticesNormals = new float[verticesNormals.Count * 3]; for (int i = 0; i < verticesNormals.Count; i++) { Vector3 n = verticesNormals[i]; meshData.verticesNormals[i * 3] = n.X; meshData.verticesNormals[i * 3 + 1] = n.Y; meshData.verticesNormals[i * 3 + 2] = n.Z; } //Cargar array de colores meshData.colorIndices = colorIndices.ToArray(); meshData.verticesColors = new int[verticesColors.Count * 3]; for (int i = 0; i < verticesColors.Count; i++) { Color c = Color.FromArgb(verticesColors[i]); meshData.verticesColors[i * 3] = c.R; meshData.verticesColors[i * 3 + 1] = c.G; meshData.verticesColors[i * 3 + 2] = c.B; } }
/// <summary> /// Exportar datos de Mesh de formato TgcMesh.MeshRenderType.DIFFUSE_MAP_AND_LIGHTMAP /// </summary> private void exportMeshDiffuseMapAndLightmap(TgcMesh tgcMesh, MeshExport meshExport, TgcMeshData meshData) { //Obtener datos del VertexBuffer TgcSceneLoader.DiffuseMapAndLightmapVertex[] vbData = (TgcSceneLoader.DiffuseMapAndLightmapVertex[])tgcMesh.D3dMesh.LockVertexBuffer( typeof(TgcSceneLoader.DiffuseMapAndLightmapVertex), LockFlags.ReadOnly, tgcMesh.D3dMesh.NumberVertices); tgcMesh.D3dMesh.UnlockVertexBuffer(); short[] indices = (short[])tgcMesh.D3dMesh.LockIndexBuffer(typeof(short), LockFlags.ReadOnly, tgcMesh.D3dMesh.NumberFaces * 3); tgcMesh.D3dMesh.UnlockIndexBuffer(); //Color general Color defaultColor = Color.White; ColorValue defaultColorValue = ColorValue.FromColor(defaultColor); meshData.color = new float[] { defaultColorValue.Red, defaultColorValue.Green, defaultColorValue.Blue }; //Armar buffer de vertices, normales y coordenadas de textura, buscando similitudes de valores List<int> coordinatesIndices = new List<int>(); List<int> texCoordinatesIndices = new List<int>(); List<int> texCoordinatesIndicesLightMap = new List<int>(); List<Vector3> verticesCoordinates = new List<Vector3>(); List<Vector2> textureCoordinates = new List<Vector2>(); List<Vector2> textureCoordinatesLightMap = new List<Vector2>(); List<Vector3> verticesNormals = new List<Vector3>(); List<int> colorIndices = new List<int>(); List<int> verticesColors = new List<int>(); for (int i = 0; i < indices.Length; i++) { TgcSceneLoader.DiffuseMapAndLightmapVertex vertexData = vbData[indices[i]]; Vector3 position = Vector3.TransformCoordinate(vertexData.Position, tgcMesh.Transform); int coordIdx = addVertex(coordinatesIndices, verticesCoordinates, position); addNormal(verticesNormals, coordIdx, vertexData.Normal); addTextureCoordinates(texCoordinatesIndices, textureCoordinates, new Vector2(vertexData.Tu0, vertexData.Tv0)); addTextureCoordinates(texCoordinatesIndicesLightMap, textureCoordinatesLightMap, new Vector2(vertexData.Tu1, vertexData.Tv1)); addColor(colorIndices, verticesColors, vertexData.Color); } //Cargar array de vertices meshData.coordinatesIndices = coordinatesIndices.ToArray(); meshData.verticesCoordinates = new float[verticesCoordinates.Count * 3]; for (int i = 0; i < verticesCoordinates.Count; i++) { Vector3 v = verticesCoordinates[i]; meshData.verticesCoordinates[i * 3] = v.X; meshData.verticesCoordinates[i * 3 + 1] = v.Y; meshData.verticesCoordinates[i * 3 + 2] = v.Z; } //Cargar array de normales meshData.verticesNormals = new float[verticesNormals.Count * 3]; for (int i = 0; i < verticesNormals.Count; i++) { Vector3 n = verticesNormals[i]; meshData.verticesNormals[i * 3] = n.X; meshData.verticesNormals[i * 3 + 1] = n.Y; meshData.verticesNormals[i * 3 + 2] = n.Z; } //Cargar array de coordenadas de textura meshData.texCoordinatesIndices = texCoordinatesIndices.ToArray(); meshData.textureCoordinates = new float[textureCoordinates.Count * 2]; for (int i = 0; i < textureCoordinates.Count; i++) { Vector2 t = textureCoordinates[i]; meshData.textureCoordinates[i * 2] = t.X; meshData.textureCoordinates[i * 2 + 1] = t.Y; } //Cargar array de coordenadas de textura de Lightmap meshData.texCoordinatesIndicesLightMap = texCoordinatesIndicesLightMap.ToArray(); meshData.textureCoordinatesLightMap = new float[textureCoordinatesLightMap.Count * 2]; for (int i = 0; i < textureCoordinatesLightMap.Count; i++) { Vector2 t = textureCoordinatesLightMap[i]; meshData.textureCoordinatesLightMap[i * 2] = t.X; meshData.textureCoordinatesLightMap[i * 2 + 1] = t.Y; } //Cargar array de colores meshData.colorIndices = colorIndices.ToArray(); meshData.verticesColors = new int[verticesColors.Count * 3]; for (int i = 0; i < verticesColors.Count; i++) { Color c = Color.FromArgb(verticesColors[i]); meshData.verticesColors[i * 3] = c.R; meshData.verticesColors[i * 3 + 1] = c.G; meshData.verticesColors[i * 3 + 2] = c.B; } //Exportar Materials y DiffuseMaps exportMaterialData(tgcMesh, meshExport, meshData); //Exportar Lightmap TgcTexture tgcLightmap = tgcMesh.LightMap; meshData.lightmap = tgcLightmap.FileName; meshExport.lightmapAbsolutePath = tgcLightmap.FilePath; }
/// <summary> /// Exportar datos de Material /// </summary> private void exportMaterialData(TgcMesh tgcMesh, MeshExport meshExport, TgcMeshData meshData) { //Exportar diffuseMap y material simple bool alphaBlendEnabled = false; if (tgcMesh.Materials.Length == 1) { TgcMaterialData materialData = new TgcMaterialData(); meshExport.MaterialsData = new TgcMaterialData[] { materialData }; //Material Material tgcMaterial = tgcMesh.Materials[0]; materialData.type = TgcMaterialData.StandardMaterial; materialData.name = TgcMaterialData.StandardMaterial; materialData.subMaterials = null; materialData.ambientColor = new float[]{ tgcMaterial.AmbientColor.Red, tgcMaterial.AmbientColor.Green, tgcMaterial.AmbientColor.Blue, tgcMaterial.AmbientColor.Alpha, }; materialData.diffuseColor = new float[]{ tgcMaterial.DiffuseColor.Red, tgcMaterial.DiffuseColor.Green, tgcMaterial.DiffuseColor.Blue, tgcMaterial.DiffuseColor.Alpha, }; materialData.specularColor = new float[]{ tgcMaterial.SpecularColor.Red, tgcMaterial.SpecularColor.Green, tgcMaterial.SpecularColor.Blue, tgcMaterial.SpecularColor.Alpha, }; materialData.opacity = 1f; materialData.alphaBlendEnable = tgcMesh.AlphaBlendEnable; //Texture TgcTexture tgcTexture = tgcMesh.DiffuseMaps[0]; materialData.fileName = tgcTexture.FileName; materialData.uvOffset = new float[] { 1f, 1f }; materialData.uvTiling = new float[] { 1f, 1f }; meshExport.diffuseMapsAbsolutePath = new string[] { tgcTexture.FilePath }; //Configurar mesh meshData.materialId = 0; meshData.materialsIds = new int[] { meshData.materialId }; } //Exportar varios diffuseMaps y materials else { meshExport.MaterialsData = new TgcMaterialData[tgcMesh.Materials.Length]; meshExport.diffuseMapsAbsolutePath = new string[tgcMesh.Materials.Length]; for (int i = 0; i < tgcMesh.Materials.Length; i++) { //Material Material tgcMaterial = tgcMesh.Materials[i]; TgcMaterialData materialData = new TgcMaterialData(); meshExport.MaterialsData[i] = materialData; materialData.type = TgcMaterialData.StandardMaterial; materialData.name = TgcMaterialData.StandardMaterial; materialData.subMaterials = null; materialData.ambientColor = new float[]{ tgcMaterial.AmbientColor.Red, tgcMaterial.AmbientColor.Green, tgcMaterial.AmbientColor.Blue, tgcMaterial.AmbientColor.Alpha, }; materialData.diffuseColor = new float[]{ tgcMaterial.DiffuseColor.Red, tgcMaterial.DiffuseColor.Green, tgcMaterial.DiffuseColor.Blue, tgcMaterial.DiffuseColor.Alpha, }; materialData.specularColor = new float[]{ tgcMaterial.SpecularColor.Red, tgcMaterial.SpecularColor.Green, tgcMaterial.SpecularColor.Blue, tgcMaterial.SpecularColor.Alpha, }; materialData.opacity = 1f; materialData.alphaBlendEnable = tgcMesh.AlphaBlendEnable; //Texture TgcTexture tgcTexture = tgcMesh.DiffuseMaps[i]; materialData.fileName = tgcTexture.FileName; materialData.uvOffset = new float[] { 1f, 1f }; materialData.uvTiling = new float[] { 1f, 1f }; meshExport.diffuseMapsAbsolutePath[i] = tgcTexture.FilePath; } //Configurar Mesh meshData.materialId = 0; meshData.materialsIds = tgcMesh.D3dMesh.LockAttributeBufferArray(LockFlags.ReadOnly); tgcMesh.D3dMesh.UnlockAttributeBuffer(); } }
/// <summary> /// Crear BoundingBox para escena /// </summary> private TgcBoundingBox createSceneBoundingBox(MeshExport[] meshesExport) { List<TgcBoundingBox> boundingBoxes = new List<TgcBoundingBox>(); foreach (MeshExport m in meshesExport) { boundingBoxes.Add(new TgcBoundingBox( TgcParserUtils.float3ArrayToVector3(m.MeshData.pMin), TgcParserUtils.float3ArrayToVector3(m.MeshData.pMax))); } return TgcBoundingBox.computeFromBoundingBoxes(boundingBoxes); }