[an error occurred while processing this directive]
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // // // Project: Talina Gaming System (TgS) (∂) // File: TgS Collision - Triangle-Particle.cpp // Author: Andrew Aye (EMail: andrew.aye@gmail.com, Web: http://www.andrewaye.com) // Version: 3.11 // // ------------------------------------------------------------------------------------------------------------------------------ // // // Copyright: © 2002-2008, Andrew Aye. All Rights Reserved. // // This software is free for non-commercial use. Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: // Redistributions of source code must retain this copyright notice, this list of conditions and the following disclaimers. // Redistributions in binary form must reproduce this copyright notice, this list of conditions and the following // disclaimers in the documentation and other materials provided with the distribution. // // Neither the names of the copyright owner nor the names of its contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // The intellectual property rights of the algorithms used reside with Andrew Aye. You may not use this software, in whole or // in part, in support of any commercial product without the express written consent of the author. // // There is no warranty or other guarantee of fitness of this software for any purpose. It is provided solely "as is". // // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // namespace TGS { // START TGS /////////////////////////////////////////////////////////////////////////////////////////////////////// namespace COL { // START COL /////////////////////////////////////////////////////////////////////////////////////////////////////// // ============================================================================================================================== // // ---- F_Internal_Sweep -------------------------------------------------------------------------------------------------------- // // // The culling situation for a particle is complicated by its parabolic path of motion. Back face culling is done on a point by // point basis. Thus, it is possible for a particle to ignore a triangle as it comes up through the back face and then collide // with it as it descends through the front face. // // Input: tgET0: Edge triangle primitive - also undergoing a linear translation // Input: tgPC0: Particle - this primitive is undergoing the sweep/translation. // Input: tvRV: Relative velocity of the particle // Output: tgContact: Contact point if one is registered for the time period. // Return: Result Code // ------------------------------------------------------------------------------------------------------------------------------ // template <typename TYPE, int DIM> TgRESULT F_Internal_Sweep( PC_(CONTACT,DIM) ptgContact, CR_(PARTICLE,DIM) tgPC0, M_(VECTOR,DIM) tvRV, CR_(ETRI,DIM) tgET0 ) { C_(VECTOR,DIM) tvK0 = MATH::F_SUB( tgPC0.Query_Position(), tgET0.Query_Origin() ); const TYPE tyDist = MATH::F_DOT( tgET0.Query_Normal(), tvK0 ); const TYPE tyA_N = MATH::F_DOT( tgET0.Query_Normal(), tgPC0.Query_Acceleration() ); const TYPE tyRV_N = MATH::F_DOT (tgET0.Query_Normal(), tvRV ); // Check to see if the particle is moving away from the triangle plane. if (tyDist > TYPE(0.0) && tyRV_N >= TYPE(0.0) && tyA_N >= TYPE(0.0)) { return (TgE_NOINTERSECT); }; if (tyDist < TYPE(0.0) && tyRV_N <= TYPE(0.0) && tyA_N <= TYPE(0.0)) { return (TgE_NOINTERSECT); }; TYPE tyT0; if (Near_Zero( tyA_N )) { // The particle's acceleration is completely parallel to the triangle plane. In this case, intersection can only exist // if there is a velocity component towards the triangle. In that case, the equation is only first order (linear). If // the velocity's projection onto the triangle normal is positive then the particle can only intersect with the back face // of the triangle - a case which is ignored. if (tyRV_N >= TYPE(0.0) || Near_Zero( tyRV_N )) { return (TgE_NOINTERSECT); }; tyT0 = -tyDist / tyRV_N; if (tyT0 < TYPE(0.0)) { // Sanity check - this can occur because floating point error and epsilon testing. return (TgE_NOINTERSECT); }; } else { // The particle has an acceleration component towards the triangle plane. The equation of motion is a quadratic and thus, // will have two solutions. The desired answer will be the first positive root. const TYPE tyDSC = tyRV_N*tyRV_N - TYPE(2.0)*tyA_N*tyDist; if (tyDSC < TYPE(0.0)) { // There is no real result for the given discriminant. This should never occur given the other logic before this // point. Register an error and return a non-intersection. COUT_NOOBJ( ERROR, TgT("%-16.16s(%-48.48s): [PA][ET] Unexpected invalid discriminant in calculation.\n"), TgT("Collision"), TgT("F_Internal_Sweep") ); return (TgE_NOINTERSECT); }; // The math dictates that only one solution can possibly satisfy the constraints on the solution. Specifically, the // requirement that the velocity of the particle at the time of intersection have a negative projection on the triangle's // normal eliminates the second root of the solution set. // N_(r + t•a,DIM) < 0.0, t = (-(r•N) ± β) / (a•N) // N•r + t_(N•a,DIM) < 0.0 // N•r + ((-(r•N) ± β) / (a•N))T_(N•a,DIM) < 0.0 // N•r + (-(r•N) ± β) < 0.0 // ± β < 0.0 // β is known to always be positive since the solution space is restricted to the real plane. The root constructed with // the positive square root value can never satisfy the velocity requirement, and thus, can always be ignored. const TYPE tySQRT_DSC = P::SQRT( tyDSC ); // Check to see if the derived value for T0 would be negative, and if so, return with no intersection. if ((tyA_N > TYPE(0.0) && -tyRV_N < tySQRT_DSC) || (tyA_N < TYPE(0.0) && -tyRV_N > tySQRT_DSC)) { return (TgE_NOINTERSECT); }; tyT0 = (-tyRV_N - tySQRT_DSC) / tyA_N; }; // Compute the point on the triangle plane and then test to see if its contained within the triangle itself. C_(VECTOR,DIM) tvK1 = MATH::F_ADD( tgPC0.Query_Position(), MATH::F_MUL( tvRV, tyT0 ) ); ptgContact->m_tvPos = MATH::F_ADD( tvK1, MATH::F_MUL( tgPC0.Query_Acceleration(), tyT0*tyT0 ) ); ptgContact->m_tvNormal = tgET0.Query_Normal(); ptgContact->m_tyT0 = tyT0; ptgContact->m_tyDepth = TYPE(0.0); return (TgS_OK); }; template TgRESULT F_Internal_Sweep( PC_TgF4CONTACT, CR_TgF4PARTICLE, M_TgF4VECTOR, CR_TgF4ETRI ); // ============================================================================================================================== // // ---- F_Contact_Sweep --------------------------------------------------------------------------------------------------------- // // Input: tgPacket: Contact generation parameters // Input: tyPM: Current normalized time of first contact for the contact query set. // Input: tgET0: Edge triangle primitive - also undergoing a linear translation // Input: tgPC0: Particle - this primitive is undergoing the sweep/translation. // Input: tgDT: A structure holding the swept primitive displacement for the entire duration of the test period. // Output: tgPacket: Contact points are added or replace the current set depending on the time comparison and given parameters // Output: tyPM: New normalized time of first contact // Return: Result Code // ------------------------------------------------------------------------------------------------------------------------------ // template <typename TYPE, int DIM> TgRESULT F_Contact_Sweep( PC_(CONTACT_PACKET,DIM) ptgPacket, TYPE *ptyPM, CR_(PARTICLE,DIM) tgPC0, CR_(ETRI,DIM) tgET0, CR_(DELTA,DIM) tgDT ) { TgBLOCK_FCN_NOOBJ(ETgFAC_COLLISION, 0, ETgTEST_SWEEP, (((TgUINT)ETgPARTICLE<<16)|(TgUINT)ETgTRIANGLE)) TgASSERT((TgSIZE)ptgPacket->m_iStride >= sizeof( P_(CONTACT,DIM) )) TgASSERT(tgET0.Is_Valid() && tgPC0.Is_Valid()) if (0 == ptgPacket->m_niMaxContact || ptgPacket->m_niContact >= ptgPacket->m_niMaxContact || NULL == ptgPacket->m_ptgContact) { return (TgE_FAIL); }; T_(CONTACT,DIM) tgContact; C_TgRESULT tgResult = F_Internal_Sweep( &tgContact, tgPC0, MATH::F_SUB( tgPC0.Query_Velocity(), tgDT.m_tvDT ), tgET0 ); if (TgFAILED( tgResult )) { return (tgResult); }; if (tgContact.m_tyT0 > *ptyPM + ptgPacket->m_tySweepTol || !tgET0.Is_Contained( tgContact.m_tvPos )) { return (TgE_NOINTERSECT); }; if (tgContact.m_tyT0 < *ptyPM - ptgPacket->m_tySweepTol) { ptgPacket->m_niContact = 0; *ptyPM = tgContact.m_tyT0; }; P_(CONTACT,DIM) ptgContact; ptgContact = (P_(CONTACT,DIM))((PC_TgUINT08)ptgPacket->m_ptgContact + ptgPacket->m_niContact*ptgPacket->m_iStride); ptgContact->m_tvPos = tgContact.m_tvPos; ptgContact->m_tvNormal = tgContact.m_tvNormal; ptgContact->m_tyT0 = tgContact.m_tyT0; ptgContact->m_tyDepth = tgContact.m_tyDepth; ++ptgPacket->m_niContact; return (TgS_OK); }; template TgRESULT F_Contact_Sweep( PC_TgF4CONTACT_PACKET, P_TgFLOAT32, CR_TgF4PARTICLE, CR_TgF4ETRI, CR_TgF4DELTA ); // ============================================================================================================================== // // ---- F_Contact_Sweep --------------------------------------------------------------------------------------------------------- // // Input: tgPacket: Contact generation parameters // Input: tyPM: Current normalized time of first contact for the contact query set. // Input: tgST0: Space triangle primitive - also undergoing a linear translation // Input: tgPC0: Particle - this primitive is undergoing the sweep/translation. // Input: tgDT: A structure holding the swept primitive displacement for the entire duration of the test period. // Output: tgPacket: Contact points are added or replace the current set depending on the time comparison and given parameters // Output: tyPM: New normalized time of first contact // Return: Result Code // ------------------------------------------------------------------------------------------------------------------------------ // template <typename TYPE, int DIM> TgRESULT F_Contact_Sweep( PC_(CONTACT_PACKET,DIM) ptgPacket, TYPE *ptyPM, CR_(PARTICLE,DIM) tgPC0, CR_(STRI,DIM) tgST0, CR_(DELTA,DIM) tgDT ) { TgBLOCK_FCN_NOOBJ(ETgFAC_COLLISION, 0, ETgTEST_SWEEP, (((TgUINT)ETgPARTICLE<<16)|(TgUINT)ETgTRIANGLE)) TgASSERT((TgSIZE)ptgPacket->m_iStride >= sizeof( P_(CONTACT,DIM) )) TgASSERT(tgST0.Is_Valid() && tgPC0.Is_Valid()) if (0 == ptgPacket->m_niMaxContact || ptgPacket->m_niContact >= ptgPacket->m_niMaxContact || NULL == ptgPacket->m_ptgContact) { return (TgE_FAIL); }; T_(CONTACT,DIM) tgContact; C_TgRESULT tgResult = F_Internal_Sweep( &tgContact, tgPC0, MATH::F_SUB( tgPC0.Query_Velocity(), tgDT.m_tvDT ), tgST0.Query_ET() ); if (TgFAILED( tgResult )) { return (tgResult); }; if (tgContact.m_tyT0 > *ptyPM + ptgPacket->m_tySweepTol || !tgST0.Is_Contained( tgContact.m_tvPos )) { return (TgE_NOINTERSECT); }; if (tgContact.m_tyT0 < *ptyPM - ptgPacket->m_tySweepTol) { ptgPacket->m_niContact = 0; *ptyPM = tgContact.m_tyT0; }; P_(CONTACT,DIM) ptgContact; ptgContact = (P_(CONTACT,DIM))((PC_TgUINT08)ptgPacket->m_ptgContact + ptgPacket->m_niContact*ptgPacket->m_iStride); ptgContact->m_tvPos = tgContact.m_tvPos; ptgContact->m_tvNormal = tgContact.m_tvNormal; ptgContact->m_tyT0 = tgContact.m_tyT0; ptgContact->m_tyDepth = tgContact.m_tyDepth; ++ptgPacket->m_niContact; return (TgS_OK); }; template TgRESULT F_Contact_Sweep( PC_TgF4CONTACT_PACKET, P_TgFLOAT32, CR_TgF4PARTICLE, CR_TgF4STRI, CR_TgF4DELTA ); // ============================================================================================================================== // // ---- F_Contact_Sweep --------------------------------------------------------------------------------------------------------- // // Input: tgPacket: Contact generation parameters // Input: tyPM: Current normalized time of first contact for the contact query set. // Input: tgET0: Edge triangle primitive // Input: tgPC0: Particle - this primitive is undergoing the sweep/translation. // Output: tgPacket: Contact points are added or replace the current set depending on the time comparison and given parameters // Output: tyPM: New normalized time of first contact // Return: Result Code // ------------------------------------------------------------------------------------------------------------------------------ // template <typename TYPE, int DIM> TgRESULT F_Contact_Sweep( PC_(CONTACT_PACKET,DIM) ptgPacket, TYPE *ptyPM, CR_(ETRI,DIM) tgET0, CR_(PARTICLE,DIM) tgPC0 ) { TgBLOCK_FCN_NOOBJ(ETgFAC_COLLISION, 0, ETgTEST_SWEEP, (((TgUINT)ETgTRIANGLE<<16)|(TgUINT)ETgPARTICLE)) TgASSERT((TgSIZE)ptgPacket->m_iStride >= sizeof( P_(CONTACT,DIM) )) TgASSERT(tgET0.Is_Valid() && tgPC0.Is_Valid()) if (0 == ptgPacket->m_niMaxContact || ptgPacket->m_niContact >= ptgPacket->m_niMaxContact || NULL == ptgPacket->m_ptgContact) { return (TgE_FAIL); }; T_(CONTACT,DIM) tgContact; C_TgRESULT tgResult = F_Internal_Sweep( &tgContact, tgPC0, tgPC0.Query_Velocity(), tgET0 ); if (TgFAILED( tgResult )) { return (tgResult); }; if (tgContact.m_tyT0 > *ptyPM + ptgPacket->m_tySweepTol || !tgET0.Is_Contained( tgContact.m_tvPos )) { return (TgE_NOINTERSECT); }; if (tgContact.m_tyT0 < *ptyPM - ptgPacket->m_tySweepTol) { ptgPacket->m_niContact = 0; *ptyPM = tgContact.m_tyT0; }; P_(CONTACT,DIM) ptgContact; ptgContact = (P_(CONTACT,DIM))((PC_TgUINT08)ptgPacket->m_ptgContact + ptgPacket->m_niContact*ptgPacket->m_iStride); ptgContact->m_tvPos = tgContact.m_tvPos; ptgContact->m_tvNormal = tgContact.m_tvNormal; ptgContact->m_tyT0 = tgContact.m_tyT0; ptgContact->m_tyDepth = tgContact.m_tyDepth; ++ptgPacket->m_niContact; return (TgS_OK); }; template TgRESULT F_Contact_Sweep( PC_TgF4CONTACT_PACKET, P_TgFLOAT32, CR_TgF4ETRI, CR_TgF4PARTICLE ); // ============================================================================================================================== // // ---- F_Contact_Sweep --------------------------------------------------------------------------------------------------------- // // Input: tgPacket: Contact generation parameters // Input: tyPM: Current normalized time of first contact for the contact query set. // Input: tgST0: Space triangle primitive // Input: tgPC0: Particle - this primitive is undergoing the sweep/translation. // Output: tgPacket: Contact points are added or replace the current set depending on the time comparison and given parameters // Output: tyPM: New normalized time of first contact // Return: Result Code // ------------------------------------------------------------------------------------------------------------------------------ // template <typename TYPE, int DIM> TgRESULT F_Contact_Sweep( PC_(CONTACT_PACKET,DIM) ptgPacket, TYPE *ptyPM, CR_(STRI,DIM) tgST0, CR_(PARTICLE,DIM) tgPC0 ) { TgBLOCK_FCN_NOOBJ(ETgFAC_COLLISION, 0, ETgTEST_SWEEP, (((TgUINT)ETgTRIANGLE<<16)|(TgUINT)ETgPARTICLE)) TgASSERT((TgSIZE)ptgPacket->m_iStride >= sizeof( P_(CONTACT,DIM) )) TgASSERT(tgST0.Is_Valid() && tgPC0.Is_Valid()) if (0 == ptgPacket->m_niMaxContact || ptgPacket->m_niContact >= ptgPacket->m_niMaxContact || NULL == ptgPacket->m_ptgContact) { return (TgE_FAIL); }; T_(CONTACT,DIM) tgContact; C_TgRESULT tgResult = F_Internal_Sweep( &tgContact, tgPC0, tgPC0.Query_Velocity(), tgST0.Query_ET() ); if (TgFAILED( tgResult )) { return (tgResult); }; if (tgContact.m_tyT0 > *ptyPM + ptgPacket->m_tySweepTol || !tgST0.Is_Contained( tgContact.m_tvPos )) { return (TgE_NOINTERSECT); }; if (tgContact.m_tyT0 < *ptyPM - ptgPacket->m_tySweepTol) { ptgPacket->m_niContact = 0; *ptyPM = tgContact.m_tyT0; }; P_(CONTACT,DIM) ptgContact; ptgContact = (P_(CONTACT,DIM))((PC_TgUINT08)ptgPacket->m_ptgContact + ptgPacket->m_niContact*ptgPacket->m_iStride); ptgContact->m_tvPos = tgContact.m_tvPos; ptgContact->m_tvNormal = tgContact.m_tvNormal; ptgContact->m_tyT0 = tgContact.m_tyT0; ptgContact->m_tyDepth = tgContact.m_tyDepth; ++ptgPacket->m_niContact; return (TgS_OK); }; template TgRESULT F_Contact_Sweep( PC_TgF4CONTACT_PACKET, P_TgFLOAT32, CR_TgF4STRI, CR_TgF4PARTICLE ); // ============================================================================================================================== // }; // END COL ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// }; // END TGS //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////[an error occurred while processing this directive]