#include <maya/MIOStream.h>
#include <maya/MStatus.h>
#include <maya/MDagPath.h>
#include <maya/MFloatPointArray.h>
#include <maya/MObject.h>
#include <maya/MPlugArray.h>
#include <maya/MFnDependencyNode.h>
#include <maya/MFnDagNode.h>
#include <maya/MFnMesh.h>
#include <maya/MHairSystem.h>
#include <maya/MFnPlugin.h>
#include <math.h>
#define kPluginName "hairCollisionSolver"
typedef struct {
int numVerts;
double minx;
double miny;
double minz;
double maxx;
double maxy;
double maxz;
} COLLISION_OBJ ;
typedef struct {
int numObjs;
COLLISION_OBJ *objs;
} COLLISION_INFO ;
bool preFrame(
const double curTime,
void **privateData )
{
fprintf( stderr,
"preFrame: calling hairSystem node=`%s', time=%g\n",
fnHairSystem.name().asChar(), curTime );
cols, logIdxs ), false );
int nobj = cols.length();
COLLISION_INFO *collisionInfo = (COLLISION_INFO *) malloc(
sizeof( COLLISION_INFO ) );
collisionInfo->objs = (COLLISION_OBJ *) malloc(
nobj * sizeof( COLLISION_OBJ ) );
collisionInfo->numObjs = nobj;
*privateData = (void *) collisionInfo;
int obj;
for ( obj = 0; obj < nobj; ++obj ) {
status = fnDagNode.getPath( path );
if ( MS::kSuccess != status ) {
fprintf( stderr,
"%s:%d: collide was not passed a valid mesh shape\n",
__FILE__, __LINE__ );
return( false );
}
double minx, miny, minz, maxx, maxy, maxz, x, y, z;
minx = maxx = verts[0].x;
miny = maxy = verts[0].y;
minz = maxz = verts[0].z;
int i;
for ( i = 1; i < nv; ++i ) {
x = verts[i].x;
y = verts[i].y;
z = verts[i].z;
if ( x < minx ) {
minx = x;
}
if ( y < miny ) {
miny = y;
}
if ( z < minz ) {
minz = z;
}
if ( x > maxx ) {
maxx = x;
}
if ( y > maxy ) {
maxy = y;
}
if ( z > maxz ) {
maxz = z;
}
}
collisionInfo->objs[obj].numVerts = nv;
collisionInfo->objs[obj].minx = minx;
collisionInfo->objs[obj].miny = miny;
collisionInfo->objs[obj].minz = minz;
collisionInfo->objs[obj].maxx = maxx;
collisionInfo->objs[obj].maxy = maxy;
collisionInfo->objs[obj].maxz = maxz;
fprintf( stderr, "Inside preFrameInit, bbox=%g %g %g %g %g %g\n",
minx,miny,minz,maxx,maxy,maxz);
}
return( true );
}
bool belowCollisionPlane(
const COLLISION_OBJ *co,
const MVector &pnt )
{
return( pnt.
x > co->minx && pnt.
x < co->maxx
&& pnt.
z > co->minz && pnt.
z < co->maxz );
}
#define EPSILON 0.0001
bool collide(
const int follicleIndex,
const int startIndex,
const int endIndex,
const double curTime,
const double friction,
const void *privateData )
{
COLLISION_INFO *ci = (COLLISION_INFO *) privateData;
if ( !ci ) {
fprintf( stderr,"%s:%d: collide() privateData pointer is NULL\n",
__FILE__, __LINE__ );
return( false );
}
if ( ci->numObjs <= 0 || hairPositions.
length() <= 0 ) {
return( true );
}
int obj;
for ( obj = 0; obj < ci->numObjs; ++obj ) {
COLLISION_OBJ *co = &ci->objs[obj];
int numSegments = hairPositions.
length() - 1;
int seg;
for ( seg = 0; seg < numSegments; ++seg ) {
MVector pStart = hairPositions[seg];
MVector pEnd = hairPositions[seg + 1];
MVector vStart = pStart - hairPositionsLast[seg];
MVector vEnd = pEnd - hairPositionsLast[seg + 1];
#define STEPS 4
int step;
for ( step = 0; step < STEPS; ++step ) {
double fracAlongSeg = step / ( (double) STEPS );
v = vStart * ( 1.0 - fracAlongSeg ) + vEnd * fracAlongSeg;
MVector p1 = pStart * ( 1.0 - fracAlongSeg )
+ pEnd * fracAlongSeg;
if ( (p0.x < co->minx && p1.x < co->minx)
|| (p0.y < co->miny && p1.y < co->miny)
|| (p0.z < co->minz && p1.z < co->minz)
|| (p0.x > co->maxx && p1.x > co->maxx)
|| (p0.y > co->maxy && p1.y > co->maxy)
|| (p0.z > co->maxz && p1.z > co->maxz) ) {
continue;
}
MVector where(-100000,-100000,-100000);
double fracTime;
if ( fabs( v.y ) < EPSILON
&& fabs( p1.y - co->maxy ) < EPSILON ) {
where = p1;
fracTime = 1.0;
} else {
fracTime = ( co->maxy - p0.y ) / v.y;
if ( fracTime >= 0.0 && fracTime <= 1.0 ) {
where = p0 + v * fracTime;
}
}
if ( seg >= startIndex && seg <= endIndex ) {
bool segCollides = false;
if ( where.x >= co->minx && where.x <= co->maxx
&& where.z >= co->minz && where.z <= co->maxz
&& fracTime >= 0.0 && fracTime <= 0.0 ) {
MVector objVelAlongNormal = (objectVel * normal)
* normal;
MVector objVelAlongTangent = objectVel
- objVelAlongNormal;
MVector pntVelAlongTangent = v - ( v * normal )
* normal;
MVector reflectedPntVelAlongTangent
= pntVelAlongTangent * ( 1.0 - friction )
+ objVelAlongTangent * friction;
+ reflectedPntVelAlongTangent;
if ( fracAlongSeg > 0.5 ) {
MVector deltaPos = -newVel * fracTime;
hairPositionsLast[seg + 1] += deltaPos;
hairPositions[seg + 1] = hairPositionsLast[seg]
+ newVel;
} else {
MVector deltaPos = newVel * fracTime;
hairPositionsLast[seg] += deltaPos;
hairPositions[seg] = hairPositionsLast[seg]
+ newVel;
}
segCollides = true;
}
bool inside = false;
if ( belowCollisionPlane( co, hairPositions[seg] ) ) {
hairPositions[seg].y = co->maxy + EPSILON;
hairPositionsLast[seg] = hairPositions[seg] - objectVel;
inside = true;
}
if ( belowCollisionPlane( co, hairPositions[seg+1] ) ) {
hairPositions[seg+1].y = co->maxy + EPSILON;
hairPositionsLast[seg+1] = hairPositions[seg+1] - objectVel;
inside = true;
}
if ( segCollides || inside ) {
goto nextSeg;
}
}
}
nextSeg:;
}
}
return( true );
}
{
MFnPlugin plugin( obj,
"Autodesk",
"8.0",
"Any" );
return( MS::kSuccess );
}
{
return( MS::kSuccess );
}