protected override Scenery Read(ContentReader input, Scenery existingInstance) { Scenery scenery = existingInstance; if (scenery == null) { scenery = new Scenery(); } scenery.Terrain = input.ReadObject <Texture2D>(); scenery.TerrainBufferDeclaration = input.ReadObject <VertexDeclaration>(); scenery.TerrainBufferVertexStride = input.ReadInt32(); scenery.TerrainBuffer = input.ReadObject <VertexBuffer>(); scenery.TerrainBufferVertexCount = input.ReadInt32(); List <SceneryTriangleNode> nodes = new List <SceneryTriangleNode>(); int nodeCount = input.ReadInt32(); for (int i = 0; i < nodeCount; i++) { SceneryTriangleNode node = input.ReadObject <SceneryTriangleNode>(); nodes.Add(node); } SceneryNode root = BuildQuadtree(nodes.ToArray()); scenery.Root = root; scenery.TerrainIndexBuffers.Add(LOD.High, input.ReadObject <IndexBuffer>()); scenery.TerrainIndexBuffers.Add(LOD.Medium, input.ReadObject <IndexBuffer>()); scenery.TerrainIndexBuffers.Add(LOD.Low, input.ReadObject <IndexBuffer>()); scenery.Effect = input.ReadObject <Effect>(); scenery.Texture1 = input.ReadObject <Texture2D>(); scenery.Texture2 = input.ReadObject <Texture2D>(); scenery.Texture3 = input.ReadObject <Texture2D>(); scenery.Texture4 = input.ReadObject <Texture2D>(); scenery.DetailTexture1 = input.ReadObject <Texture2D>(); scenery.DetailTexture2 = input.ReadObject <Texture2D>(); scenery.DetailTexture3 = input.ReadObject <Texture2D>(); scenery.DetailTexture4 = input.ReadObject <Texture2D>(); //Leer el efecto para renderizar billboards scenery.BillboardEffect = input.ReadObject <Effect>(); scenery.BillboardGrassTexture = input.ReadObject <Texture2D>(); scenery.BillboardTreeTexture = input.ReadObject <Texture2D>(); return(scenery); }
/// <summary> /// Dibuja el contenido gráfico del componente atendiendo al nivel de detalle /// </summary> /// <param name="device">Dispositivo gráfico</param> /// <param name="gameTime">Tiempo de juego</param> /// <param name="nodesToDraw">Lista de nodos a dibujar</param> /// <param name="lod">Nivel de detalle</param> private void LODDraw(GraphicsDevice device, GameTime gameTime, SceneryNode[] nodesToDraw, LOD lod) { if (nodesToDraw != null && nodesToDraw.Length > 0) { // Comprobar si el nodo se debe dibujar if ((this.LevelOfDetail != LOD.None) && (this.LevelOfDetail != lod)) { return; } // Establecer los índices según el nivel de detalle device.Indices = this.TerrainIndexBuffers[lod]; // Cantidad de vértices del buffer int vertexCount = this.TerrainBufferVertexCount; this.Effect.Begin(); foreach (EffectPass pass in this.Effect.CurrentTechnique.Passes) { pass.Begin(); foreach (SceneryNode node in nodesToDraw) { SceneryTriangleNode triNode = node as SceneryTriangleNode; if (triNode != null) { int centerPrimitiveCount = triNode.IndexInfo[lod].CenterPrimitiveCount; int borderConnectionPrimitiveCount = triNode.IndexInfo[lod].BorderConnectionPrimitiveCount; int borderPrimitiveCount = triNode.IndexInfo[lod].BorderPrimitiveCount; // Dibujar el centro this.DrawNodePart( device, triNode.IndexInfo[lod].CenterOffset, vertexCount, centerPrimitiveCount); // Dibujar los bordes si es necesario if (borderPrimitiveCount > 0 || borderConnectionPrimitiveCount > 0) { if (triNode.IsNorthBorder) { // Dibujar la conexión norte this.DrawNodePart( device, triNode.IndexInfo[lod].NorthConnectionOffset, vertexCount, borderConnectionPrimitiveCount); } else { // Dibujar el norte this.DrawNodePart( device, triNode.IndexInfo[lod].NorthOffset, vertexCount, borderPrimitiveCount); } if (triNode.IsSouthBorder) { // Dibujar la conexión norte this.DrawNodePart( device, triNode.IndexInfo[lod].SouthConnectionOffset, vertexCount, borderConnectionPrimitiveCount); } else { // Dibujar el norte this.DrawNodePart( device, triNode.IndexInfo[lod].SouthOffset, vertexCount, borderPrimitiveCount); } if (triNode.IsWestBorder) { // Dibujar la conexión norte this.DrawNodePart( device, triNode.IndexInfo[lod].WestConnectionOffset, vertexCount, borderConnectionPrimitiveCount); } else { // Dibujar el norte this.DrawNodePart( device, triNode.IndexInfo[lod].WestOffset, vertexCount, borderPrimitiveCount); } if (triNode.IsEastBorder) { // Dibujar la conexión norte this.DrawNodePart( device, triNode.IndexInfo[lod].EastConnectionOffset, vertexCount, borderConnectionPrimitiveCount); } else { // Dibujar el norte this.DrawNodePart( device, triNode.IndexInfo[lod].EastOffset, vertexCount, borderPrimitiveCount); } } } } pass.End(); } this.Effect.End(); } }
/// <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, }); }