// culls backfaces bool MFCollision_RayTriCullTest(const MFVector& rayPos, const MFVector& rayDir, const MFVector& p0, const MFVector& p1, const MFVector& p2, float *pT, float *pU, float *pV, MFVector *pIntersectionPoint) { MFVector edge1, edge2, tvec, pvec, qvec; float det, inv_det; float u, v; /* find vectors for two edges sharing vert0 */ edge1 = p1 - p0; edge2 = p2 - p0; /* begin calculating determinant - also used to calculate U parameter */ pvec.Cross3(rayDir, edge2); /* if determinant is near zero, ray lies in plane of triangle */ det = edge1.Dot3(pvec); if (det < MFALMOST_ZERO) return false; /* calculate distance from vert0 to ray origin */ tvec = rayPos - p0; /* calculate U parameter and test bounds */ u = tvec.Dot3(pvec); if (u < 0.0f || u > det) return false; /* prepare to test V parameter */ qvec.Cross3(tvec, edge1); /* calculate V parameter and test bounds */ v = rayDir.Dot3(qvec); if (v < 0.0f || u + v > det) return false; /* calculate t, scale parameters, ray intersects triangle */ if(pIntersectionPoint || pT || pU) { inv_det = 1.0f / det; u *= inv_det; v *= inv_det; if(pT) *pT = edge2.Dot3(qvec) * inv_det; if(pU) { *pU = u; *pV = v; } if(pIntersectionPoint) { *pIntersectionPoint = p0*(1.0f-u-v) + p1*u + p2*v; } } return true; }
bool MFCollision_RaySlabTest(const MFVector& rayPos, const MFVector& rayDir, const MFVector& plane, float slabHalfWidth, MFRayIntersectionResult *pResult) { float a = plane.Dot3(rayDir); // if ray is parallel to plane if(a > -MFALMOST_ZERO && a < MFALMOST_ZERO) { // TODO: this is intentionally BROKEN // this is a near impossible case, and it adds a lot of junk to the function /* if(MFAbs(rayPos.DotH(plane)) <= slabHalfWidth) { if(pResult) { pResult->time = 0.0f; } return true; } */ return false; } // otherwise we can do the conventional test float inva = MFRcp(a); float t = -rayPos.DotH(plane); float t1 = (t + slabHalfWidth) * inva; float t2 = (t - slabHalfWidth) * inva; t = MFMin(t1, t2); t2 = MFMax(t1, t2); if(t > 1.0f || t2 < 0.0f) return false; if(pResult) { pResult->time = MFMax(t, 0.0f); pResult->surfaceNormal = a > 0.0f ? -plane : plane; } return true; }
bool MFCollision_RayCylinderTest(const MFVector& rayPos, const MFVector& rayDir, const MFVector& cylinderPos, const MFVector& cylinderDir, float cylinderRadius, bool capped, MFRayIntersectionResult *pResult, float *pCylinderTime) { MFVector local = rayPos - cylinderPos; float rayD = rayDir.Dot3(cylinderDir); float T0 = local.Dot3(cylinderDir); // bring T0 into 0.0-1.0 range float invMagSq = MFRcp(cylinderDir.MagSquared3()); rayD *= invMagSq; T0 *= invMagSq; // calculate some intermediate vectors MFVector v1 = rayDir - rayD*cylinderDir; MFVector v2 = local - T0*cylinderDir; // calculate coeff in quadratic formula float a = v1.MagSquared3(); float b = (2.0f*v1).Dot3(v2); float c = v2.MagSquared3() - cylinderRadius*cylinderRadius; // calculate the stuff under the root sign, if it's negative no (real) solutions exist float d = b*b - 4.0f*a*c; if(d < 0.0f) // this means ray misses cylinder return false; float root = MFSqrt(d); float rcp2a = MFRcp(2.0f*a); float t1 = (-b - root)*rcp2a; float t2 = (-b + root)*rcp2a; if(t1 > 1.0f || t2 < 0.0f) return false; // the cylinder is beyond the ray.. if(capped || pCylinderTime || pResult) { float t = MFMax(t1, 0.0f); // get the t for the cylinders ray MFVector intersectedRay; intersectedRay.Mad3(rayDir, t, local); float ct = intersectedRay.Dot3(cylinderDir) * invMagSq; if(capped && (ct < 0.0f || ct > 1.0f)) { // we need to test the caps // TODO: this is REALLY slow!! can be majorly improved!! // generate a plane for the cap MFVector point, plane; if(rayD > 0.0f) { // the near one point = cylinderPos; plane = MFCollision_MakePlaneFromPointAndNormal(point, -cylinderDir); } else { // the far one point = cylinderPos + cylinderDir; plane = MFCollision_MakePlaneFromPointAndNormal(point, cylinderDir); } // test the ray against the plane bool collide = MFCollision_RayPlaneTest(rayPos, rayDir, plane, pResult); if(collide) { // calculate the intersection point intersectedRay.Mad3(rayDir, pResult->time, rayPos); intersectedRay.Sub3(intersectedRay, point); // and see if its within the cylinders radius if(intersectedRay.MagSquared3() <= cylinderRadius * cylinderRadius) { return true; } } return false; } if(pResult) { pResult->time = t; pResult->surfaceNormal.Mad3(cylinderDir, -ct, intersectedRay); pResult->surfaceNormal.Normalise3(); } if(pCylinderTime) { *pCylinderTime = ct; } } return true; }
MF_API void MFParticleSystem_AddParticle(MFParticleEmitter *pEmitter) { MFParticleEmitterParameters *pE = &pEmitter->params; MFParticleSystem *pParticleSystem = pE->pParticleSystem; MFParticle *pNew = NULL; if(pParticleSystem->particles.GetLength() < pParticleSystem->params.maxActiveParticles) pNew = pParticleSystem->particles.Create(); if(pNew) { MFParticleParameters *pP = &pParticleSystem->params; pNew->colour = pP->colour; pNew->life = pP->life; pNew->rot = 0.0f; pNew->size = pP->size; switch(pE->type) { case MFET_Point: pNew->pos = pE->position.GetTrans(); break; case MFET_Sphere: case MFET_Disc: { MFVector offset; do { offset = MakeVector(MFRand_Range(-pE->radius, pE->radius), MFRand_Range(-pE->radius, pE->radius), MFRand_Range(-pE->radius, pE->radius)); } while(offset.MagSquared3() > pE->radius*pE->radius); if(pE->type == MFET_Disc) { // flatten it on to the disc float dist = offset.Dot3(pE->position.GetYAxis()); offset -= pE->position.GetYAxis()*dist; } pNew->pos = pE->position.GetTrans() + offset; break; } } switch(pE->behaviour) { case MFEB_Direction: pNew->velocity.Normalise3(pE->startVector); break; case MFEB_TargetAttract: pNew->velocity.Normalise3(pE->startVector - pE->position.GetTrans()); break; case MFEB_TargetRepel: pNew->velocity.Normalise3(pE->position.GetTrans() - pE->startVector); break; } pNew->velocity *= pE->velocity + MFRand_Range(-pE->velocityScatter, pE->velocityScatter); if(pE->directionScatter) { MFVector scatter; do { scatter = MakeVector(MFRand_Range(-1, 1), MFRand_Range(-1, 1), MFRand_Range(-1, 1)); float dist = scatter.Dot3(pE->position.GetYAxis()); scatter -= pE->position.GetYAxis()*dist; } while(scatter.MagSquared3() < 0.000001f); scatter.Normalise3(); MFMatrix scatterMat; scatterMat.SetRotation(scatter, MFRand_Unit()*pE->directionScatter); pNew->velocity = ApplyMatrixH(pNew->velocity, scatterMat); } } }