⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cloth.cs

📁 Game Engine Desing Direct X and C#.rar
💻 CS
字号:
using System;
using System.Collections;
using System.Drawing;
using System.Threading;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;

namespace GameEngine
{
	/// <summary>
	/// Summary description for Model.
	/// </summary>
	public class Cloth : Object3D, IDynamic
	{
		private struct Node
		{
			public float  mass;
			public float  inverse_mass;
			public Vector3 position;
			public Vector3 velocity;
			public Vector3 acceleration;
			public Vector3 force;
			public bool    constrained;

			public Node(float mass_, double x, double y, double z, bool fixed_in_place)
			{
				mass = mass_;
				inverse_mass = 1.0f / mass;
				position.X = (float)x;
				position.Y = (float)y;
				position.Z = (float)z;
				velocity.X = 0.0f;
				velocity.Y = 0.0f;
				velocity.Z = 0.0f;
				acceleration.X = 0.0f;
				acceleration.Y = 0.0f;
				acceleration.Z = 0.0f;
				force.X = 0.0f;
				force.Y = 0.0f;
				force.Z = 0.0f;
				constrained = fixed_in_place;
			}
		}

		private struct NodeIndex
		{
			public int row;
			public int column;
		}

		private struct Spring
		{
			public NodeIndex node1;
			public NodeIndex node2;
			public float	 spring_constant;
			public float     damping;
			public float     length;
		}

		#region Attributes
		private CustomVertex.PositionNormalTextured[]  m_vertices;   
		private VertexBuffer m_VB = null;  // Vertex buffer
		private IndexBuffer  m_IB = null;  // Index buffer
		//indices buffer
		private short[] indices;
		private Texture      m_Texture; // image for face
		private Node[,] nodes;
		private int num_springs;
		private int num_faces;
		private int num_rows;
		private int num_columns;
		private int num_nodes;
		private Spring[] springs;
		private Vector3  m_vOffset = new Vector3(0.0f, 0.0f, 0.0f);
		private Attitude m_AttitudeOffset = new Attitude();
		private bool m_bValid = false;
		private Thread        m_physics_thread;
		private bool thread_active = true;
		private Mutex mutex = new Mutex();

		// global variables
		private static Vector3 wind = new Vector3();

		// constants
		private static float gravity = -32.174f; 
		private static float spring_tension = 50.10f;
		private static float damping = 1.70f;
		private static float drag_coefficient = 0.01f;
		#endregion

		#region Properties
		public Vector3 Offset { set { m_vOffset = value; } get { return m_vOffset; } }

		public static float EastWind { set { wind.X = value; } get { return wind.X; } }
		public static float NorthWind { set { wind.Z = value; } get { return wind.Z; } }
		#endregion


		public Cloth(string name, string texture_name, int rows, int columns, double spacing, float mass) : base(name)
		{
			try 
			{
				num_rows = rows;
				num_columns = columns;
				m_Texture = GraphicsUtility.CreateTexture(CGameEngine.Device3D, texture_name); 
				nodes = new Node[rows+1,columns+1];
				num_faces = rows * columns * 2;
				num_springs = columns * ( rows+1) + rows * (columns+1) + columns*rows*2;
				springs = new Spring[num_springs];

				wind.X = 0.0f;
				wind.Y = 0.0f;
				wind.Z = 0.0f;

				num_nodes = (rows+1) * (columns+1);

				m_vertices = new CustomVertex.PositionNormalTextured[num_nodes];

				float mass_per_node = mass / num_nodes;

				for ( int r=0; r<=rows; r++ )
				{
					for ( int c=0; c <=columns; c++ )
					{
						nodes[r,c] = new Node(mass_per_node, -(c*spacing), -(r*spacing), 0.0, c==0 && (r==0 || r == rows));
					}
				}

				// Create a buffer for rendering the cloth
				m_VB = new VertexBuffer( typeof(CustomVertex.PositionNormalTextured), num_nodes,
					CGameEngine.Device3D, Usage.WriteOnly, CustomVertex.PositionNormalTextured.Format,
					Pool.Default );

				m_IB = new IndexBuffer(typeof(short), num_faces * 3, CGameEngine.Device3D, Usage.WriteOnly, Pool.Managed);
				indices = new short[num_faces * 3];
				m_IB.Created += new System.EventHandler(this.PopulateIndexBuffer);
				this.PopulateIndexBuffer(m_IB, null);

				m_VB.Created += new System.EventHandler(this.PopulateBuffer);
				this.PopulateBuffer(m_VB, null);

				// create the springs
				int index = 0;
				for ( int r=0; r<=rows; r++ )
				{
					for ( int c=0; c <=columns; c++ )
					{
						if ( c < columns )
						{
							springs[index].node1.row = r;
							springs[index].node1.column = c;
							springs[index].node2.row = r;
							springs[index].node2.column = c+1;
							springs[index].spring_constant = spring_tension;
							springs[index].damping = damping;
							Vector3 length = nodes[r,c].position - nodes[r,c+1].position;
							springs[index].length = length.Length();
							index++;
						}
						if ( r < rows )
						{
							springs[index].node1.row = r;
							springs[index].node1.column = c;
							springs[index].node2.row = r+1;
							springs[index].node2.column = c;
							springs[index].spring_constant = spring_tension;
							springs[index].damping = damping;
							Vector3 length = nodes[r,c].position - nodes[r+1,c].position;
							springs[index].length = length.Length();
							index++;
						}
						if ( r < (rows-1) && c < (columns-1) )
						{
							springs[index].node1.row = r;
							springs[index].node1.column = c;
							springs[index].node2.row = r+1;
							springs[index].node2.column = c+1;
							springs[index].spring_constant = spring_tension;
							springs[index].damping = damping;
							Vector3 length = nodes[r,c].position - nodes[r+1,c+1].position;
							springs[index].length = length.Length();
							index++;
						}
						if ( r < (rows-1) && c > 0 )
						{
							springs[index].node1.row = r;
							springs[index].node1.column = c;
							springs[index].node2.row = r+1;
							springs[index].node2.column = c-1;
							springs[index].spring_constant = spring_tension;
							springs[index].damping = damping;
							Vector3 length = nodes[r,c].position - nodes[r+1,c-1].position;
							springs[index].length = length.Length();
							index++;
						}
					}
				}

				m_physics_thread = new Thread(new ThreadStart(DoPhysics));
				m_physics_thread.Start();
				m_bValid = true;
			}
			catch (DirectXException d3de)
			{
				Console.AddLine("Unable to create cloth for " + name);
				Console.AddLine(d3de.ErrorString);
			}
			catch ( Exception e )
			{
				Console.AddLine("Unable to create cloth for " + name);
				Console.AddLine(e.Message);
			}
			
		}

		public void PopulateBuffer(object sender, EventArgs e)
		{
			VertexBuffer vb = (VertexBuffer)sender;

			int index = 0;
			for ( int r=0; r<(1+num_rows); r++ )
			{
				for ( int c=0; c <(1+num_columns); c++ )
				{
					m_vertices[index].SetPosition(nodes[r,c].position);
					m_vertices[index].SetNormal(new Vector3(0.0f, 0.0f, 1.0f));
					m_vertices[index].Tv = (float)r / (float)(num_rows);
					m_vertices[index].Tu = (float)c / (float)(num_columns);
					index++;
				}
			}
			// Copy vertices into vertexbuffer
			mutex.WaitOne();
			vb.SetData(m_vertices, 0, 0);
			mutex.ReleaseMutex();
		}

