//
Some defines to determine how our cloth will look
static
int g_width = 30;
static
int g_height = 30;
static
float g_gap = 0.5f;
static
float g_disOffFloor = 15.0f;
//
Some helper containers
struct
Constraint
{
int index0;
int index1;
float restLength;
};
struct
Points
{
D3DXVECTOR3
curPos;
D3DXVECTOR3
oldPos;
};
//
The actual cloth class
class
Cloth
{
public:
int m_numPoints;
Points* m_points;
int m_numConstraints;
Constraint*
m_constraints;
Cloth()
{
float gap = g_gap;
int w = g_width;
int h = g_height;
m_numPoints = w * h;
m_points = new Points[m_numPoints];
// Put points together
for (int
x=0; x<w; x++)
{
for (int
y=0; y<h; y++)
{
m_points[x + y*h].curPos = D3DXVECTOR3(x*gap, g_disOffFloor, y*gap);
m_points[x + y*h].oldPos = D3DXVECTOR3(x*gap,
g_disOffFloor, y*gap);
}
}
// Build linking constraints
m_numConstraints = (w)*(h)*2 - w - h;
m_constraints = new
Constraint[m_numConstraints];
int i = 0;
for (int
y=0; y<h; y++)
{
for (int
x=0; x<w; x++)
{
if ((x+1) < w)
{
m_constraints[i].index0 = x + y*w;
m_constraints[i].index1 = x+1 + y*w;
m_constraints[i].restLength =
D3DXVec3Length(&(m_points[x].curPos
- m_points[x+1].curPos));
i++;
}
if ((y+1) < h)
{
m_constraints[i].index0 = x + y*w;
m_constraints[i].index1 = x+w + y*w;
m_constraints[i].restLength =
D3DXVec3Length(&(m_points[x].curPos
- m_points[x+w].curPos));
i++;
}
if (i>m_numConstraints)
DBG_HALT;
}
}
if (i!=m_numConstraints) DBG_HALT;
}
~Cloth()
{
delete[] m_points;
delete[] m_constraints;
}
void VerletIntegrate(float
dt)
{
for (int i=0;
i<m_numPoints; i++)
{
D3DXVECTOR3 oldPos = m_points[i].oldPos;
D3DXVECTOR3 curPos = m_points[i].curPos;
D3DXVECTOR3 a = D3DXVECTOR3(0,-9.8f,0);
curPos = 2*curPos - oldPos + a*dt*dt;
m_points[i].oldPos = m_points[i].curPos;
m_points[i].curPos = curPos;
}
}
void SatisfyConstraints()
{
const int
numIterations = 10;
for (int i=0;
i<numIterations; i++)
{
for (int
k=0; k< m_numConstraints; k++)
{
// Constraint 1 (Floor)
if (g_floorCollisions)
for (int
v=0; v<m_numPoints; v++)
{
if (m_points[v].curPos.y
< 0.0f) m_points[v].curPos.y = 0.0f;
}
// Constraint 2 (Cloth)
Constraint* c = &m_constraints[k];
D3DXVECTOR3& p0 = m_points[c->index0].curPos;
D3DXVECTOR3& p1 = m_points[c->index1].curPos;
D3DXVECTOR3 delta = p1-p0;
float len =
D3DXVec3Length(&delta);
float diff = (len -
c->restLength) / len;
p0 += delta*0.5f*diff;
p1 -= delta*0.5f*diff;
}
// Keep these two points contraints to there
original position
float gap = g_gap;
m_points[0].curPos =
D3DXVECTOR3(0, g_disOffFloor, 0);
m_points[g_width-1].curPos = D3DXVECTOR3((g_width-1)*gap, g_disOffFloor,
0);
}
}
void Update(float
dt)
{
VerletIntegrate(dt);
SatisfyConstraints();
}
void Render(IDirect3DDevice9* pDevice)
{
if (0) // If we
want to draw little spheres for our points
for (int i=0;
i<m_numPoints; i++)
{
// Just for debug, draw a sphere
static debugsphere ball(pDevice);
ball.Draw(pDevice,
m_points[i].curPos.x,
m_points[i].curPos.y,
m_points[i].curPos.z,
0.2f);
}
// Draw a wire mesh for our constraints
for (int i=0;
i<m_numConstraints; i++)
{
Constraint* c = &m_constraints[i];
DrawLine3D( pDevice,
m_points[c->index0].curPos,
m_points[c->index1].curPos,
0xffff00ff);
}
}
}; |