/// <summary> /// Procesar el mapa de alturas /// </summary> /// <param name="input">Información del escenario de entrada</param> /// <param name="context">Contexto de procesado</param> /// <returns>Devuelve la información de escenario leída</returns> public override SceneryInfo Process(SceneryFile input, ContentProcessorContext context) { // Cargar la textura del mapa de alturas Texture2DContent terrain = context.BuildAndLoadAsset <Texture2DContent, Texture2DContent>(new ExternalReference <Texture2DContent>(input.HeightMapFile), null); // Obtener el mapa de alturas HeightMap heightMap = this.BuildHeightMap(terrain, input.HeightMapCellScale, context); // Generar los vértices e inicializar el buffer de vértices VertexMultitextured[] vertList = heightMap.BuildVertices( input.HeightMapCellSize, input.ProportionTexture1, input.ProportionTexture2, input.ProportionTexture3); VertexBufferContent vertexBuffer = new VertexBufferContent(VertexMultitextured.SizeInBytes * vertList.Length); vertexBuffer.Write <VertexMultitextured>(0, VertexMultitextured.SizeInBytes, vertList, context.TargetPlatform); // Generar los índices e inicializar los buffers de índices double lowOrderLevels = (Math.Sqrt(heightMap.DataLength) - 1) * 0.5f; int levelCount = Convert.ToInt32(Math.Log(lowOrderLevels, 4.0d)); SceneryNodeInfo sceneryIndexInfo = SceneryNodeInfo.Build( vertList, heightMap.Width, heightMap.Deep, levelCount); // Efecto de renderización CompiledEffect effect = Effect.CompileEffectFromFile( input.EffectFile, null, null, CompilerOptions.None, context.TargetPlatform); // Texturas del terreno Texture2DContent texture1 = context.BuildAndLoadAsset <Texture2DContent, Texture2DContent>(new ExternalReference <Texture2DContent>(input.Texture1File), null); Texture2DContent texture2 = context.BuildAndLoadAsset <Texture2DContent, Texture2DContent>(new ExternalReference <Texture2DContent>(input.Texture2File), null); Texture2DContent texture3 = context.BuildAndLoadAsset <Texture2DContent, Texture2DContent>(new ExternalReference <Texture2DContent>(input.Texture3File), null); Texture2DContent texture4 = context.BuildAndLoadAsset <Texture2DContent, Texture2DContent>(new ExternalReference <Texture2DContent>(input.Texture4File), null); Texture2DContent detailTexture1 = context.BuildAndLoadAsset <Texture2DContent, Texture2DContent>(new ExternalReference <Texture2DContent>(input.DetailTexture1File), null); Texture2DContent detailTexture2 = context.BuildAndLoadAsset <Texture2DContent, Texture2DContent>(new ExternalReference <Texture2DContent>(input.DetailTexture2File), null); Texture2DContent detailTexture3 = context.BuildAndLoadAsset <Texture2DContent, Texture2DContent>(new ExternalReference <Texture2DContent>(input.DetailTexture3File), null); Texture2DContent detailTexture4 = context.BuildAndLoadAsset <Texture2DContent, Texture2DContent>(new ExternalReference <Texture2DContent>(input.DetailTexture4File), null); CompiledEffect billboardEffect = Effect.CompileEffectFromFile( input.BillboardEffectFile, null, null, CompilerOptions.None, context.TargetPlatform); Texture2DContent billboardGrassTexture = context.BuildAndLoadAsset <Texture2DContent, Texture2DContent>(new ExternalReference <Texture2DContent>(input.BillboardGrassTextureFile), null); Texture2DContent billboardTreeTexture = context.BuildAndLoadAsset <Texture2DContent, Texture2DContent>(new ExternalReference <Texture2DContent>(input.BillboardTreeTextureFile), null); int billboardsPerTriangle = input.BillboardsPerTriangle; float billboardTreesPercent = input.BillboardTreesPercent; return(new SceneryInfo() { Terrain = terrain, TerrainBuffer = vertexBuffer, TerrainBufferVertexCount = vertList.Length, TerrainInfo = sceneryIndexInfo, Effect = effect, Texture1 = texture1, Texture2 = texture2, Texture3 = texture3, Texture4 = texture4, DetailTexture1 = detailTexture1, DetailTexture2 = detailTexture2, DetailTexture3 = detailTexture3, DetailTexture4 = detailTexture4, BillboardEffect = billboardEffect, BillboardGrass = billboardGrassTexture, BillboardTree = billboardTreeTexture, BillboardsPerTriangle = billboardsPerTriangle, BillboardTreesPercent = billboardTreesPercent, }); }
/// <summary> /// Construye la información de nodos del terreno /// </summary> /// <param name="vertList">Lista de vértices</param> /// <param name="width">Anchura del terreno</param> /// <param name="deep">Profundidad del terreno</param> /// <param name="levels">Niveles distintos de detalle</param> /// <returns>Devuelve la información de nodos del terreno</returns> public static SceneryNodeInfo Build( VertexMultitextured[] vertList, int width, int deep, int levels) { // Lista resultante de nodos List <SceneryTriangleNode> nodes = new List <SceneryTriangleNode>(); // Diccionario de índices Dictionary <LOD, IndexCollection> indices = new Dictionary <LOD, IndexCollection>(); IndexCollection highIndices = new IndexCollection(); IndexCollection mediumIndices = new IndexCollection(); IndexCollection lowIndices = new IndexCollection(); // Tamaño de la cuadrícula int totalCellsX = width; int totalCellsZ = deep; // Número de divisiones int divisions = Convert.ToInt32(Math.Pow(4, levels)); int divisionsX = divisions / 2; int divisionsZ = divisions / 2; // Número de vértices en X y en Z int numVertexesX = (totalCellsX / divisionsX); int numVertexesZ = (totalCellsZ / divisionsZ); // Número total de vértices, triángulos e índices int totalVertices = totalCellsX * totalCellsZ; int totalTriangles = (totalCellsX - 1) * (totalCellsZ - 1) * 2; int totalIndices = totalTriangles * 3; for (int x = 0; x < divisionsX; x++) { int offsetX = x * numVertexesX; int cellsX = numVertexesX; for (int z = 0; z < divisionsZ; z++) { int offsetZ = z * numVertexesZ; int cellsZ = numVertexesZ; // Crear índices para generar la lista de triángulos de colisión int[] collisionIndices = SceneryNodeInfo.CreateCollisionIndices( offsetX, offsetZ, cellsX, cellsZ, totalCellsX, totalCellsZ); // Crear la lista de triángulos Triangle[] quadTriangles = SceneryNodeInfo.BuildPrimitiveList(vertList, collisionIndices); // Crear los índices para alta resolución SceneryNodeIndexInfo quadHighInfo = null; Int32[] quadHighIndices = Build( LOD.High, highIndices.Count, offsetX, offsetZ, cellsX, cellsZ, totalCellsX, totalCellsZ, out quadHighInfo); // Crear los índices para media resolución SceneryNodeIndexInfo quadMediumInfo = null; Int32[] quadMediumIndices = Build( LOD.Medium, mediumIndices.Count, offsetX, offsetZ, cellsX, cellsZ, totalCellsX, totalCellsZ, out quadMediumInfo); // Crear los índices para baja resolución SceneryNodeIndexInfo quadLowInfo = null; Int32[] quadLowIndices = Build( LOD.Low, lowIndices.Count, offsetX, offsetZ, cellsX, cellsZ, totalCellsX, totalCellsZ, out quadLowInfo); // Añadir los índices a la colección de índices para cada resolución highIndices.AddRange(quadHighIndices); mediumIndices.AddRange(quadMediumIndices); lowIndices.AddRange(quadLowIndices); Dictionary <LOD, SceneryNodeIndexInfo> info = new Dictionary <LOD, SceneryNodeIndexInfo>(); info.Add(LOD.High, quadHighInfo); info.Add(LOD.Medium, quadMediumInfo); info.Add(LOD.Low, quadLowInfo); // Crear el nodo con los triángulos para la colisión, los índices de inicio y el número de triángulos para cada resolución SceneryTriangleNode newQuadNode = new SceneryTriangleNode(quadTriangles, info); nodes.Add(newQuadNode); } } // Crear el diccionario de buffers de índices para cada resolución indices = new Dictionary <LOD, IndexCollection>(); indices.Add(LOD.High, highIndices); indices.Add(LOD.Medium, mediumIndices); indices.Add(LOD.Low, lowIndices); // Devolver la información de nodos del escenario return(new SceneryNodeInfo() { Nodes = nodes.ToArray(), Indices = indices, }); }