SkyProcessor.cs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. #region File Description
  2. //-----------------------------------------------------------------------------
  3. // SkyProcessor.cs
  4. //
  5. // Microsoft XNA Community Game Platform
  6. // Copyright (C) Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #endregion
  9. #region Using Statements
  10. using System;
  11. using System.IO;
  12. using System.Collections.Generic;
  13. using Microsoft.Xna.Framework;
  14. using Microsoft.Xna.Framework.Content.Pipeline;
  15. using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
  16. using Microsoft.Xna.Framework.Content.Pipeline.Processors;
  17. #endregion
  18. namespace GeneratedGeometryPipeline
  19. {
  20. /// <summary>
  21. /// Custom content processor for creating skydome meshes. Given an
  22. /// input sky texture, this processor uses the MeshBuilder class to
  23. /// programatically generate skydome geometry. It creates a cylinder,
  24. /// texture maps the sky image around it, and assigns a custom effect
  25. /// that will be used to render the sky.
  26. /// </summary>
  27. [ContentProcessor]
  28. public class SkyProcessor : ContentProcessor<Texture2DContent, SkyContent>
  29. {
  30. const float cylinderSize = 100;
  31. const int cylinderSegments = 32;
  32. const float texCoordTop = 0.1f;
  33. const float texCoordBottom = 0.9f;
  34. /// <summary>
  35. /// Generates skydome geometry for an input sky texture.
  36. /// </summary>
  37. public override SkyContent Process(Texture2DContent input,
  38. ContentProcessorContext context)
  39. {
  40. MeshBuilder builder = MeshBuilder.StartMesh("sky");
  41. // Create two rings of vertices around the top and bottom of the cylinder.
  42. List<int> topVertices = new List<int>();
  43. List<int> bottomVertices = new List<int>();
  44. for (int i = 0; i < cylinderSegments; i++)
  45. {
  46. float angle = MathHelper.TwoPi * i / cylinderSegments;
  47. float x = (float)Math.Cos(angle) * cylinderSize;
  48. float z = (float)Math.Sin(angle) * cylinderSize;
  49. topVertices.Add(builder.CreatePosition(x, cylinderSize, z));
  50. bottomVertices.Add(builder.CreatePosition(x, -cylinderSize, z));
  51. }
  52. // Create two center vertices, used for closing the top and bottom.
  53. int topCenterVertex = builder.CreatePosition(0, cylinderSize * 2, 0);
  54. int bottomCenterVertex = builder.CreatePosition(0, -cylinderSize * 2, 0);
  55. // Create a vertex channel for holding texture coordinates.
  56. int texCoordId = builder.CreateVertexChannel<Vector2>(
  57. VertexChannelNames.TextureCoordinate(0));
  58. builder.SetMaterial(new BasicMaterialContent());
  59. // Create the individual triangles that make up our skydome.
  60. for (int i = 0; i < cylinderSegments; i++)
  61. {
  62. int j = (i + 1) % cylinderSegments;
  63. // Calculate texture coordinates for this segment of the cylinder.
  64. float u1 = (float)i / (float)cylinderSegments;
  65. float u2 = (float)(i + 1) / (float)cylinderSegments;
  66. // Two triangles form a quad, one side segment of the cylinder.
  67. AddVertex(builder, topVertices[i], texCoordId, u1, texCoordTop);
  68. AddVertex(builder, topVertices[j], texCoordId, u2, texCoordTop);
  69. AddVertex(builder, bottomVertices[i], texCoordId, u1, texCoordBottom);
  70. AddVertex(builder, topVertices[j], texCoordId, u2, texCoordTop);
  71. AddVertex(builder, bottomVertices[j], texCoordId, u2, texCoordBottom);
  72. AddVertex(builder, bottomVertices[i], texCoordId, u1, texCoordBottom);
  73. // Triangle fanning inward to fill the top above this segment.
  74. AddVertex(builder, topCenterVertex, texCoordId, u1, 0);
  75. AddVertex(builder, topVertices[j], texCoordId, u2, texCoordTop);
  76. AddVertex(builder, topVertices[i], texCoordId, u1, texCoordTop);
  77. // Triangle fanning inward to fill the bottom below this segment.
  78. AddVertex(builder, bottomCenterVertex, texCoordId, u1, 1);
  79. AddVertex(builder, bottomVertices[i], texCoordId, u1, texCoordBottom);
  80. AddVertex(builder, bottomVertices[j], texCoordId, u2, texCoordBottom);
  81. }
  82. // Create the output object.
  83. SkyContent sky = new SkyContent();
  84. // Chain to the ModelProcessor so it can convert the mesh we just generated.
  85. MeshContent skyMesh = builder.FinishMesh();
  86. sky.Model = context.Convert<MeshContent, ModelContent>(skyMesh,
  87. "ModelProcessor");
  88. // Chain to the TextureProcessor so it can convert the sky
  89. // texture. We don't use the default ModelTextureProcessor
  90. // here, because that would apply DXT compression, which
  91. // doesn't usually look very good with sky images.
  92. // Note: This could also be accomplished by creating a custom ModelProcessor
  93. // that would process its textures with the default TextureProcessor,
  94. // and adding the sky texture to the materials Textures dictionary.
  95. // For simplicity, the approach below is used instead.
  96. sky.Texture = context.Convert<TextureContent, TextureContent>(input,
  97. "TextureProcessor");
  98. return sky;
  99. }
  100. /// <summary>
  101. /// Helper for adding a new triangle vertex to a MeshBuilder,
  102. /// along with an associated texture coordinate value.
  103. /// </summary>
  104. static void AddVertex(MeshBuilder builder, int vertex,
  105. int texCoordId, float u, float v)
  106. {
  107. builder.SetVertexChannelData(texCoordId, new Vector2(u, v));
  108. builder.AddTriangleVertex(vertex);
  109. }
  110. }
  111. }