Advertisement
Guest User

Untitled

a guest
Sep 24th, 2017
64
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 14.09 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using Microsoft.Xna.Framework;
  5. using Microsoft.Xna.Framework.Audio;
  6. using Microsoft.Xna.Framework.Content;
  7. using Microsoft.Xna.Framework.GamerServices;
  8. using Microsoft.Xna.Framework.Graphics;
  9. using Microsoft.Xna.Framework.Input;
  10. using Microsoft.Xna.Framework.Media;
  11. using Microsoft.Xna.Framework.Net;
  12. using Microsoft.Xna.Framework.Storage;
  13.  
  14. namespace MorphTargetAnimation
  15. {
  16.     /// <summary>
  17.     /// This class presents an approach to morph target animation.
  18.     /// A custom vertex declaration is used to blend multiple vertex streams
  19.     /// so that multiple model geometry can be interpolated. Vertex streams
  20.     /// are then blended in an HLSL shader.
  21.     ///
  22.     /// This approach requires model topology to be exactly the same for all
  23.     /// morph targets. Vertex/Index counts and orders must be the same as
  24.     /// well as the number and order of meshes contained within each model.
  25.     /// This code makes the assumption that the predescribed requirements
  26.     /// are met and will exhibit undesired behaviour/thrown exceptions if
  27.     /// provided with differing topologies.
  28.     ///
  29.     /// Capability for further extension:
  30.     ///
  31.     /// Currently this implementation only uses 2 vertex streams, so only
  32.     /// two morph targets can be blended at any one time. This implementation
  33.     /// could be further improved by allowing varying interpolation with
  34.     /// other morph targets. The vertex stream limit on DX9 cards I believe
  35.     /// is 16 streams, however utilisation of that many streams is unlikely
  36.     /// to be required. Instead, I'd recommend a lower limit of streams, using
  37.     /// the first stream as a neutral expression (in the case of facial
  38.     /// animation) and blending to other streams (in order of importance.)
  39.     /// As the strength of a morph target is increased, it can increase in
  40.     /// importance. This way the least visible (and therefore least
  41.     /// important) streams can be kept outside the enforced stream limit.
  42.     ///
  43.     /// The morph targets could also be generated into vertex textures
  44.     /// and VTF used to change positions and normals.
  45.     /// </summary>
  46.  
  47.     public class MorphGameObject : DrawableGameComponent
  48.     {
  49.         #region Fields
  50.         private ContentManager Content;
  51.  
  52.         private VertexDeclaration morphingVertexDeclaration;
  53.         private Effect morphingEffect;
  54.  
  55.         // Models to blend between
  56.         private Model[] models;
  57.  
  58.         // Interpolation value for blending between models
  59.         private float tween;
  60.  
  61.         // Camera matrices
  62.         Matrix world, view, projection;
  63.         // Camera view
  64.         float cameraArc = 0;
  65.         float cameraRotation = MathHelper.Pi;
  66.         float cameraDistance = 300;
  67.  
  68.         // Which mesh is currently being blended from
  69.         int primaryMeshIndex;
  70.  
  71.         // Track input to detect input changes
  72.         KeyboardState lastKeyboardState;
  73.         GamePadState lastGamePadState;
  74.         #endregion
  75.  
  76.         #region Properties
  77.         public float Tween
  78.         {
  79.             get { return tween; }
  80.             set { tween = value; }
  81.         }
  82.  
  83.         public int PrimaryMeshIndex
  84.         {
  85.             get { return primaryMeshIndex; }
  86.             set { primaryMeshIndex = value; }
  87.         }
  88.         #endregion
  89.  
  90.         public MorphGameObject(Game game, ContentManager Content)
  91.             : base(game)
  92.         {
  93.             this.Content = Content;
  94.         }
  95.         public override void Initialize()
  96.         {
  97.             base.Initialize();
  98.  
  99.             // Initialise the custom vertex declaration to allow two vertex streams to be blended
  100.             morphingVertexDeclaration = new VertexDeclaration(GraphicsDevice,
  101.                     new VertexElement[] {
  102.                     new VertexElement(
  103.                         // Texture coordinates from vertex stream 0
  104.                         0, // which stream this element comes from
  105.                         sizeof(float) * 6, // byte offset within the stream
  106.                         VertexElementFormat.Vector2,
  107.                         VertexElementMethod.Default,
  108.                         VertexElementUsage.TextureCoordinate,
  109.                         0
  110.                     ),
  111.                     // Positions from vertex stream 0
  112.                     new VertexElement(
  113.                         0, // which stream this element comes from
  114.                         0, // byte offset within the stream
  115.                         VertexElementFormat.Vector3,
  116.                         VertexElementMethod.Default,
  117.                         VertexElementUsage.Position,
  118.                         0
  119.                     ),
  120.                     // Normals from vertex stream 0
  121.                     new VertexElement(
  122.                         0, // which stream this element comes from
  123.                         sizeof(float) * 3, // byte offset within the stream
  124.                         VertexElementFormat.Vector3,
  125.                         VertexElementMethod.Default,
  126.                         VertexElementUsage.Normal,
  127.                         0
  128.                     ),
  129.                     // Position from vertex stream 1
  130.                     new VertexElement(
  131.                         1, // which stream this element comes from
  132.                         0, // byte offset within the stream
  133.                         VertexElementFormat.Vector3,
  134.                         VertexElementMethod.Default,
  135.                         VertexElementUsage.Position,
  136.                         1
  137.                     ),
  138.                     // Normals from vertex stream 1
  139.                     new VertexElement(
  140.                         1, // which stream this element comes from
  141.                         sizeof(float) * 3, // byte offset within the stream
  142.                         VertexElementFormat.Vector3,
  143.                         VertexElementMethod.Default,
  144.                         VertexElementUsage.Normal,
  145.                         1
  146.                     )      
  147.                 }
  148.                 );
  149.  
  150.             // Set up the camera
  151.             world = Matrix.Identity;
  152.             view = Matrix.CreateLookAt(new Vector3(300, 100, 300), Vector3.Zero, Vector3.Up);
  153.             projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45.0f), GraphicsDevice.Viewport.AspectRatio, 0.1f, 1000.0f);
  154.         }
  155.         protected override void LoadContent()
  156.         {
  157.             // Load the models and morphing effect
  158.             models = new Model[3];
  159.             for (int i = 0; i < models.Length; i++)
  160.             {
  161.                 models[i] = Content.Load<Model>((i + 1).ToString());
  162.             }
  163.             morphingEffect = Content.Load<Effect>("MorphingEffect");
  164.  
  165.             base.LoadContent();
  166.         }
  167.  
  168.         /// <summary>
  169.         /// Handles input.
  170.         /// </summary>
  171.         private void HandleInput(GameTime gameTime)
  172.         {
  173.             KeyboardState currentKeyboardState = Keyboard.GetState();
  174.             GamePadState currentGamePadState = GamePad.GetState(PlayerIndex.One);
  175.             float time = 20 * (float)gameTime.ElapsedGameTime.TotalSeconds;
  176.  
  177.             // Check for input to rotate the camera up and down around the model.
  178.             if (currentKeyboardState.IsKeyDown(Keys.Up) ||
  179.                 currentKeyboardState.IsKeyDown(Keys.W))
  180.             {
  181.                 cameraArc += time * 0.1f;
  182.             }
  183.  
  184.             if (currentKeyboardState.IsKeyDown(Keys.Down) ||
  185.                 currentKeyboardState.IsKeyDown(Keys.S))
  186.             {
  187.                 cameraArc -= time * 0.1f;
  188.             }
  189.  
  190.             cameraArc += currentGamePadState.ThumbSticks.Right.Y * time * 0.25f;
  191.  
  192.             // Limit the arc movement.
  193.             if (cameraArc > 90.0f)
  194.                 cameraArc = 90.0f;
  195.             else if (cameraArc < -90.0f)
  196.                 cameraArc = -90.0f;
  197.  
  198.             // Check for input to rotate the camera around the model.
  199.             if (currentKeyboardState.IsKeyDown(Keys.Right) ||
  200.                 currentKeyboardState.IsKeyDown(Keys.D))
  201.             {
  202.                 cameraRotation += time * 0.1f;
  203.             }
  204.  
  205.             if (currentKeyboardState.IsKeyDown(Keys.Left) ||
  206.                 currentKeyboardState.IsKeyDown(Keys.A))
  207.             {
  208.                 cameraRotation -= time * 0.1f;
  209.             }
  210.  
  211.             cameraRotation += currentGamePadState.ThumbSticks.Right.X * time * 0.25f;
  212.  
  213.             // Check for input to zoom camera in and out.
  214.             if (currentKeyboardState.IsKeyDown(Keys.Z))
  215.                 cameraDistance += time * 2.5f;
  216.  
  217.             if (currentKeyboardState.IsKeyDown(Keys.X))
  218.                 cameraDistance -= time * 2.5f;
  219.  
  220.             cameraDistance += currentGamePadState.Triggers.Left * time * 5f;
  221.             cameraDistance -= currentGamePadState.Triggers.Right * time * 5f;
  222.  
  223.             // Limit the camera distance.
  224.             if (cameraDistance > 500.0f)
  225.                 cameraDistance = 500.0f;
  226.             else if (cameraDistance < 10.0f)
  227.                 cameraDistance = 10.0f;
  228.  
  229.             // Toggle wireframe
  230.             if ((lastGamePadState.IsButtonDown(Buttons.A) && currentGamePadState.IsButtonUp(Buttons.A))
  231.                 || (lastKeyboardState.IsKeyDown(Keys.Q) && currentKeyboardState.IsKeyUp(Keys.Q)))
  232.                 GraphicsDevice.RenderState.FillMode = (GraphicsDevice.RenderState.FillMode == FillMode.Solid) ? FillMode.WireFrame : FillMode.Solid;
  233.  
  234.             lastGamePadState = currentGamePadState;
  235.             lastKeyboardState = currentKeyboardState;
  236.         }
  237.  
  238.         public override void Update(GameTime gameTime)
  239.         {
  240.             // Increase the tween value over time, while maintaining frame rate independence
  241.             tween += (float)gameTime.ElapsedGameTime.TotalSeconds;
  242.             // Clean up the tween value to be between -180 and 180 degrees
  243.             tween = MathHelper.WrapAngle(tween);
  244.  
  245.             if (tween > 1)
  246.             {
  247.                 tween -= 1;
  248.                 primaryMeshIndex++;
  249.                 if (primaryMeshIndex >= models.Length)
  250.                     primaryMeshIndex = 0;
  251.             }
  252.  
  253.             HandleInput(gameTime);
  254.  
  255.             base.Update(gameTime);
  256.         }
  257.  
  258.         public override void Draw(GameTime gameTime)
  259.         {
  260.             // Ensure that the device vertex declaration is set correctly
  261.             GraphicsDevice.VertexDeclaration = morphingVertexDeclaration;
  262.  
  263.             // Update view matrix
  264.             view =
  265.               Matrix.CreateRotationY(cameraRotation) *
  266.               Matrix.CreateRotationX(cameraArc) *
  267.               Matrix.CreateLookAt(new Vector3(0, 0, -cameraDistance),
  268.                                   new Vector3(0, 0, 0), Vector3.Up);
  269.  
  270.             // Set the camera settings
  271.             morphingEffect.Parameters["World"].SetValue(world);
  272.             morphingEffect.Parameters["View"].SetValue(view);
  273.             morphingEffect.Parameters["Projection"].SetValue(projection);
  274.  
  275.             // Set the tween value to follow a sine curve with an output value between 0 and 1
  276.             morphingEffect.Parameters["TweenValue"].SetValue(tween);
  277.             DrawHair();
  278.             // Loop through each of the meshes
  279.             for (int i = 0; i < models[0].Meshes.Count; i++)
  280.             {
  281.                 if (models[0].Meshes[i].Name == "Mesh_001")
  282.                     continue;
  283.                 int numberOfPrimitives = (models[0].Meshes[i].VertexBuffer.SizeInBytes / VertexPositionNormalTexture.SizeInBytes) / 3;
  284.  
  285.                 // Mesh topology must be the same, therefore the first model's indices should be correct for all
  286.                 GraphicsDevice.Indices = models[0].Meshes[i].IndexBuffer;
  287.  
  288.                 // Set a vertex element stride of 4 bytes
  289.                 int stride = 32;
  290.  
  291.                 // Calculate the index of the model being morphed to, wrapping back to start if necessary.
  292.                 int nextIndex = primaryMeshIndex + 1;
  293.                 if (nextIndex >= models.Length)
  294.                     nextIndex = 0;
  295.  
  296.                 // Set the vertex streams from the models, this must conform to the custom vertex declaration
  297.                 GraphicsDevice.Vertices[0].SetSource(models[primaryMeshIndex].Meshes[i].VertexBuffer, 0, stride);
  298.                 GraphicsDevice.Vertices[1].SetSource(models[nextIndex].Meshes[i].VertexBuffer, 0, stride);
  299.  
  300.                 // The default model content processor supplies the default mesh effect with its texture
  301.                 // automatically. Set the custom effect's texture appropiately from the default effect
  302.                 BasicEffect basicEffect = (BasicEffect)(models[0].Meshes[i].Effects[0]);
  303.                 morphingEffect.Parameters["Texture"].SetValue(basicEffect.Texture);
  304.  
  305.                 // Draw the geometry using the morphing effect
  306.                 morphingEffect.Begin();
  307.                 {
  308.                     foreach (EffectPass pass in morphingEffect.CurrentTechnique.Passes)
  309.                     {
  310.                         pass.Begin();
  311.                         {
  312.                             GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, numberOfPrimitives * 3 * 6, 0, numberOfPrimitives * 6);
  313.                         }
  314.  
  315.                         pass.End();
  316.                     }
  317.                 }
  318.                 morphingEffect.End();
  319.             }
  320.  
  321.             base.Draw(gameTime);
  322.         }
  323.         void DrawHair()
  324.         {
  325.             // Draw the model. A model can have multiple meshes, so loop.
  326.             foreach (ModelMesh mesh in models[0].Meshes)
  327.             {
  328.                 if (mesh.Name != "Mesh_001")
  329.                     continue;
  330.  
  331.                 // This is where the mesh orientation is set, as well as our camera and projection.
  332.                 foreach (BasicEffect effect in mesh.Effects)
  333.                 {
  334.                     effect.EnableDefaultLighting();
  335.                     effect.World = world;
  336.                     effect.View = view;
  337.                     effect.Projection = projection;
  338.                 }
  339.  
  340.                 // Draw the mesh, using the effects set above.
  341.                 mesh.Draw();
  342.             }
  343.         }
  344.     }
  345. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement