www.pudn.com > IntroductionTo3DGameEngineDesign.rar > Cloth.cs
using System;
using System.Collections;
using System.Drawing;
using System.Threading;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
namespace GameEngine
{
///
/// Summary description for Model.
///
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 0 )
{
Object3D obj;
for ( int i=0; i 0 )
{
Object3D obj;
for ( int i=0; i