		public void PopulateIndexBuffer(object sender, EventArgs e)
		{
			int index = 0;

			IndexBuffer g = (IndexBuffer)sender;
			for ( int r=0; r<num_rows; r++)
			{
				for ( int c=0; c<num_columns; c++)
				{
					indices[index]   = (short)((r)  *(1+num_columns) + (c));
					indices[index+1] = (short)((r+1)*(1+num_columns) + (c));
					indices[index+2] = (short)((r)  *(1+num_columns) + (c+1));

					indices[index+3] = (short)((r)  *(1+num_columns) + (c+1));
					indices[index+4] = (short)((r+1)*(1+num_columns) + (c));
					indices[index+5] = (short)((r+1)*(1+num_columns) + (c+1));
					index += 6;
				}
			}

			mutex.WaitOne();
			g.SetData(indices, 0, 0);
			mutex.ReleaseMutex();
		}

		public override bool Collide( Object3D Other ) 
		{ 
			return false; 
		}

		public override void Render( Camera cam )
		{
			if ( m_bValid ) 
			{
				Matrix world_matrix;

				if ( m_Parent != null )
				{
					world_matrix = Matrix.Multiply(m_Matrix, m_Parent.WorldMatrix);
				}
				else
				{
					world_matrix = m_Matrix;
				}

				CGameEngine.Device3D.Transform.World = world_matrix;

				Material mtrl = new Material();
				mtrl.Ambient = Color.White;
				mtrl.Diffuse = Color.White;
				CGameEngine.Device3D.Material = mtrl;
				CGameEngine.Device3D.SetStreamSource( 0, m_VB, 0 );
				CGameEngine.Device3D.VertexFormat = CustomVertex.PositionNormalTextured.Format;

				CGameEngine.Device3D.RenderState.CullMode = Cull.None;

				// Set the texture
				CGameEngine.Device3D.SetTexture(0, m_Texture );

				// set the indices			
				CGameEngine.Device3D.Indices = m_IB;

				// Render the face
				mutex.WaitOne();
				CGameEngine.Device3D.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, num_nodes, 0, num_faces);
				mutex.ReleaseMutex();

				if ( m_Children.Count > 0 )
				{
					Object3D obj;
					for ( int i=0; i<m_Children.Count; i++ )
					{
						obj = (Object3D)m_Children.GetByIndex(i);
						obj.Render( cam );
					}
				}
			}
		}

		public override void Update( float DeltaT )
		{
			if ( m_UpdateMethod != null ) 
			{
				m_UpdateMethod( (Object3D)this, DeltaT );
			}
			if ( m_Children.Count > 0 )
			{
				Object3D obj;
				for ( int i=0; i<m_Children.Count; i++ )
				{
					obj = (Object3D)m_Children.GetByIndex(i);
					obj.Update( DeltaT );
				}
			}
		}

