VertexLighting.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. #region File Description
  2. //-----------------------------------------------------------------------------
  3. // VertexLighting.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.Collections.Generic;
  12. using Microsoft.Xna.Framework;
  13. using Microsoft.Xna.Framework.Audio;
  14. using Microsoft.Xna.Framework.Content;
  15. using Microsoft.Xna.Framework.Graphics;
  16. using Microsoft.Xna.Framework.Input;
  17. using Microsoft.Xna.Framework.Storage;
  18. #endregion
  19. namespace VertexLightingSample
  20. {
  21. /// <summary>
  22. /// The central class for the sample Game.
  23. /// </summary>
  24. public class VertexLighting : Microsoft.Xna.Framework.Game
  25. {
  26. #region Sample Fields
  27. private GraphicsDeviceManager graphics;
  28. private SampleArcBallCamera camera;
  29. private Model[] sampleMeshes;
  30. private SampleGrid grid;
  31. private int activeMesh;
  32. private bool enableAdvancedEffect = true;
  33. private GamePadState lastGpState;
  34. private KeyboardState lastKbState;
  35. #endregion
  36. /// <summary>
  37. /// Example 1.1: Effect objects used for this example
  38. /// </summary>
  39. #region Effect Fields
  40. private Effect noLightingEffect;
  41. private Effect vertexLightingEffect;
  42. private EffectParameter projectionParameter;
  43. private EffectParameter viewParameter;
  44. private EffectParameter worldParameter;
  45. private EffectParameter lightColorParameter;
  46. private EffectParameter lightDirectionParameter;
  47. private EffectParameter ambientColorParameter;
  48. #endregion
  49. /// <summary>
  50. /// Example 1.2: Data fields corresponding to the effect paramters
  51. /// </summary>
  52. #region Uniform Data Fields
  53. private Matrix world, view, projection;
  54. private Vector3 diffuseLightDirection;
  55. private Vector4 diffuseLightColor;
  56. private Vector4 ambientLightColor;
  57. #endregion
  58. #region Initialization and Cleanup
  59. public VertexLighting()
  60. {
  61. graphics = new GraphicsDeviceManager(this);
  62. Content.RootDirectory = "Content";
  63. }
  64. /// <summary>
  65. /// Initialize the sample.
  66. /// </summary>
  67. protected override void Initialize()
  68. {
  69. base.Initialize();
  70. }
  71. /// <summary>
  72. /// Load the graphics content.
  73. /// </summary>
  74. protected override void LoadContent()
  75. {
  76. //Set up the reference grid and sample camera
  77. grid = new SampleGrid();
  78. grid.GridColor = Color.LimeGreen;
  79. grid.GridScale = 1.0f;
  80. grid.GridSize = 32;
  81. grid.LoadGraphicsContent(graphics.GraphicsDevice);
  82. camera = new SampleArcBallCamera(
  83. SampleArcBallCameraMode.RollConstrained);
  84. camera.Distance = 3;
  85. //orbit the camera so we're looking down the z=-1 axis
  86. //the acr-ball camera is traditionally oriented to look
  87. //at the "front" of an object
  88. camera.OrbitRight(MathHelper.Pi);
  89. //orbit up a bit for perspective
  90. camera.OrbitUp(.2f);
  91. sampleMeshes = new Model[5];
  92. //load meshes
  93. sampleMeshes[0] = Content.Load<Model>("Cube");
  94. sampleMeshes[1] = Content.Load<Model>("SphereHighPoly");
  95. sampleMeshes[2] = Content.Load<Model>("SphereLowPoly");
  96. sampleMeshes[3] = Content.Load<Model>("Cylinder");
  97. sampleMeshes[4] = Content.Load<Model>("Cone");
  98. //Example 1.2
  99. //create the effect objects that correspond to the effect files
  100. //that have been imported via the Content Pipeline
  101. noLightingEffect = Content.Load<Effect>("FlatShaded");
  102. vertexLightingEffect = Content.Load<Effect>("VertexLighting");
  103. GetEffectParameters();
  104. //Calculate the projection properties first on any
  105. //load callback. That way if the window gets resized,
  106. //the perspective matrix is updated accordingly
  107. float aspectRatio = (float)graphics.GraphicsDevice.Viewport.Width /
  108. (float)graphics.GraphicsDevice.Viewport.Height;
  109. float fov = MathHelper.PiOver4 * aspectRatio * 3 / 4;
  110. projection = Matrix.CreatePerspectiveFieldOfView(fov,
  111. aspectRatio, .1f, 1000f);
  112. //create a default world matrix
  113. world = Matrix.Identity;
  114. //grid requires a projection matrix to draw correctly
  115. grid.ProjectionMatrix = projection;
  116. //Set the grid to draw on the x/z plane around the origin
  117. grid.WorldMatrix = Matrix.Identity;
  118. }
  119. /// <summary>
  120. /// Example 1.3
  121. /// This function obtains EffectParameter objects from the Effect objects.
  122. /// The EffectParameters are handles to the values in the shaders and are
  123. /// effectively how your C# code and your shader code communicate.
  124. /// </summary>
  125. private void GetEffectParameters()
  126. {
  127. //These parameters are used by both vertexLightingEffect and
  128. //noLightingEffect, so we must take care to look up the correct ones.
  129. if (enableAdvancedEffect)
  130. {
  131. worldParameter = vertexLightingEffect.Parameters["world"];
  132. viewParameter = vertexLightingEffect.Parameters["view"];
  133. projectionParameter = vertexLightingEffect.Parameters["projection"];
  134. }
  135. else
  136. {
  137. worldParameter = noLightingEffect.Parameters["world"];
  138. viewParameter = noLightingEffect.Parameters["view"];
  139. projectionParameter = noLightingEffect.Parameters["projection"];
  140. }
  141. //These effect parameters are only used by vertexLightingEffect
  142. //to indicate the lights' colors and direction
  143. lightColorParameter = vertexLightingEffect.Parameters["lightColor"];
  144. lightDirectionParameter = vertexLightingEffect.Parameters["lightDirection"];
  145. ambientColorParameter = vertexLightingEffect.Parameters["ambientColor"];
  146. }
  147. #endregion
  148. #region Update and Render
  149. /// <summary>
  150. /// Update the game world.
  151. /// </summary>
  152. /// <param name="gameTime">Provides a snapshot of timing values.</param>
  153. protected override void Update(GameTime gameTime)
  154. {
  155. GamePadState gpState = GamePad.GetState(PlayerIndex.One);
  156. KeyboardState kbState = Keyboard.GetState();
  157. //check for exit
  158. if ((gpState.Buttons.Back == ButtonState.Pressed) ||
  159. kbState.IsKeyDown(Keys.Escape))
  160. {
  161. Exit();
  162. }
  163. //Handle inputs for the sample camera
  164. camera.HandleDefaultGamepadControls(
  165. gpState, gameTime);
  166. camera.HandleDefaultKeyboardControls(
  167. kbState, gameTime);
  168. //handle inputs specific to this sample
  169. HandleInput(gameTime, gpState, kbState);
  170. //Set the light direction to a fixed value.
  171. //This will place the light source behind, to the right, and above the user.
  172. diffuseLightDirection = new Vector3(-1, -1, -1);
  173. //ensure the light direction is normalized, or
  174. //the shader will give some weird results
  175. diffuseLightDirection.Normalize();
  176. //set the color of the diffuse light
  177. diffuseLightColor = Color.CornflowerBlue.ToVector4();
  178. //set the ambient lighting color
  179. ambientLightColor = Color.DarkSlateGray.ToVector4();
  180. //The built-in camera class provides the view matrix
  181. view = camera.ViewMatrix;
  182. //additionally, the reference grid included in the sample
  183. //requires a view matrix to draw correctly
  184. grid.ViewMatrix = camera.ViewMatrix;
  185. lastGpState = gpState;
  186. lastKbState = kbState;
  187. base.Update(gameTime);
  188. }
  189. private void HandleInput(GameTime gameTime, GamePadState gpState,
  190. KeyboardState kbState)
  191. {
  192. float elapsedTime = (float) gameTime.ElapsedGameTime.TotalSeconds;
  193. //Handle input for selecting meshes
  194. if (((gpState.Buttons.X == ButtonState.Pressed) &&
  195. (lastGpState.Buttons.X == ButtonState.Released)) ||
  196. (kbState.IsKeyDown(Keys.Tab) && lastKbState.IsKeyUp(Keys.Tab)))
  197. {
  198. //switch the active mesh
  199. activeMesh = (activeMesh + 1) % sampleMeshes.Length;
  200. }
  201. //Handle input for selecting the active effect
  202. if (((gpState.Buttons.Y == ButtonState.Pressed) &&
  203. (lastGpState.Buttons.Y == ButtonState.Released)) ||
  204. (kbState.IsKeyDown(Keys.Space) && lastKbState.IsKeyUp(Keys.Space)))
  205. {
  206. //toggle the advanced effect
  207. enableAdvancedEffect = !enableAdvancedEffect;
  208. GetEffectParameters();
  209. }
  210. //handle mesh rotation inputs
  211. float dx =
  212. SampleArcBallCamera.ReadKeyboardAxis(kbState, Keys.Left, Keys.Right) +
  213. gpState.ThumbSticks.Left.X;
  214. float dy =
  215. SampleArcBallCamera.ReadKeyboardAxis(kbState, Keys.Down, Keys.Up) +
  216. gpState.ThumbSticks.Left.Y;
  217. //apply mesh rotation to world matrix
  218. if (dx != 0)
  219. {
  220. world = world * Matrix.CreateFromAxisAngle(camera.Up,
  221. elapsedTime * dx);
  222. }
  223. if (dy != 0)
  224. {
  225. world = world * Matrix.CreateFromAxisAngle(camera.Right,
  226. elapsedTime * -dy);
  227. }
  228. }
  229. /// <summary>
  230. /// Example 1.4
  231. ///
  232. /// The effect parameters set in this function
  233. /// are shared between all of the rendered elements in the scene.
  234. /// </summary>
  235. private void SetSharedEffectParameters()
  236. {
  237. projectionParameter.SetValue(projection);
  238. viewParameter.SetValue(view);
  239. worldParameter.SetValue(world);
  240. }
  241. /// <summary>
  242. /// Draw the current scene.
  243. /// </summary>
  244. /// <param name="gameTime">Provides a snapshot of timing values.</param>
  245. protected override void Draw(GameTime gameTime)
  246. {
  247. graphics.GraphicsDevice.Clear(Color.Black);
  248. //draw the reference grid so it's easier to get our bearings
  249. grid.Draw();
  250. //always set the shared effects parameters
  251. SetSharedEffectParameters();
  252. if (enableAdvancedEffect)
  253. {
  254. //Example 1.5
  255. //Since we're using the advanced effect, we'll be setting the effect
  256. //parameters for the lighting effect.
  257. ambientColorParameter.SetValue(ambientLightColor);
  258. lightColorParameter.SetValue(diffuseLightColor);
  259. lightDirectionParameter.SetValue(diffuseLightDirection);
  260. }
  261. //finally, draw the mesh itself
  262. DrawSampleMesh(sampleMeshes[activeMesh]);
  263. base.Draw(gameTime);
  264. }
  265. /// <summary>
  266. /// Example 1.6
  267. ///
  268. /// Draws a sample mesh using a single effect with a single technique.
  269. /// This pattern is very common in simple effect usage.
  270. /// </summary>
  271. /// <param name="sampleMesh"></param>
  272. public void DrawSampleMesh(Model sampleMesh)
  273. {
  274. if (sampleMesh == null)
  275. return;
  276. //our sample meshes only contain a single part, so we don't need to bother
  277. //looping over the ModelMesh and ModelMeshPart collections. If the meshes
  278. //were more complex, we would repeat all the following code for each part
  279. ModelMesh mesh = sampleMesh.Meshes[0];
  280. ModelMeshPart meshPart = mesh.MeshParts[0];
  281. //set the vertex source to the mesh's vertex buffer
  282. graphics.GraphicsDevice.SetVertexBuffer(meshPart.VertexBuffer, meshPart.VertexOffset);
  283. //set the current index buffer to the sample mesh's index buffer
  284. graphics.GraphicsDevice.Indices = meshPart.IndexBuffer;
  285. //figure out which effect we're using currently
  286. Effect effect;
  287. if (enableAdvancedEffect) effect = vertexLightingEffect;
  288. else effect = noLightingEffect;
  289. //at this point' we're ready to begin drawing
  290. //now we loop through the passes in the teqnique, drawing each
  291. //one in order
  292. for (int i = 0; i < effect.CurrentTechnique.Passes.Count; i++)
  293. {
  294. //EffectPass.Apply will update the device to
  295. //begin using the state information defined in the current pass
  296. effect.CurrentTechnique.Passes[i].Apply();
  297. //sampleMesh contains all of the information required to draw
  298. //the current mesh
  299. graphics.GraphicsDevice.DrawIndexedPrimitives(
  300. PrimitiveType.TriangleList, 0, 0,
  301. meshPart.NumVertices, meshPart.StartIndex, meshPart.PrimitiveCount);
  302. }
  303. }
  304. #endregion
  305. #region Entry Point
  306. /// <summary>
  307. /// The main entry point for the application.
  308. /// </summary>
  309. static void Main()
  310. {
  311. using (VertexLighting game = new VertexLighting())
  312. {
  313. game.Run();
  314. }
  315. }
  316. #endregion
  317. }
  318. }