		private void DoPhysics()
		{
			Vector3 parent_wind = new Vector3(0.0f, 0.0f, 0.0f);
			Console.AddLine("cloth physics thread started");
			System.Random rand = new System.Random();
			while ( thread_active )
			{

				try
				{
					if ( m_Parent != null )
					{
//						parent_wind = m_Parent.Velocity * -0.10f;
					}
					m_Matrix = Matrix.Identity;
					m_Matrix = Matrix.RotationYawPitchRoll(Heading+m_AttitudeOffset.Heading,
						Pitch+m_AttitudeOffset.Pitch,Roll+m_AttitudeOffset.Roll);
					Matrix temp = Matrix.Translation(m_vPosition);
					m_Matrix.Multiply(temp);

					for ( int r=0; r<=num_rows; r++ )
					{
						for ( int c=0; c <=num_columns; c++ )
						{
							nodes[r,c].force.X = 0.0f;
							nodes[r,c].force.Y = 0.0f;
							nodes[r,c].force.Z = 0.0f;
						}
					}

					// process external forces
					for ( int r=0; r<=num_rows; r++ )
					{
						for ( int c=0; c <=num_columns; c++ )
						{
							if ( !nodes[r,c].constrained )
							{
								// gravity
								nodes[r,c].force.Y += (float)(gravity * nodes[r,c].mass);

								// drag
								Vector3 drag = nodes[r,c].velocity;
								drag.Multiply(-1.0f);
								drag.Normalize();
								drag.Multiply((nodes[r,c].velocity.Length() * nodes[r,c].velocity.Length()) * drag_coefficient);
								nodes[r,c].force += drag;

								// wind
								Vector3 turbulence = new Vector3((float)rand.NextDouble(), 0.0f, (float)rand.NextDouble());
								Vector3 total_wind = wind + turbulence + parent_wind;
								nodes[r,c].force += total_wind;
								if ( r==1 && c==1 )
								{
//									Console.AddLine(" wind " + total_wind.X + " " + total_wind.Y + " " +total_wind.Z );
								}
							}
						}
					}

					// spring forces
					for ( int i=0; i<num_springs; i++ )
					{
						int row1    = springs[i].node1.row;
						int column1 = springs[i].node1.column;
						int row2    = springs[i].node2.row;
						int column2 = springs[i].node2.column;

						Vector3 distance = nodes[row1,column1].position - nodes[row2,column2].position;
						float spring_length = distance.Length();
						Vector3 normalized_distance = distance;
						normalized_distance.Multiply( 1.0f / spring_length );
						Vector3 velocity = nodes[row1,column1].velocity - nodes[row2,column2].velocity;
						float length = springs[i].length;

						float spring_force = springs[i].spring_constant * (spring_length - length);
						float damping_force = springs[i].damping * Vector3.Dot(velocity,distance) / spring_length;

						Vector3 force2 = (spring_force + damping_force) * normalized_distance;
						Vector3 force1 = force2;
						force1.Multiply(-1.0f);

						if ( !nodes[row1,column1].constrained )
						{
							nodes[row1,column1].force += force1;
						}

						if ( !nodes[row2,column2].constrained )
						{
							nodes[row2,column2].force += force2;
						}
					}

					//				DeltaT *= 0.001f;

					// integrate position
					for ( int r=0; r<=num_rows; r++ )
					{
						for ( int c=0; c <=num_columns; c++ )
						{
							float x;
							Vector3 accel = nodes[r,c].force;
							accel.Multiply( nodes[r,c].inverse_mass);
							nodes[r,c].acceleration = accel;
							nodes[r,c].velocity.X += accel.X * 0.01f;
							nodes[r,c].velocity.Y += accel.Y * 0.01f;
							nodes[r,c].velocity.Z += accel.Z * 0.01f;
							nodes[r,c].position.X += nodes[r,c].velocity.X * 0.01f;
							nodes[r,c].position.Y += nodes[r,c].velocity.Y * 0.01f;
							nodes[r,c].position.Z += nodes[r,c].velocity.Z * 0.01f;
							x=1;
							if ( r==1 && c==1 )
							{
//								Console.AddLine("Force " + accel.X + " " + accel.Y + " " + accel.Z);
//								Console.AddLine("velocity " + nodes[r,c].velocity.X + " " + nodes[r,c].velocity.Y + " " + nodes[r,c].velocity.Z);
//								Console.AddLine("position " + nodes[r,c].position.X + " " + nodes[r,c].position.Y + " " + nodes[r,c].position.Z);
//								Console.AddLine("");
							}
						}
					}
					PopulateBuffer((object)m_VB, null);

				}
				catch (DirectXException d3de)
				{
					Console.AddLine("Unable to update cloth " + Name);
					Console.AddLine(d3de.ErrorString);
				}
				catch ( Exception e )
				{
					Console.AddLine("Unable to update cloth " + Name);
					Console.AddLine(e.Message);
				}

				Thread.Sleep(10);

			}
			Console.AddLine("cloth physics thread terminated");
		}

		public override void Dispose()
		{
			thread_active = false;
			if ( m_VB != null ) 
			{
				m_VB.Dispose();
				m_IB.Dispose();
				m_Texture.Dispose();
			}
			Thread.Sleep(100);
		}
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -