Compare commits
21 Commits
collision_
...
main
Author | SHA1 | Date | |
---|---|---|---|
7851f45134 | |||
bc8f81bb4c | |||
3a73c9aa4b | |||
08acb860c1 | |||
beba85290c | |||
640d3fdcbe | |||
42f5d84744 | |||
59280cc06c | |||
4525e80a60 | |||
696a979395 | |||
b1fe6eebb4 | |||
b85098fcaa | |||
33f24d6b17 | |||
14644e4f5f | |||
96d6ff59d1 | |||
078fc33309 | |||
7689205279 | |||
619246407c | |||
8d77c326de | |||
cccb93fd34 | |||
a353893266 |
5
.gitignore
vendored
5
.gitignore
vendored
@ -1,3 +1,8 @@
|
||||
__pycache__
|
||||
.bck
|
||||
out
|
||||
target
|
||||
build
|
||||
# Compiled source #
|
||||
###################
|
||||
*.com
|
||||
|
29
GLD_ephysics-test.json
Normal file
29
GLD_ephysics-test.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"type":"BINARY",
|
||||
"sub-type":"TEST",
|
||||
"group-id":"com.atria-soft",
|
||||
"description":"Ewol Physic engine TEST UNIT",
|
||||
"license":"MPL-2",
|
||||
"license-file":"file://LICENSE",
|
||||
"maintainer":"file://authors.txt",
|
||||
"author":"file://authors.txt",
|
||||
"version":"file://version.txt",
|
||||
"code-quality":"MEDIUM",
|
||||
|
||||
"source": [
|
||||
"test/main.cpp",
|
||||
"test/testAABB.cpp",
|
||||
"test/testCollisionWorld.cpp",
|
||||
"test/testDynamicAABBTree.cpp",
|
||||
"test/testPointInside.cpp",
|
||||
"test/testRaycast.cpp"
|
||||
],
|
||||
"path":[
|
||||
"."
|
||||
],
|
||||
"dependency": [
|
||||
"ephysics",
|
||||
"etest",
|
||||
"test-debug"
|
||||
]
|
||||
}
|
145
GLD_ephysics.json
Normal file
145
GLD_ephysics.json
Normal file
@ -0,0 +1,145 @@
|
||||
{
|
||||
"type":"LIBRARY",
|
||||
"group-id":"com.atria-soft",
|
||||
"description":"Algorithm generic",
|
||||
"license":"MPL-2",
|
||||
"license-file":"file://LICENSE",
|
||||
"maintainer":"file://authors.txt",
|
||||
"author":"file://authors.txt",
|
||||
"version":"file://version.txt",
|
||||
"code-quality":"MEDIUM",
|
||||
|
||||
"source": [
|
||||
"ephysics/debug.cpp",
|
||||
"ephysics/constraint/Joint.cpp",
|
||||
"ephysics/constraint/HingeJoint.cpp",
|
||||
"ephysics/constraint/ContactPoint.cpp",
|
||||
"ephysics/constraint/BallAndSocketJoint.cpp",
|
||||
"ephysics/constraint/SliderJoint.cpp",
|
||||
"ephysics/constraint/FixedJoint.cpp",
|
||||
"ephysics/collision/ContactManifoldSet.cpp",
|
||||
"ephysics/collision/RaycastInfo.cpp",
|
||||
"ephysics/collision/narrowphase/GJK/Simplex.cpp",
|
||||
"ephysics/collision/narrowphase/GJK/GJKAlgorithm.cpp",
|
||||
"ephysics/collision/narrowphase/DefaultCollisionDispatch.cpp",
|
||||
"ephysics/collision/narrowphase/SphereVsSphereAlgorithm.cpp",
|
||||
"ephysics/collision/narrowphase/NarrowPhaseAlgorithm.cpp",
|
||||
"ephysics/collision/narrowphase/ConcaveVsConvexAlgorithm.cpp",
|
||||
"ephysics/collision/narrowphase/EPA/EPAAlgorithm.cpp",
|
||||
"ephysics/collision/narrowphase/EPA/TrianglesStore.cpp",
|
||||
"ephysics/collision/narrowphase/EPA/TriangleEPA.cpp",
|
||||
"ephysics/collision/narrowphase/EPA/EdgeEPA.cpp",
|
||||
"ephysics/collision/ProxyShape.cpp",
|
||||
"ephysics/collision/shapes/ConcaveShape.cpp",
|
||||
"ephysics/collision/shapes/CylinderShape.cpp",
|
||||
"ephysics/collision/shapes/SphereShape.cpp",
|
||||
"ephysics/collision/shapes/CapsuleShape.cpp",
|
||||
"ephysics/collision/shapes/ConvexMeshShape.cpp",
|
||||
"ephysics/collision/shapes/CollisionShape.cpp",
|
||||
"ephysics/collision/shapes/BoxShape.cpp",
|
||||
"ephysics/collision/shapes/TriangleShape.cpp",
|
||||
"ephysics/collision/shapes/HeightFieldShape.cpp",
|
||||
"ephysics/collision/shapes/ConvexShape.cpp",
|
||||
"ephysics/collision/shapes/ConeShape.cpp",
|
||||
"ephysics/collision/shapes/ConcaveMeshShape.cpp",
|
||||
"ephysics/collision/shapes/AABB.cpp",
|
||||
"ephysics/collision/TriangleMesh.cpp",
|
||||
"ephysics/collision/CollisionDetection.cpp",
|
||||
"ephysics/collision/TriangleVertexArray.cpp",
|
||||
"ephysics/collision/ContactManifold.cpp",
|
||||
"ephysics/collision/broadphase/DynamicAABBTree.cpp",
|
||||
"ephysics/collision/broadphase/BroadPhaseAlgorithm.cpp",
|
||||
"ephysics/body/RigidBody.cpp",
|
||||
"ephysics/body/Body.cpp",
|
||||
"ephysics/body/CollisionBody.cpp",
|
||||
"ephysics/mathematics/mathematics_functions.cpp",
|
||||
"ephysics/engine/CollisionWorld.cpp",
|
||||
"ephysics/engine/OverlappingPair.cpp",
|
||||
"ephysics/engine/Material.cpp",
|
||||
"ephysics/engine/Island.cpp",
|
||||
"ephysics/engine/Profiler.cpp",
|
||||
"ephysics/engine/ConstraintSolver.cpp",
|
||||
"ephysics/engine/DynamicsWorld.cpp",
|
||||
"ephysics/engine/ContactSolver.cpp",
|
||||
"ephysics/engine/Timer.cpp"
|
||||
],
|
||||
"header": [
|
||||
"ephysics/debug.hpp",
|
||||
"ephysics/memory/Stack.hpp",
|
||||
"ephysics/constraint/BallAndSocketJoint.hpp",
|
||||
"ephysics/constraint/Joint.hpp",
|
||||
"ephysics/constraint/FixedJoint.hpp",
|
||||
"ephysics/constraint/HingeJoint.hpp",
|
||||
"ephysics/constraint/ContactPoint.hpp",
|
||||
"ephysics/constraint/SliderJoint.hpp",
|
||||
"ephysics/collision/TriangleVertexArray.hpp",
|
||||
"ephysics/collision/ContactManifold.hpp",
|
||||
"ephysics/collision/ContactManifoldSet.hpp",
|
||||
"ephysics/collision/narrowphase/SphereVsSphereAlgorithm.hpp",
|
||||
"ephysics/collision/narrowphase/GJK/Simplex.hpp",
|
||||
"ephysics/collision/narrowphase/GJK/GJKAlgorithm.hpp",
|
||||
"ephysics/collision/narrowphase/ConcaveVsConvexAlgorithm.hpp",
|
||||
"ephysics/collision/narrowphase/CollisionDispatch.hpp",
|
||||
"ephysics/collision/narrowphase/DefaultCollisionDispatch.hpp",
|
||||
"ephysics/collision/narrowphase/NarrowPhaseAlgorithm.hpp",
|
||||
"ephysics/collision/narrowphase/EPA/EdgeEPA.hpp",
|
||||
"ephysics/collision/narrowphase/EPA/EPAAlgorithm.hpp",
|
||||
"ephysics/collision/narrowphase/EPA/TrianglesStore.hpp",
|
||||
"ephysics/collision/narrowphase/EPA/TriangleEPA.hpp",
|
||||
"ephysics/collision/CollisionDetection.hpp",
|
||||
"ephysics/collision/shapes/TriangleShape.hpp",
|
||||
"ephysics/collision/shapes/AABB.hpp",
|
||||
"ephysics/collision/shapes/CapsuleShape.hpp",
|
||||
"ephysics/collision/shapes/SphereShape.hpp",
|
||||
"ephysics/collision/shapes/CollisionShape.hpp",
|
||||
"ephysics/collision/shapes/BoxShape.hpp",
|
||||
"ephysics/collision/shapes/ConcaveMeshShape.hpp",
|
||||
"ephysics/collision/shapes/ConvexMeshShape.hpp",
|
||||
"ephysics/collision/shapes/HeightFieldShape.hpp",
|
||||
"ephysics/collision/shapes/CylinderShape.hpp",
|
||||
"ephysics/collision/shapes/ConeShape.hpp",
|
||||
"ephysics/collision/shapes/ConvexShape.hpp",
|
||||
"ephysics/collision/shapes/ConcaveShape.hpp",
|
||||
"ephysics/collision/CollisionShapeInfo.hpp",
|
||||
"ephysics/collision/TriangleMesh.hpp",
|
||||
"ephysics/collision/RaycastInfo.hpp",
|
||||
"ephysics/collision/ProxyShape.hpp",
|
||||
"ephysics/collision/broadphase/DynamicAABBTree.hpp",
|
||||
"ephysics/collision/broadphase/BroadPhaseAlgorithm.hpp",
|
||||
"ephysics/configuration.hpp",
|
||||
"ephysics/ephysics.hpp",
|
||||
"ephysics/body/Body.hpp",
|
||||
"ephysics/body/RigidBody.hpp",
|
||||
"ephysics/body/CollisionBody.hpp",
|
||||
"ephysics/mathematics/mathematics.hpp",
|
||||
"ephysics/mathematics/Ray.hpp",
|
||||
"ephysics/mathematics/mathematics_functions.hpp",
|
||||
"ephysics/engine/CollisionWorld.hpp",
|
||||
"ephysics/engine/DynamicsWorld.hpp",
|
||||
"ephysics/engine/ConstraintSolver.hpp",
|
||||
"ephysics/engine/OverlappingPair.hpp",
|
||||
"ephysics/engine/Island.hpp",
|
||||
"ephysics/engine/ContactSolver.hpp",
|
||||
"ephysics/engine/Material.hpp",
|
||||
"ephysics/engine/Profiler.hpp",
|
||||
"ephysics/engine/Timer.hpp",
|
||||
"ephysics/engine/Impulse.hpp",
|
||||
"ephysics/engine/EventListener.hpp"
|
||||
],
|
||||
"path":[
|
||||
"."
|
||||
],
|
||||
"compilation-version": {
|
||||
"c++": 2011
|
||||
},
|
||||
"dependency": [
|
||||
"m",
|
||||
"elog",
|
||||
"etk",
|
||||
"ememory",
|
||||
"echrono"
|
||||
],
|
||||
"flag":{
|
||||
"c++": "-Wno-overloaded-virtual"
|
||||
}
|
||||
}
|
389
LICENSE
389
LICENSE
@ -1,20 +1,379 @@
|
||||
ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/
|
||||
Copyright (c) 2010-2016 Daniel Chappuis
|
||||
Original Licence
|
||||
================
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the
|
||||
use of this software.
|
||||
Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/>
|
||||
This code is re-licensed with permission from ReactPhysics3D author.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim
|
||||
that you wrote the original software. If you use this software in a
|
||||
product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
28
README.md
28
README.md
@ -1,18 +1,19 @@
|
||||
[](https://travis-ci.org/DanielChappuis/ephysics)
|
||||
[](https://travis-ci.org/atria-soft/ephysics)
|
||||
|
||||
## ReactPhysics3D
|
||||
## ephysics
|
||||
|
||||
ReactPhysics3D is an open source C++ physics engine library that can be used in 3D simulations and games.
|
||||
ephysics is an open source C++ physics engine library that can be used in 3D simulations and games.
|
||||
|
||||
Website : [http://www.ephysics.com](http://www.ephysics.com)
|
||||
Website: [http://www.ephysics.com](http://www.ephysics.com)
|
||||
|
||||
Author : Daniel Chappuis
|
||||
Author: Daniel CHAPPUIS (original project ReactPhysics3D)
|
||||
Author: Edouard DUPIN (forker)
|
||||
|
||||
<img src="https://raw.githubusercontent.com/DanielChappuis/ephysics/master/documentation/UserManual/images/testbed.png" alt="Drawing" height="400" />
|
||||
|
||||
## Features
|
||||
|
||||
ReactPhysics3D has the following features :
|
||||
ephysics has the following features:
|
||||
|
||||
- Rigid body dynamics
|
||||
- Discrete collision detection
|
||||
@ -34,18 +35,5 @@ ReactPhysics3D has the following features :
|
||||
|
||||
## License
|
||||
|
||||
The ReactPhysics3D library is released under the open-source BSD 3 clauses license.
|
||||
The ephysics library is released under the MPL-2 license.
|
||||
|
||||
## Documentation
|
||||
|
||||
You can find the User Manual and the Doxygen API Documentation [here](http://www.ephysics.com/documentation.html)
|
||||
|
||||
## Branches
|
||||
|
||||
The "master" branch always contains the last released version of the library and some possible bug fixes. This is the most stable version. On the other side,
|
||||
the "develop" branch is used for development. This branch is frequently updated and can be quite unstable. Therefore, if you want to use the library in
|
||||
your application, it is recommended to checkout the "master" branch.
|
||||
|
||||
## Issues
|
||||
|
||||
If you find any issue with the library, you can report it on the issue tracker [here](https://github.com/DanielChappuis/ephysics/issues).
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <ephysics/body/Body.hpp>
|
||||
@ -15,6 +18,6 @@ ephysics::Body::Body(bodyindex _id):
|
||||
m_isActive(true),
|
||||
m_isSleeping(false),
|
||||
m_sleepTime(0),
|
||||
m_userData(nullptr) {
|
||||
m_userData(null) {
|
||||
|
||||
}
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -151,7 +154,9 @@ namespace ephysics {
|
||||
bool operator!=(const Body& _obj) const {
|
||||
return (m_id != _obj.m_id);
|
||||
}
|
||||
// TODO : remove this
|
||||
friend class DynamicsWorld;
|
||||
friend class Island;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -1,10 +1,11 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
// Libraries
|
||||
#include <ephysics/body/CollisionBody.hpp>
|
||||
#include <ephysics/engine/CollisionWorld.hpp>
|
||||
#include <ephysics/collision/ContactManifold.hpp>
|
||||
@ -17,15 +18,22 @@ CollisionBody::CollisionBody(const etk::Transform3D& _transform, CollisionWorld&
|
||||
Body(_id),
|
||||
m_type(DYNAMIC),
|
||||
m_transform(_transform),
|
||||
m_proxyCollisionShapes(nullptr),
|
||||
m_proxyCollisionShapes(null),
|
||||
m_numberCollisionShapes(0),
|
||||
m_contactManifoldsList(nullptr),
|
||||
m_contactManifoldsList(null),
|
||||
m_world(_world) {
|
||||
|
||||
EPHY_DEBUG(" set transform: " << _transform);
|
||||
if (isnan(_transform.getPosition().x()) == true) { // check NAN
|
||||
EPHY_CRITICAL(" set transform: " << _transform);
|
||||
}
|
||||
if (isinf(_transform.getOrientation().z()) == true) {
|
||||
EPHY_CRITICAL(" set transform: " << _transform);
|
||||
}
|
||||
}
|
||||
|
||||
CollisionBody::~CollisionBody() {
|
||||
assert(m_contactManifoldsList == nullptr);
|
||||
assert(m_contactManifoldsList == null);
|
||||
|
||||
// Remove all the proxy collision shapes of the body
|
||||
removeAllCollisionShapes();
|
||||
@ -39,13 +47,24 @@ inline void CollisionBody::setType(BodyType _type) {
|
||||
}
|
||||
}
|
||||
|
||||
void CollisionBody::setTransform(const etk::Transform3D& _transform) {
|
||||
EPHY_DEBUG(" set transform: " << m_transform << " ==> " << _transform);
|
||||
if (isnan(_transform.getPosition().x()) == true) { // check NAN
|
||||
EPHY_CRITICAL(" set transform: " << m_transform << " ==> " << _transform);
|
||||
}
|
||||
if (isinf(_transform.getOrientation().z()) == true) {
|
||||
EPHY_CRITICAL(" set transform: " << m_transform << " ==> " << _transform);
|
||||
}
|
||||
m_transform = _transform;
|
||||
updateBroadPhaseState();
|
||||
}
|
||||
|
||||
ProxyShape* CollisionBody::addCollisionShape(CollisionShape* _collisionShape,
|
||||
const etk::Transform3D& _transform) {
|
||||
// Create a new proxy collision shape to attach the collision shape to the body
|
||||
ProxyShape* proxyShape = new ProxyShape(this, _collisionShape,_transform, float(1));
|
||||
// Create a proxy collision shape to attach the collision shape to the body
|
||||
ProxyShape* proxyShape = ETK_NEW(ProxyShape, this, _collisionShape,_transform, float(1));
|
||||
// Add it to the list of proxy collision shapes of the body
|
||||
if (m_proxyCollisionShapes == nullptr) {
|
||||
if (m_proxyCollisionShapes == null) {
|
||||
m_proxyCollisionShapes = proxyShape;
|
||||
} else {
|
||||
proxyShape->m_next = m_proxyCollisionShapes;
|
||||
@ -66,13 +85,13 @@ void CollisionBody::removeCollisionShape(const ProxyShape* _proxyShape) {
|
||||
if (m_isActive) {
|
||||
m_world.m_collisionDetection.removeProxyCollisionShape(current);
|
||||
}
|
||||
delete current;
|
||||
current = nullptr;
|
||||
ETK_DELETE(ProxyShape, current);
|
||||
current = null;
|
||||
m_numberCollisionShapes--;
|
||||
return;
|
||||
}
|
||||
// Look for the proxy shape that contains the collision shape in parameter
|
||||
while(current->m_next != nullptr) {
|
||||
while(current->m_next != null) {
|
||||
// If we have found the collision shape to remove
|
||||
if (current->m_next == _proxyShape) {
|
||||
// Remove the proxy collision shape
|
||||
@ -81,8 +100,8 @@ void CollisionBody::removeCollisionShape(const ProxyShape* _proxyShape) {
|
||||
if (m_isActive) {
|
||||
m_world.m_collisionDetection.removeProxyCollisionShape(elementToRemove);
|
||||
}
|
||||
delete elementToRemove;
|
||||
elementToRemove = nullptr;
|
||||
ETK_DELETE(ProxyShape, elementToRemove);
|
||||
elementToRemove = null;
|
||||
m_numberCollisionShapes--;
|
||||
return;
|
||||
}
|
||||
@ -95,36 +114,36 @@ void CollisionBody::removeCollisionShape(const ProxyShape* _proxyShape) {
|
||||
void CollisionBody::removeAllCollisionShapes() {
|
||||
ProxyShape* current = m_proxyCollisionShapes;
|
||||
// Look for the proxy shape that contains the collision shape in parameter
|
||||
while(current != nullptr) {
|
||||
while(current != null) {
|
||||
// Remove the proxy collision shape
|
||||
ProxyShape* nextElement = current->m_next;
|
||||
if (m_isActive) {
|
||||
m_world.m_collisionDetection.removeProxyCollisionShape(current);
|
||||
}
|
||||
delete current;
|
||||
ETK_DELETE(ProxyShape, current);
|
||||
// Get the next element in the list
|
||||
current = nextElement;
|
||||
}
|
||||
m_proxyCollisionShapes = nullptr;
|
||||
m_proxyCollisionShapes = null;
|
||||
}
|
||||
|
||||
|
||||
void CollisionBody::resetContactManifoldsList() {
|
||||
// Delete the linked list of contact manifolds of that body
|
||||
ContactManifoldListElement* currentElement = m_contactManifoldsList;
|
||||
while (currentElement != nullptr) {
|
||||
while (currentElement != null) {
|
||||
ContactManifoldListElement* nextElement = currentElement->next;
|
||||
// Delete the current element
|
||||
delete currentElement;
|
||||
ETK_DELETE(ContactManifoldListElement, currentElement);
|
||||
currentElement = nextElement;
|
||||
}
|
||||
m_contactManifoldsList = nullptr;
|
||||
m_contactManifoldsList = null;
|
||||
}
|
||||
|
||||
|
||||
void CollisionBody::updateBroadPhaseState() const {
|
||||
// For all the proxy collision shapes of the body
|
||||
for (ProxyShape* shape = m_proxyCollisionShapes; shape != nullptr; shape = shape->m_next) {
|
||||
for (ProxyShape* shape = m_proxyCollisionShapes; shape != null; shape = shape->m_next) {
|
||||
// Update the proxy
|
||||
updateProxyShapeInBroadPhase(shape);
|
||||
}
|
||||
@ -146,13 +165,13 @@ void CollisionBody::setIsActive(bool _isActive) {
|
||||
Body::setIsActive(_isActive);
|
||||
// If we have to activate the body
|
||||
if (_isActive == true) {
|
||||
for (ProxyShape* shape = m_proxyCollisionShapes; shape != nullptr; shape = shape->m_next) {
|
||||
for (ProxyShape* shape = m_proxyCollisionShapes; shape != null; shape = shape->m_next) {
|
||||
AABB aabb;
|
||||
shape->getCollisionShape()->computeAABB(aabb, m_transform * shape->m_localToBodyTransform);
|
||||
m_world.m_collisionDetection.addProxyCollisionShape(shape, aabb);
|
||||
}
|
||||
} else {
|
||||
for (ProxyShape* shape = m_proxyCollisionShapes; shape != nullptr; shape = shape->m_next) {
|
||||
for (ProxyShape* shape = m_proxyCollisionShapes; shape != null; shape = shape->m_next) {
|
||||
m_world.m_collisionDetection.removeProxyCollisionShape(shape);
|
||||
}
|
||||
resetContactManifoldsList();
|
||||
@ -161,7 +180,7 @@ void CollisionBody::setIsActive(bool _isActive) {
|
||||
|
||||
|
||||
void CollisionBody::askForBroadPhaseCollisionCheck() const {
|
||||
for (ProxyShape* shape = m_proxyCollisionShapes; shape != nullptr; shape = shape->m_next) {
|
||||
for (ProxyShape* shape = m_proxyCollisionShapes; shape != null; shape = shape->m_next) {
|
||||
m_world.m_collisionDetection.askForBroadPhaseCollisionCheck(shape);
|
||||
}
|
||||
}
|
||||
@ -172,7 +191,7 @@ int32_t CollisionBody::resetIsAlreadyInIslandAndCountManifolds() {
|
||||
int32_t nbManifolds = 0;
|
||||
// Reset the m_isAlreadyInIsland variable of the contact manifolds for this body
|
||||
ContactManifoldListElement* currentElement = m_contactManifoldsList;
|
||||
while (currentElement != nullptr) {
|
||||
while (currentElement != null) {
|
||||
currentElement->contactManifold->m_isAlreadyInIsland = false;
|
||||
currentElement = currentElement->next;
|
||||
nbManifolds++;
|
||||
@ -181,7 +200,7 @@ int32_t CollisionBody::resetIsAlreadyInIslandAndCountManifolds() {
|
||||
}
|
||||
|
||||
bool CollisionBody::testPointInside(const vec3& _worldPoint) const {
|
||||
for (ProxyShape* shape = m_proxyCollisionShapes; shape != nullptr; shape = shape->m_next) {
|
||||
for (ProxyShape* shape = m_proxyCollisionShapes; shape != null; shape = shape->m_next) {
|
||||
if (shape->testPointInside(_worldPoint)) return true;
|
||||
}
|
||||
return false;
|
||||
@ -193,7 +212,7 @@ bool CollisionBody::raycast(const Ray& _ray, RaycastInfo& _raycastInfo) {
|
||||
}
|
||||
bool isHit = false;
|
||||
Ray rayTemp(_ray);
|
||||
for (ProxyShape* shape = m_proxyCollisionShapes; shape != nullptr; shape = shape->m_next) {
|
||||
for (ProxyShape* shape = m_proxyCollisionShapes; shape != null; shape = shape->m_next) {
|
||||
// Test if the ray hits the collision shape
|
||||
if (shape->raycast(rayTemp, _raycastInfo)) {
|
||||
rayTemp.maxFraction = _raycastInfo.hitFraction;
|
||||
@ -205,11 +224,11 @@ bool CollisionBody::raycast(const Ray& _ray, RaycastInfo& _raycastInfo) {
|
||||
|
||||
AABB CollisionBody::getAABB() const {
|
||||
AABB bodyAABB;
|
||||
if (m_proxyCollisionShapes == nullptr) {
|
||||
if (m_proxyCollisionShapes == null) {
|
||||
return bodyAABB;
|
||||
}
|
||||
m_proxyCollisionShapes->getCollisionShape()->computeAABB(bodyAABB, m_transform * m_proxyCollisionShapes->getLocalToBodyTransform());
|
||||
for (ProxyShape* shape = m_proxyCollisionShapes->m_next; shape != nullptr; shape = shape->m_next) {
|
||||
for (ProxyShape* shape = m_proxyCollisionShapes->m_next; shape != null; shape = shape->m_next) {
|
||||
AABB aabb;
|
||||
shape->getCollisionShape()->computeAABB(aabb, m_transform * shape->getLocalToBodyTransform());
|
||||
bodyAABB.mergeWithAABB(aabb);
|
||||
|
@ -1,11 +1,12 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// Libraries
|
||||
#include <ephysics/body/Body.hpp>
|
||||
#include <etk/math/Transform3D.hpp>
|
||||
#include <ephysics/collision/shapes/AABB.hpp>
|
||||
@ -105,10 +106,7 @@ namespace ephysics {
|
||||
* @brief Set the current position and orientation
|
||||
* @param transform The transformation of the body that transforms the local-space of the body int32_to world-space
|
||||
*/
|
||||
void setTransform(const etk::Transform3D& _transform) {
|
||||
m_transform = _transform;
|
||||
updateBroadPhaseState();
|
||||
}
|
||||
virtual void setTransform(const etk::Transform3D& _transform);
|
||||
/**
|
||||
* @brief Add a collision shape to the body. Note that you can share a collision shape between several bodies using the same collision shape instance to
|
||||
* when you add the shape to the different bodies. Do not forget to delete the collision shape you have created at the end of your program.
|
||||
|
@ -1,10 +1,11 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
// Libraries
|
||||
#include <ephysics/body/RigidBody.hpp>
|
||||
#include <ephysics/constraint/Joint.hpp>
|
||||
#include <ephysics/collision/shapes/CollisionShape.hpp>
|
||||
@ -22,13 +23,13 @@ RigidBody::RigidBody(const etk::Transform3D& _transform, CollisionWorld& _world,
|
||||
m_isGravityEnabled(true),
|
||||
m_linearDamping(0.0f),
|
||||
m_angularDamping(float(0.0)),
|
||||
m_jointsList(nullptr) {
|
||||
m_jointsList(null) {
|
||||
// Compute the inverse mass
|
||||
m_massInverse = 1.0f / m_initMass;
|
||||
}
|
||||
|
||||
RigidBody::~RigidBody() {
|
||||
assert(m_jointsList == nullptr);
|
||||
assert(m_jointsList == null);
|
||||
}
|
||||
|
||||
|
||||
@ -96,23 +97,23 @@ void RigidBody::setMass(float _mass) {
|
||||
}
|
||||
|
||||
void RigidBody::removeJointFrom_jointsList(const Joint* _joint) {
|
||||
assert(_joint != nullptr);
|
||||
assert(m_jointsList != nullptr);
|
||||
assert(_joint != null);
|
||||
assert(m_jointsList != null);
|
||||
// Remove the joint from the linked list of the joints of the first body
|
||||
if (m_jointsList->joint == _joint) { // If the first element is the one to remove
|
||||
JointListElement* elementToRemove = m_jointsList;
|
||||
m_jointsList = elementToRemove->next;
|
||||
delete elementToRemove;
|
||||
elementToRemove = nullptr;
|
||||
ETK_DELETE(JointListElement, elementToRemove);
|
||||
elementToRemove = null;
|
||||
}
|
||||
else { // If the element to remove is not the first one in the list
|
||||
JointListElement* currentElement = m_jointsList;
|
||||
while (currentElement->next != nullptr) {
|
||||
while (currentElement->next != null) {
|
||||
if (currentElement->next->joint == _joint) {
|
||||
JointListElement* elementToRemove = currentElement->next;
|
||||
currentElement->next = elementToRemove->next;
|
||||
delete elementToRemove;
|
||||
elementToRemove = nullptr;
|
||||
ETK_DELETE(JointListElement, elementToRemove);
|
||||
elementToRemove = null;
|
||||
break;
|
||||
}
|
||||
currentElement = currentElement->next;
|
||||
@ -126,9 +127,9 @@ ProxyShape* RigidBody::addCollisionShape(CollisionShape* _collisionShape,
|
||||
float _mass) {
|
||||
assert(_mass > 0.0f);
|
||||
// Create a new proxy collision shape to attach the collision shape to the body
|
||||
ProxyShape* proxyShape = new ProxyShape(this, _collisionShape, _transform, _mass);
|
||||
ProxyShape* proxyShape = ETK_NEW(ProxyShape, this, _collisionShape, _transform, _mass);
|
||||
// Add it to the list of proxy collision shapes of the body
|
||||
if (m_proxyCollisionShapes == nullptr) {
|
||||
if (m_proxyCollisionShapes == null) {
|
||||
m_proxyCollisionShapes = proxyShape;
|
||||
} else {
|
||||
proxyShape->m_next = m_proxyCollisionShapes;
|
||||
@ -181,8 +182,25 @@ void RigidBody::setIsSleeping(bool _isSleeping) {
|
||||
Body::setIsSleeping(_isSleeping);
|
||||
}
|
||||
|
||||
void RigidBody::updateTransformWithCenterOfMass() {
|
||||
// Translate the body according to the translation of the center of mass position
|
||||
m_transform.setPosition(m_centerOfMassWorld - m_transform.getOrientation() * m_centerOfMassLocal);
|
||||
if (isnan(m_transform.getPosition().x()) == true) {
|
||||
EPHY_CRITICAL("updateTransformWithCenterOfMass: " << m_transform);
|
||||
}
|
||||
if (isinf(m_transform.getOrientation().z()) == true) {
|
||||
EPHY_CRITICAL(" set transform: " << m_transform);
|
||||
}
|
||||
}
|
||||
|
||||
void RigidBody::setTransform(const etk::Transform3D& _transform) {
|
||||
EPHY_DEBUG(" set transform: " << m_transform << " ==> " << _transform);
|
||||
if (isnan(_transform.getPosition().x()) == true) {
|
||||
EPHY_CRITICAL(" set transform: " << m_transform << " ==> " << _transform);
|
||||
}
|
||||
if (isinf(_transform.getOrientation().z()) == true) {
|
||||
EPHY_CRITICAL(" set transform: " << m_transform << " ==> " << _transform);
|
||||
}
|
||||
m_transform = _transform;
|
||||
const vec3 oldCenterOfMass = m_centerOfMassWorld;
|
||||
// Compute the new center of mass in world-space coordinates
|
||||
@ -220,7 +238,7 @@ void RigidBody::recomputeMassInformation() {
|
||||
m_centerOfMassLocal *= m_massInverse;
|
||||
m_centerOfMassWorld = m_transform * m_centerOfMassLocal;
|
||||
// Compute the total mass and inertia tensor using all the collision shapes
|
||||
for (ProxyShape* shape = m_proxyCollisionShapes; shape != nullptr; shape = shape->m_next) {
|
||||
for (ProxyShape* shape = m_proxyCollisionShapes; shape != null; shape = shape->m_next) {
|
||||
// Get the inertia tensor of the collision shape in its local-space
|
||||
etk::Matrix3x3 inertiaTensor;
|
||||
shape->getCollisionShape()->computeLocalInertiaTensor(inertiaTensor, shape->getMass());
|
||||
@ -253,12 +271,13 @@ void RigidBody::updateBroadPhaseState() const {
|
||||
DynamicsWorld& world = static_cast<DynamicsWorld&>(m_world);
|
||||
const vec3 displacement = world.m_timeStep * m_linearVelocity;
|
||||
// For all the proxy collision shapes of the body
|
||||
for (ProxyShape* shape = m_proxyCollisionShapes; shape != nullptr; shape = shape->m_next) {
|
||||
for (ProxyShape* shape = m_proxyCollisionShapes; shape != null; shape = shape->m_next) {
|
||||
// Recompute the world-space AABB of the collision shape
|
||||
AABB aabb;
|
||||
EPHY_ERROR(" : " << aabb.getMin() << " " << aabb.getMax());
|
||||
EPHY_VERBOSE(" : " << aabb.getMin() << " " << aabb.getMax());
|
||||
EPHY_VERBOSE(" m_transform: " << m_transform);
|
||||
shape->getCollisionShape()->computeAABB(aabb, m_transform *shape->getLocalToBodyTransform());
|
||||
EPHY_ERROR(" : " << aabb.getMin() << " " << aabb.getMax());
|
||||
EPHY_VERBOSE(" : " << aabb.getMin() << " " << aabb.getMax());
|
||||
// Update the broad-phase state for the proxy collision shape
|
||||
m_world.m_collisionDetection.updateProxyCollisionShape(shape, aabb, displacement);
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -50,10 +53,7 @@ namespace ephysics {
|
||||
/**
|
||||
* @brief Update the transform of the body after a change of the center of mass
|
||||
*/
|
||||
void updateTransformWithCenterOfMass() {
|
||||
// Translate the body according to the translation of the center of mass position
|
||||
m_transform.setPosition(m_centerOfMassWorld - m_transform.getOrientation() * m_centerOfMassLocal);
|
||||
}
|
||||
void updateTransformWithCenterOfMass();
|
||||
void updateBroadPhaseState() const override;
|
||||
public :
|
||||
/**
|
||||
@ -72,7 +72,7 @@ namespace ephysics {
|
||||
* @brief Set the current position and orientation
|
||||
* @param[in] _transform The transformation of the body that transforms the local-space of the body int32_to world-space
|
||||
*/
|
||||
virtual void setTransform(const etk::Transform3D& _transform);
|
||||
void setTransform(const etk::Transform3D& _transform) override;
|
||||
/**
|
||||
* @brief Get the mass of the body
|
||||
* @return The mass (in kilograms) of the body
|
||||
|
@ -1,10 +1,11 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
// Libraries
|
||||
#include <ephysics/collision/CollisionDetection.hpp>
|
||||
#include <ephysics/engine/CollisionWorld.hpp>
|
||||
#include <ephysics/body/Body.hpp>
|
||||
@ -39,20 +40,16 @@ void CollisionDetection::computeCollisionDetection() {
|
||||
computeNarrowPhase();
|
||||
}
|
||||
|
||||
void CollisionDetection::testCollisionBetweenShapes(CollisionCallback* callback,
|
||||
const etk::Set<uint32_t>& shapes1,
|
||||
const etk::Set<uint32_t>& shapes2) {
|
||||
void CollisionDetection::testCollisionBetweenShapes(CollisionCallback* _callback, const etk::Set<uint32_t>& _shapes1, const etk::Set<uint32_t>& _shapes2) {
|
||||
// Compute the broad-phase collision detection
|
||||
computeBroadPhase();
|
||||
// Delete all the contact points in the currently overlapping pairs
|
||||
clearContactPoints();
|
||||
// Compute the narrow-phase collision detection among given sets of shapes
|
||||
computeNarrowPhaseBetweenShapes(callback, shapes1, shapes2);
|
||||
computeNarrowPhaseBetweenShapes(_callback, _shapes1, _shapes2);
|
||||
}
|
||||
|
||||
void CollisionDetection::reportCollisionBetweenShapes(CollisionCallback* callback,
|
||||
const etk::Set<uint32_t>& shapes1,
|
||||
const etk::Set<uint32_t>& shapes2) {
|
||||
void CollisionDetection::reportCollisionBetweenShapes(CollisionCallback* _callback, const etk::Set<uint32_t>& _shapes1, const etk::Set<uint32_t>& _shapes2) {
|
||||
// For each possible collision pair of bodies
|
||||
etk::Map<overlappingpairid, OverlappingPair*>::Iterator it;
|
||||
for (it = m_overlappingPairs.begin(); it != m_overlappingPairs.end(); ++it) {
|
||||
@ -62,24 +59,24 @@ void CollisionDetection::reportCollisionBetweenShapes(CollisionCallback* callbac
|
||||
assert(shape1->m_broadPhaseID != shape2->m_broadPhaseID);
|
||||
// If both shapes1 and shapes2 sets are non-empty, we check that
|
||||
// shape1 is among on set and shape2 is among the other one
|
||||
if ( !shapes1.empty()
|
||||
&& !shapes2.empty()
|
||||
&& ( shapes1.count(shape1->m_broadPhaseID) == 0
|
||||
|| shapes2.count(shape2->m_broadPhaseID) == 0 )
|
||||
&& ( shapes1.count(shape2->m_broadPhaseID) == 0
|
||||
|| shapes2.count(shape1->m_broadPhaseID) == 0 ) ) {
|
||||
if ( !_shapes1.empty()
|
||||
&& !_shapes2.empty()
|
||||
&& ( _shapes1.count(shape1->m_broadPhaseID) == 0
|
||||
|| _shapes2.count(shape2->m_broadPhaseID) == 0 )
|
||||
&& ( _shapes1.count(shape2->m_broadPhaseID) == 0
|
||||
|| _shapes2.count(shape1->m_broadPhaseID) == 0 ) ) {
|
||||
continue;
|
||||
}
|
||||
if ( !shapes1.empty()
|
||||
&& shapes2.empty()
|
||||
&& shapes1.count(shape1->m_broadPhaseID) == 0
|
||||
&& shapes1.count(shape2->m_broadPhaseID) == 0) {
|
||||
if ( !_shapes1.empty()
|
||||
&& _shapes2.empty()
|
||||
&& _shapes1.count(shape1->m_broadPhaseID) == 0
|
||||
&& _shapes1.count(shape2->m_broadPhaseID) == 0) {
|
||||
continue;
|
||||
}
|
||||
if ( !shapes2.empty()
|
||||
&& shapes1.empty()
|
||||
&& shapes2.count(shape1->m_broadPhaseID) == 0
|
||||
&& shapes2.count(shape2->m_broadPhaseID) == 0) {
|
||||
if ( !_shapes2.empty()
|
||||
&& _shapes1.empty()
|
||||
&& _shapes2.count(shape1->m_broadPhaseID) == 0
|
||||
&& _shapes2.count(shape2->m_broadPhaseID) == 0) {
|
||||
continue;
|
||||
}
|
||||
// For each contact manifold set of the overlapping pair
|
||||
@ -91,15 +88,15 @@ void CollisionDetection::reportCollisionBetweenShapes(CollisionCallback* callbac
|
||||
ContactPoint* contactPoint = manifold->getContactPoint(i);
|
||||
// Create the contact info object for the contact
|
||||
ContactPointInfo contactInfo(manifold->getShape1(), manifold->getShape2(),
|
||||
manifold->getShape1()->getCollisionShape(),
|
||||
manifold->getShape2()->getCollisionShape(),
|
||||
contactPoint->getNormal(),
|
||||
contactPoint->getPenetrationDepth(),
|
||||
contactPoint->getLocalPointOnBody1(),
|
||||
contactPoint->getLocalPointOnBody2());
|
||||
manifold->getShape1()->getCollisionShape(),
|
||||
manifold->getShape2()->getCollisionShape(),
|
||||
contactPoint->getNormal(),
|
||||
contactPoint->getPenetrationDepth(),
|
||||
contactPoint->getLocalPointOnBody1(),
|
||||
contactPoint->getLocalPointOnBody2());
|
||||
// Notify the collision callback about this new contact
|
||||
if (callback != nullptr) {
|
||||
callback->notifyContact(contactInfo);
|
||||
if (_callback != null) {
|
||||
_callback->notifyContact(contactInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -136,8 +133,8 @@ void CollisionDetection::computeNarrowPhase() {
|
||||
!m_broadPhaseAlgorithm.testOverlappingShapes(shape1, shape2)) {
|
||||
// TODO : Remove all the contact manifold of the overlapping pair from the contact manifolds list of the two bodies involved
|
||||
// Destroy the overlapping pair
|
||||
delete it->second;
|
||||
it->second = nullptr;
|
||||
ETK_DELETE(OverlappingPair, it->second);
|
||||
it->second = null;
|
||||
it = m_overlappingPairs.erase(it);
|
||||
continue;
|
||||
} else {
|
||||
@ -163,7 +160,7 @@ void CollisionDetection::computeNarrowPhase() {
|
||||
const CollisionShapeType shape2Type = shape2->getCollisionShape()->getType();
|
||||
NarrowPhaseAlgorithm* narrowPhaseAlgorithm = m_collisionMatrix[shape1Type][shape2Type];
|
||||
// If there is no collision algorithm between those two kinds of shapes
|
||||
if (narrowPhaseAlgorithm == nullptr) {
|
||||
if (narrowPhaseAlgorithm == null) {
|
||||
continue;
|
||||
}
|
||||
// Notify the narrow-phase algorithm about the overlapping pair we are going to test
|
||||
@ -183,9 +180,7 @@ void CollisionDetection::computeNarrowPhase() {
|
||||
addAllContactManifoldsToBodies();
|
||||
}
|
||||
|
||||
void CollisionDetection::computeNarrowPhaseBetweenShapes(CollisionCallback* callback,
|
||||
const etk::Set<uint32_t>& shapes1,
|
||||
const etk::Set<uint32_t>& shapes2) {
|
||||
void CollisionDetection::computeNarrowPhaseBetweenShapes(CollisionCallback* _callback, const etk::Set<uint32_t>& _shapes1, const etk::Set<uint32_t>& _shapes2) {
|
||||
m_contactOverlappingPairs.clear();
|
||||
// For each possible collision pair of bodies
|
||||
etk::Map<overlappingpairid, OverlappingPair*>::Iterator it;
|
||||
@ -196,39 +191,39 @@ void CollisionDetection::computeNarrowPhaseBetweenShapes(CollisionCallback* call
|
||||
assert(shape1->m_broadPhaseID != shape2->m_broadPhaseID);
|
||||
// If both shapes1 and shapes2 sets are non-empty, we check that
|
||||
// shape1 is among on set and shape2 is among the other one
|
||||
if ( !shapes1.empty()
|
||||
&& !shapes2.empty()
|
||||
&& ( shapes1.count(shape1->m_broadPhaseID) == 0
|
||||
|| shapes2.count(shape2->m_broadPhaseID) == 0 )
|
||||
&& ( shapes1.count(shape2->m_broadPhaseID) == 0
|
||||
|| shapes2.count(shape1->m_broadPhaseID) == 0 ) ) {
|
||||
if ( !_shapes1.empty()
|
||||
&& !_shapes2.empty()
|
||||
&& ( _shapes1.count(shape1->m_broadPhaseID) == 0
|
||||
|| _shapes2.count(shape2->m_broadPhaseID) == 0 )
|
||||
&& ( _shapes1.count(shape2->m_broadPhaseID) == 0
|
||||
|| _shapes2.count(shape1->m_broadPhaseID) == 0 ) ) {
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
if ( !shapes1.empty()
|
||||
&& shapes2.empty()
|
||||
&& shapes1.count(shape1->m_broadPhaseID) == 0
|
||||
&& shapes1.count(shape2->m_broadPhaseID) == 0) {
|
||||
if ( !_shapes1.empty()
|
||||
&& _shapes2.empty()
|
||||
&& _shapes1.count(shape1->m_broadPhaseID) == 0
|
||||
&& _shapes1.count(shape2->m_broadPhaseID) == 0) {
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
if ( !shapes2.empty()
|
||||
&& shapes1.empty()
|
||||
&& shapes2.count(shape1->m_broadPhaseID) == 0
|
||||
&& shapes2.count(shape2->m_broadPhaseID) == 0) {
|
||||
if ( !_shapes2.empty()
|
||||
&& _shapes1.empty()
|
||||
&& _shapes2.count(shape1->m_broadPhaseID) == 0
|
||||
&& _shapes2.count(shape2->m_broadPhaseID) == 0) {
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
// Check if the collision filtering allows collision between the two shapes and
|
||||
// that the two shapes are still overlapping. Otherwise, we destroy the
|
||||
// overlapping pair
|
||||
if (((shape1->getCollideWithMaskBits() & shape2->getCollisionCategoryBits()) == 0 ||
|
||||
(shape1->getCollisionCategoryBits() & shape2->getCollideWithMaskBits()) == 0) ||
|
||||
!m_broadPhaseAlgorithm.testOverlappingShapes(shape1, shape2)) {
|
||||
if ( ( (shape1->getCollideWithMaskBits() & shape2->getCollisionCategoryBits()) == 0
|
||||
|| (shape1->getCollisionCategoryBits() & shape2->getCollideWithMaskBits()) == 0 )
|
||||
|| !m_broadPhaseAlgorithm.testOverlappingShapes(shape1, shape2) ) {
|
||||
// TODO : Remove all the contact manifold of the overlapping pair from the contact manifolds list of the two bodies involved
|
||||
// Destroy the overlapping pair
|
||||
delete it->second;
|
||||
it->second = nullptr;
|
||||
ETK_DELETE(OverlappingPair, it->second);
|
||||
it->second = null;
|
||||
it = m_overlappingPairs.erase(it);
|
||||
continue;
|
||||
} else {
|
||||
@ -255,17 +250,23 @@ void CollisionDetection::computeNarrowPhaseBetweenShapes(CollisionCallback* call
|
||||
const CollisionShapeType shape2Type = shape2->getCollisionShape()->getType();
|
||||
NarrowPhaseAlgorithm* narrowPhaseAlgorithm = m_collisionMatrix[shape1Type][shape2Type];
|
||||
// If there is no collision algorithm between those two kinds of shapes
|
||||
if (narrowPhaseAlgorithm == nullptr) {
|
||||
if (narrowPhaseAlgorithm == null) {
|
||||
continue;
|
||||
}
|
||||
// Notify the narrow-phase algorithm about the overlapping pair we are going to test
|
||||
narrowPhaseAlgorithm->setCurrentOverlappingPair(pair);
|
||||
// Create the CollisionShapeInfo objects
|
||||
CollisionShapeInfo shape1Info(shape1, shape1->getCollisionShape(), shape1->getLocalToWorldTransform(),
|
||||
pair, shape1->getCachedCollisionData());
|
||||
CollisionShapeInfo shape2Info(shape2, shape2->getCollisionShape(), shape2->getLocalToWorldTransform(),
|
||||
pair, shape2->getCachedCollisionData());
|
||||
TestCollisionBetweenShapesCallback narrowPhaseCallback(callback);
|
||||
CollisionShapeInfo shape1Info(shape1,
|
||||
shape1->getCollisionShape(),
|
||||
shape1->getLocalToWorldTransform(),
|
||||
pair,
|
||||
shape1->getCachedCollisionData());
|
||||
CollisionShapeInfo shape2Info(shape2,
|
||||
shape2->getCollisionShape(),
|
||||
shape2->getLocalToWorldTransform(),
|
||||
pair,
|
||||
shape2->getCachedCollisionData());
|
||||
TestCollisionBetweenShapesCallback narrowPhaseCallback(_callback);
|
||||
// Use the narrow-phase collision detection algorithm to check
|
||||
// if there really is a collision
|
||||
narrowPhaseAlgorithm->testCollision(shape1Info, shape2Info, &narrowPhaseCallback);
|
||||
@ -274,73 +275,77 @@ void CollisionDetection::computeNarrowPhaseBetweenShapes(CollisionCallback* call
|
||||
addAllContactManifoldsToBodies();
|
||||
}
|
||||
|
||||
void CollisionDetection::broadPhaseNotifyOverlappingPair(ProxyShape* shape1, ProxyShape* shape2) {
|
||||
assert(shape1->m_broadPhaseID != shape2->m_broadPhaseID);
|
||||
void CollisionDetection::broadPhaseNotifyOverlappingPair(ProxyShape* _shape1, ProxyShape* _shape2) {
|
||||
assert(_shape1->m_broadPhaseID != _shape2->m_broadPhaseID);
|
||||
// If the two proxy collision shapes are from the same body, skip it
|
||||
if (shape1->getBody()->getID() == shape2->getBody()->getID()) {
|
||||
if (_shape1->getBody()->getID() == _shape2->getBody()->getID()) {
|
||||
return;
|
||||
}
|
||||
// Check if the collision filtering allows collision between the two shapes
|
||||
if ( (shape1->getCollideWithMaskBits() & shape2->getCollisionCategoryBits()) == 0
|
||||
|| (shape1->getCollisionCategoryBits() & shape2->getCollideWithMaskBits()) == 0) {
|
||||
if ( (_shape1->getCollideWithMaskBits() & _shape2->getCollisionCategoryBits()) == 0
|
||||
|| (_shape1->getCollisionCategoryBits() & _shape2->getCollideWithMaskBits()) == 0) {
|
||||
return;
|
||||
}
|
||||
// Compute the overlapping pair ID
|
||||
overlappingpairid pairID = OverlappingPair::computeID(shape1, shape2);
|
||||
overlappingpairid pairID = OverlappingPair::computeID(_shape1, _shape2);
|
||||
// Check if the overlapping pair already exists
|
||||
if (m_overlappingPairs.find(pairID) != m_overlappingPairs.end()) return;
|
||||
// Compute the maximum number of contact manifolds for this pair
|
||||
int32_t nbMaxManifolds = CollisionShape::computeNbMaxContactManifolds(shape1->getCollisionShape()->getType(),
|
||||
shape2->getCollisionShape()->getType());
|
||||
int32_t nbMaxManifolds = CollisionShape::computeNbMaxContactManifolds(_shape1->getCollisionShape()->getType(),
|
||||
_shape2->getCollisionShape()->getType());
|
||||
// Create the overlapping pair and add it int32_to the set of overlapping pairs
|
||||
OverlappingPair* newPair = new OverlappingPair(shape1, shape2, nbMaxManifolds);
|
||||
assert(newPair != nullptr);
|
||||
OverlappingPair* newPair = ETK_NEW(OverlappingPair, _shape1, _shape2, nbMaxManifolds);
|
||||
assert(newPair != null);
|
||||
m_overlappingPairs.set(pairID, newPair);
|
||||
// Wake up the two bodies
|
||||
shape1->getBody()->setIsSleeping(false);
|
||||
shape2->getBody()->setIsSleeping(false);
|
||||
_shape1->getBody()->setIsSleeping(false);
|
||||
_shape2->getBody()->setIsSleeping(false);
|
||||
}
|
||||
|
||||
void CollisionDetection::removeProxyCollisionShape(ProxyShape* proxyShape) {
|
||||
void CollisionDetection::removeProxyCollisionShape(ProxyShape* _proxyShape) {
|
||||
// Remove all the overlapping pairs involving this proxy shape
|
||||
etk::Map<overlappingpairid, OverlappingPair*>::Iterator it;
|
||||
for (it = m_overlappingPairs.begin(); it != m_overlappingPairs.end(); ) {
|
||||
if (it->second->getShape1()->m_broadPhaseID == proxyShape->m_broadPhaseID||
|
||||
it->second->getShape2()->m_broadPhaseID == proxyShape->m_broadPhaseID) {
|
||||
if (it->second->getShape1()->m_broadPhaseID == _proxyShape->m_broadPhaseID||
|
||||
it->second->getShape2()->m_broadPhaseID == _proxyShape->m_broadPhaseID) {
|
||||
// TODO : Remove all the contact manifold of the overlapping pair from the contact manifolds list of the two bodies involved
|
||||
// Destroy the overlapping pair
|
||||
delete it->second;
|
||||
it->second = nullptr;
|
||||
ETK_DELETE(OverlappingPair, it->second);
|
||||
it->second = null;
|
||||
it = m_overlappingPairs.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
// Remove the body from the broad-phase
|
||||
m_broadPhaseAlgorithm.removeProxyCollisionShape(proxyShape);
|
||||
m_broadPhaseAlgorithm.removeProxyCollisionShape(_proxyShape);
|
||||
}
|
||||
|
||||
void CollisionDetection::notifyContact(OverlappingPair* overlappingPair, const ContactPointInfo& contactInfo) {
|
||||
void CollisionDetection::notifyContact(OverlappingPair* _overlappingPair, const ContactPointInfo& _contactInfo) {
|
||||
// If it is the first contact since the pairs are overlapping
|
||||
if (overlappingPair->getNbContactPoints() == 0) {
|
||||
if (_overlappingPair->getNbContactPoints() == 0) {
|
||||
// Trigger a callback event
|
||||
if (m_world->m_eventListener != NULL) m_world->m_eventListener->beginContact(contactInfo);
|
||||
if (m_world->m_eventListener != NULL) {
|
||||
m_world->m_eventListener->beginContact(_contactInfo);
|
||||
}
|
||||
}
|
||||
// Create a new contact
|
||||
createContact(overlappingPair, contactInfo);
|
||||
createContact(_overlappingPair, _contactInfo);
|
||||
// Trigger a callback event for the new contact
|
||||
if (m_world->m_eventListener != NULL) m_world->m_eventListener->newContact(contactInfo);
|
||||
if (m_world->m_eventListener != NULL) {
|
||||
m_world->m_eventListener->newContact(_contactInfo);
|
||||
}
|
||||
}
|
||||
|
||||
void CollisionDetection::createContact(OverlappingPair* overlappingPair, const ContactPointInfo& contactInfo) {
|
||||
void CollisionDetection::createContact(OverlappingPair* _overlappingPair, const ContactPointInfo& _contactInfo) {
|
||||
// Create a new contact
|
||||
ContactPoint* contact = new ContactPoint(contactInfo);
|
||||
ContactPoint* contact = ETK_NEW(ContactPoint, _contactInfo);
|
||||
// Add the contact to the contact manifold set of the corresponding overlapping pair
|
||||
overlappingPair->addContact(contact);
|
||||
_overlappingPair->addContact(contact);
|
||||
// Add the overlapping pair int32_to the set of pairs in contact during narrow-phase
|
||||
overlappingpairid pairId = OverlappingPair::computeID(overlappingPair->getShape1(),
|
||||
overlappingPair->getShape2());
|
||||
m_contactOverlappingPairs[pairId] = overlappingPair;
|
||||
overlappingpairid pairId = OverlappingPair::computeID(_overlappingPair->getShape1(),
|
||||
_overlappingPair->getShape2());
|
||||
m_contactOverlappingPairs.set(pairId, _overlappingPair);
|
||||
}
|
||||
|
||||
void CollisionDetection::addAllContactManifoldsToBodies() {
|
||||
@ -353,26 +358,25 @@ void CollisionDetection::addAllContactManifoldsToBodies() {
|
||||
}
|
||||
}
|
||||
|
||||
void CollisionDetection::addContactManifoldToBody(OverlappingPair* pair) {
|
||||
assert(pair != nullptr);
|
||||
CollisionBody* body1 = pair->getShape1()->getBody();
|
||||
CollisionBody* body2 = pair->getShape2()->getBody();
|
||||
const ContactManifoldSet& manifoldSet = pair->getContactManifoldSet();
|
||||
void CollisionDetection::addContactManifoldToBody(OverlappingPair* _pair) {
|
||||
assert(_pair != null);
|
||||
CollisionBody* body1 = _pair->getShape1()->getBody();
|
||||
CollisionBody* body2 = _pair->getShape2()->getBody();
|
||||
const ContactManifoldSet& manifoldSet = _pair->getContactManifoldSet();
|
||||
// For each contact manifold in the set of manifolds in the pair
|
||||
for (int32_t i=0; i<manifoldSet.getNbContactManifolds(); i++) {
|
||||
ContactManifold* contactManifold = manifoldSet.getContactManifold(i);
|
||||
assert(contactManifold->getNbContactPoints() > 0);
|
||||
// Add the contact manifold at the beginning of the linked
|
||||
// list of contact manifolds of the first body
|
||||
body1->m_contactManifoldsList = new ContactManifoldListElement(contactManifold, body1->m_contactManifoldsList);;
|
||||
body1->m_contactManifoldsList = ETK_NEW(ContactManifoldListElement, contactManifold, body1->m_contactManifoldsList);;
|
||||
// Add the contact manifold at the beginning of the linked
|
||||
// list of the contact manifolds of the second body
|
||||
body2->m_contactManifoldsList = new ContactManifoldListElement(contactManifold, body2->m_contactManifoldsList);;
|
||||
body2->m_contactManifoldsList = ETK_NEW(ContactManifoldListElement, contactManifold, body2->m_contactManifoldsList);;
|
||||
}
|
||||
}
|
||||
|
||||
void CollisionDetection::clearContactPoints() {
|
||||
|
||||
// For each overlapping pair
|
||||
etk::Map<overlappingpairid, OverlappingPair*>::Iterator it;
|
||||
for (it = m_overlappingPairs.begin(); it != m_overlappingPairs.end(); ++it) {
|
||||
@ -393,8 +397,7 @@ EventListener* CollisionDetection::getWorldEventListener() {
|
||||
return m_world->m_eventListener;
|
||||
}
|
||||
|
||||
void TestCollisionBetweenShapesCallback::notifyContact(OverlappingPair* _overlappingPair,
|
||||
const ContactPointInfo& _contactInfo) {
|
||||
void TestCollisionBetweenShapesCallback::notifyContact(OverlappingPair* _overlappingPair, const ContactPointInfo& _contactInfo) {
|
||||
m_collisionCallback->notifyContact(_contactInfo);
|
||||
}
|
||||
|
||||
@ -415,41 +418,37 @@ void CollisionDetection::addProxyCollisionShape(ProxyShape* _proxyShape, const A
|
||||
m_isCollisionShapesAdded = true;
|
||||
}
|
||||
|
||||
void CollisionDetection::addNoCollisionPair(CollisionBody* body1, CollisionBody* body2) {
|
||||
m_noCollisionPairs.set(OverlappingPair::computeBodiesIndexPair(body1, body2));
|
||||
void CollisionDetection::addNoCollisionPair(CollisionBody* _body1, CollisionBody* _body2) {
|
||||
m_noCollisionPairs.set(OverlappingPair::computeBodiesIndexPair(_body1, _body2));
|
||||
}
|
||||
|
||||
void CollisionDetection::removeNoCollisionPair(CollisionBody* body1,
|
||||
CollisionBody* body2) {
|
||||
m_noCollisionPairs.erase(m_noCollisionPairs.find(OverlappingPair::computeBodiesIndexPair(body1, body2)));
|
||||
void CollisionDetection::removeNoCollisionPair(CollisionBody* _body1, CollisionBody* _body2) {
|
||||
m_noCollisionPairs.erase(m_noCollisionPairs.find(OverlappingPair::computeBodiesIndexPair(_body1, _body2)));
|
||||
}
|
||||
|
||||
void CollisionDetection::askForBroadPhaseCollisionCheck(ProxyShape* shape) {
|
||||
m_broadPhaseAlgorithm.addMovedCollisionShape(shape->m_broadPhaseID);
|
||||
void CollisionDetection::askForBroadPhaseCollisionCheck(ProxyShape* _shape) {
|
||||
m_broadPhaseAlgorithm.addMovedCollisionShape(_shape->m_broadPhaseID);
|
||||
}
|
||||
|
||||
void CollisionDetection::updateProxyCollisionShape(ProxyShape* shape, const AABB& aabb,
|
||||
const vec3& displacement, bool forceReinsert) {
|
||||
m_broadPhaseAlgorithm.updateProxyCollisionShape(shape, aabb, displacement);
|
||||
void CollisionDetection::updateProxyCollisionShape(ProxyShape* _shape, const AABB& _aabb, const vec3& _displacement, bool _forceReinsert) {
|
||||
m_broadPhaseAlgorithm.updateProxyCollisionShape(_shape, _aabb, _displacement);
|
||||
}
|
||||
|
||||
void CollisionDetection::raycast(RaycastCallback* raycastCallback,
|
||||
const Ray& ray,
|
||||
unsigned short raycastWithCategoryMaskBits) const {
|
||||
void CollisionDetection::raycast(RaycastCallback* _raycastCallback, const Ray& _ray, unsigned short _raycastWithCategoryMaskBits) const {
|
||||
PROFILE("CollisionDetection::raycast()");
|
||||
RaycastTest rayCastTest(raycastCallback);
|
||||
RaycastTest rayCastTest(_raycastCallback);
|
||||
// Ask the broad-phase algorithm to call the testRaycastAgainstShape()
|
||||
// callback method for each proxy shape hit by the ray in the broad-phase
|
||||
m_broadPhaseAlgorithm.raycast(ray, rayCastTest, raycastWithCategoryMaskBits);
|
||||
m_broadPhaseAlgorithm.raycast(_ray, rayCastTest, _raycastWithCategoryMaskBits);
|
||||
}
|
||||
|
||||
bool CollisionDetection::testAABBOverlap(const ProxyShape* shape1,
|
||||
const ProxyShape* shape2) const {
|
||||
bool CollisionDetection::testAABBOverlap(const ProxyShape* _shape1, const ProxyShape* _shape2) const {
|
||||
// If one of the shape's body is not active, we return no overlap
|
||||
if (!shape1->getBody()->isActive() || !shape2->getBody()->isActive()) {
|
||||
if ( !_shape1->getBody()->isActive()
|
||||
|| !_shape2->getBody()->isActive()) {
|
||||
return false;
|
||||
}
|
||||
return m_broadPhaseAlgorithm.testOverlappingShapes(shape1, shape2);
|
||||
return m_broadPhaseAlgorithm.testOverlappingShapes(_shape1, _shape2);
|
||||
}
|
||||
|
||||
CollisionWorld* CollisionDetection::getWorld() {
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
@ -1,16 +1,15 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
|
||||
// Libraries
|
||||
#include <ephysics/collision/ContactManifold.hpp>
|
||||
|
||||
using namespace ephysics;
|
||||
|
||||
// Constructor
|
||||
ContactManifold::ContactManifold(ProxyShape* _shape1,
|
||||
ProxyShape* _shape2,
|
||||
short _normalDirectionId):
|
||||
@ -25,206 +24,156 @@ ContactManifold::ContactManifold(ProxyShape* _shape1,
|
||||
|
||||
}
|
||||
|
||||
// Destructor
|
||||
ContactManifold::~ContactManifold() {
|
||||
clear();
|
||||
}
|
||||
|
||||
// Add a contact point in the manifold
|
||||
void ContactManifold::addContactPoint(ContactPoint* contact) {
|
||||
|
||||
// For contact already in the manifold
|
||||
for (uint32_t i=0; i<m_nbContactPoints; i++) {
|
||||
|
||||
// Check if the new point point does not correspond to a same contact point
|
||||
// already in the manifold.
|
||||
float distance = (m_contactPoints[i]->getWorldPointOnBody1() -
|
||||
contact->getWorldPointOnBody1()).length2();
|
||||
float distance = (m_contactPoints[i]->getWorldPointOnBody1() - contact->getWorldPointOnBody1()).length2();
|
||||
if (distance <= PERSISTENT_CONTACT_DIST_THRESHOLD*PERSISTENT_CONTACT_DIST_THRESHOLD) {
|
||||
// Delete the new contact
|
||||
delete contact;
|
||||
ETK_DELETE(ContactPoint, contact);
|
||||
assert(m_nbContactPoints > 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If the contact manifold is full
|
||||
if (m_nbContactPoints == MAX_CONTACT_POINTS_IN_MANIFOLD) {
|
||||
int32_t indexMaxPenetration = getIndexOfDeepestPenetration(contact);
|
||||
int32_t indexToRemove = getIndexToRemove(indexMaxPenetration, contact->getLocalPointOnBody1());
|
||||
removeContactPoint(indexToRemove);
|
||||
}
|
||||
|
||||
// Add the new contact point in the manifold
|
||||
m_contactPoints[m_nbContactPoints] = contact;
|
||||
m_nbContactPoints++;
|
||||
|
||||
assert(m_nbContactPoints > 0);
|
||||
}
|
||||
|
||||
// Remove a contact point from the manifold
|
||||
void ContactManifold::removeContactPoint(uint32_t index) {
|
||||
assert(index < m_nbContactPoints);
|
||||
assert(m_nbContactPoints > 0);
|
||||
|
||||
// Call the destructor explicitly and tell the memory allocator that
|
||||
// the corresponding memory block is now free
|
||||
delete m_contactPoints[index];
|
||||
m_contactPoints[index] = nullptr;
|
||||
ETK_DELETE(ContactPoint, m_contactPoints[index]);
|
||||
m_contactPoints[index] = null;
|
||||
// If we don't remove the last index
|
||||
if (index < m_nbContactPoints - 1) {
|
||||
m_contactPoints[index] = m_contactPoints[m_nbContactPoints - 1];
|
||||
}
|
||||
|
||||
m_nbContactPoints--;
|
||||
}
|
||||
|
||||
// Update the contact manifold
|
||||
/// First the world space coordinates of the current contacts in the manifold are recomputed from
|
||||
/// the corresponding transforms of the bodies because they have moved. Then we remove the contacts
|
||||
/// with a negative penetration depth (meaning that the bodies are not penetrating anymore) and also
|
||||
/// the contacts with a too large distance between the contact points in the plane orthogonal to the
|
||||
/// contact normal.
|
||||
void ContactManifold::update(const etk::Transform3D& transform1, const etk::Transform3D& transform2) {
|
||||
|
||||
if (m_nbContactPoints == 0) return;
|
||||
|
||||
if (m_nbContactPoints == 0) {
|
||||
return;
|
||||
}
|
||||
// Update the world coordinates and penetration depth of the contact points in the manifold
|
||||
for (uint32_t i=0; i<m_nbContactPoints; i++) {
|
||||
m_contactPoints[i]->setWorldPointOnBody1(transform1 *
|
||||
m_contactPoints[i]->getLocalPointOnBody1());
|
||||
m_contactPoints[i]->setWorldPointOnBody2(transform2 *
|
||||
m_contactPoints[i]->getLocalPointOnBody2());
|
||||
m_contactPoints[i]->setPenetrationDepth((m_contactPoints[i]->getWorldPointOnBody1() -
|
||||
m_contactPoints[i]->getWorldPointOnBody2()).dot(m_contactPoints[i]->getNormal()));
|
||||
m_contactPoints[i]->setWorldPointOnBody1(transform1 * m_contactPoints[i]->getLocalPointOnBody1());
|
||||
m_contactPoints[i]->setWorldPointOnBody2(transform2 * m_contactPoints[i]->getLocalPointOnBody2());
|
||||
m_contactPoints[i]->setPenetrationDepth((m_contactPoints[i]->getWorldPointOnBody1() - m_contactPoints[i]->getWorldPointOnBody2()).dot(m_contactPoints[i]->getNormal()));
|
||||
}
|
||||
|
||||
const float squarePersistentContactThreshold = PERSISTENT_CONTACT_DIST_THRESHOLD *
|
||||
PERSISTENT_CONTACT_DIST_THRESHOLD;
|
||||
|
||||
const float squarePersistentContactThreshold = PERSISTENT_CONTACT_DIST_THRESHOLD * PERSISTENT_CONTACT_DIST_THRESHOLD;
|
||||
// Remove the contact points that don't represent very well the contact manifold
|
||||
for (int32_t i=static_cast<int32_t>(m_nbContactPoints)-1; i>=0; i--) {
|
||||
assert(i < static_cast<int32_t>(m_nbContactPoints));
|
||||
|
||||
// Compute the distance between contact points in the normal direction
|
||||
float distanceNormal = -m_contactPoints[i]->getPenetrationDepth();
|
||||
|
||||
// If the contacts points are too far from each other in the normal direction
|
||||
if (distanceNormal > squarePersistentContactThreshold) {
|
||||
removeContactPoint(i);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Compute the distance of the two contact points in the plane
|
||||
// orthogonal to the contact normal
|
||||
vec3 projOfPoint1 = m_contactPoints[i]->getWorldPointOnBody1() +
|
||||
m_contactPoints[i]->getNormal() * distanceNormal;
|
||||
vec3 projOfPoint1 = m_contactPoints[i]->getWorldPointOnBody1() + m_contactPoints[i]->getNormal() * distanceNormal;
|
||||
vec3 projDifference = m_contactPoints[i]->getWorldPointOnBody2() - projOfPoint1;
|
||||
|
||||
// If the orthogonal distance is larger than the valid distance
|
||||
// threshold, we remove the contact
|
||||
if (projDifference.length2() > squarePersistentContactThreshold) {
|
||||
removeContactPoint(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return the index of the contact point with the larger penetration depth.
|
||||
/// This corresponding contact will be kept in the cache. The method returns -1 is
|
||||
/// the new contact is the deepest.
|
||||
int32_t ContactManifold::getIndexOfDeepestPenetration(ContactPoint* newContact) const {
|
||||
assert(m_nbContactPoints == MAX_CONTACT_POINTS_IN_MANIFOLD);
|
||||
int32_t indexMaxPenetrationDepth = -1;
|
||||
float maxPenetrationDepth = newContact->getPenetrationDepth();
|
||||
|
||||
// For each contact in the cache
|
||||
for (uint32_t i=0; i<m_nbContactPoints; i++) {
|
||||
|
||||
// If the current contact has a larger penetration depth
|
||||
if (m_contactPoints[i]->getPenetrationDepth() > maxPenetrationDepth) {
|
||||
maxPenetrationDepth = m_contactPoints[i]->getPenetrationDepth();
|
||||
indexMaxPenetrationDepth = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the index of largest penetration depth
|
||||
return indexMaxPenetrationDepth;
|
||||
}
|
||||
|
||||
// Return the index that will be removed.
|
||||
/// The index of the contact point with the larger penetration
|
||||
/// depth is given as a parameter. This contact won't be removed. Given this contact, we compute
|
||||
/// the different area and we want to keep the contacts with the largest area. The new point is also
|
||||
/// kept. In order to compute the area of a quadrilateral, we use the formula :
|
||||
/// Area = 0.5 * | AC x BD | where AC and BD form the diagonals of the quadrilateral. Note that
|
||||
/// when we compute this area, we do not calculate it exactly but we
|
||||
/// only estimate it because we do not compute the actual diagonals of the quadrialteral. Therefore,
|
||||
/// this is only a guess that is faster to compute. This idea comes from the Bullet Physics library
|
||||
/// by Erwin Coumans (http://wwww.bulletphysics.org).
|
||||
int32_t ContactManifold::getIndexToRemove(int32_t indexMaxPenetration, const vec3& newPoint) const {
|
||||
|
||||
assert(m_nbContactPoints == MAX_CONTACT_POINTS_IN_MANIFOLD);
|
||||
|
||||
float area0 = 0.0; // Area with contact 1,2,3 and newPoint
|
||||
float area1 = 0.0; // Area with contact 0,2,3 and newPoint
|
||||
float area2 = 0.0; // Area with contact 0,1,3 and newPoint
|
||||
float area3 = 0.0; // Area with contact 0,1,2 and newPoint
|
||||
|
||||
float area0 = 0.0f; // Area with contact 1,2,3 and newPoint
|
||||
float area1 = 0.0f; // Area with contact 0,2,3 and newPoint
|
||||
float area2 = 0.0f; // Area with contact 0,1,3 and newPoint
|
||||
float area3 = 0.0f; // Area with contact 0,1,2 and newPoint
|
||||
if (indexMaxPenetration != 0) {
|
||||
// Compute the area
|
||||
vec3 vector1 = newPoint - m_contactPoints[1]->getLocalPointOnBody1();
|
||||
vec3 vector2 = m_contactPoints[3]->getLocalPointOnBody1() -
|
||||
m_contactPoints[2]->getLocalPointOnBody1();
|
||||
vec3 vector2 = m_contactPoints[3]->getLocalPointOnBody1() - m_contactPoints[2]->getLocalPointOnBody1();
|
||||
vec3 crossProduct = vector1.cross(vector2);
|
||||
area0 = crossProduct.length2();
|
||||
}
|
||||
if (indexMaxPenetration != 1) {
|
||||
// Compute the area
|
||||
vec3 vector1 = newPoint - m_contactPoints[0]->getLocalPointOnBody1();
|
||||
vec3 vector2 = m_contactPoints[3]->getLocalPointOnBody1() -
|
||||
m_contactPoints[2]->getLocalPointOnBody1();
|
||||
vec3 vector2 = m_contactPoints[3]->getLocalPointOnBody1() - m_contactPoints[2]->getLocalPointOnBody1();
|
||||
vec3 crossProduct = vector1.cross(vector2);
|
||||
area1 = crossProduct.length2();
|
||||
}
|
||||
if (indexMaxPenetration != 2) {
|
||||
// Compute the area
|
||||
vec3 vector1 = newPoint - m_contactPoints[0]->getLocalPointOnBody1();
|
||||
vec3 vector2 = m_contactPoints[3]->getLocalPointOnBody1() -
|
||||
m_contactPoints[1]->getLocalPointOnBody1();
|
||||
vec3 vector2 = m_contactPoints[3]->getLocalPointOnBody1() - m_contactPoints[1]->getLocalPointOnBody1();
|
||||
vec3 crossProduct = vector1.cross(vector2);
|
||||
area2 = crossProduct.length2();
|
||||
}
|
||||
if (indexMaxPenetration != 3) {
|
||||
// Compute the area
|
||||
vec3 vector1 = newPoint - m_contactPoints[0]->getLocalPointOnBody1();
|
||||
vec3 vector2 = m_contactPoints[2]->getLocalPointOnBody1() -
|
||||
m_contactPoints[1]->getLocalPointOnBody1();
|
||||
vec3 vector2 = m_contactPoints[2]->getLocalPointOnBody1() - m_contactPoints[1]->getLocalPointOnBody1();
|
||||
vec3 crossProduct = vector1.cross(vector2);
|
||||
area3 = crossProduct.length2();
|
||||
}
|
||||
|
||||
// Return the index of the contact to remove
|
||||
return getMaxArea(area0, area1, area2, area3);
|
||||
}
|
||||
|
||||
// Return the index of maximum area
|
||||
int32_t ContactManifold::getMaxArea(float area0, float area1, float area2, float area3) const {
|
||||
if (area0 < area1) {
|
||||
if (area1 < area2) {
|
||||
if (area2 < area3) return 3;
|
||||
else return 2;
|
||||
if (area2 < area3) {
|
||||
return 3;
|
||||
} else {
|
||||
return 2;
|
||||
}
|
||||
} else {
|
||||
if (area1 < area3) {
|
||||
return 3;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (area1 < area3) return 3;
|
||||
else return 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (area0 < area2) {
|
||||
if (area2 < area3) return 3;
|
||||
else return 2;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (area0 < area3) return 3;
|
||||
else return 0;
|
||||
}
|
||||
@ -237,8 +186,8 @@ void ContactManifold::clear() {
|
||||
|
||||
// Call the destructor explicitly and tell the memory allocator that
|
||||
// the corresponding memory block is now free
|
||||
delete m_contactPoints[iii];
|
||||
m_contactPoints[iii] = nullptr;
|
||||
ETK_DELETE(ContactPoint, m_contactPoints[iii]);
|
||||
m_contactPoints[iii] = null;
|
||||
}
|
||||
m_nbContactPoints = 0;
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -46,6 +49,17 @@ namespace ephysics {
|
||||
* The new added point is always kept.
|
||||
*/
|
||||
class ContactManifold {
|
||||
public:
|
||||
/// Constructor
|
||||
ContactManifold(ProxyShape* _shape1,
|
||||
ProxyShape* _shape2,
|
||||
int16_t _normalDirectionId);
|
||||
/// Destructor
|
||||
~ContactManifold();
|
||||
/// DELETE copy-constructor
|
||||
ContactManifold(const ContactManifold& _contactManifold) = delete;
|
||||
/// DELETE assignment operator
|
||||
ContactManifold& operator=(const ContactManifold& _contactManifold) = delete;
|
||||
private:
|
||||
ProxyShape* m_shape1; //!< Pointer to the first proxy shape of the contact
|
||||
ProxyShape* m_shape2; //!< Pointer to the second proxy shape of the contact
|
||||
@ -59,27 +73,33 @@ namespace ephysics {
|
||||
float m_frictionTwistImpulse; //!< Twist friction constraint accumulated impulse
|
||||
vec3 m_rollingResistanceImpulse; //!< Accumulated rolling resistance impulse
|
||||
bool m_isAlreadyInIsland; //!< True if the contact manifold has already been added int32_to an island
|
||||
/// Private copy-constructor
|
||||
ContactManifold(const ContactManifold& _contactManifold) = delete;
|
||||
/// Private assignment operator
|
||||
ContactManifold& operator=(const ContactManifold& _contactManifold) = delete;
|
||||
/// Return the index of maximum area
|
||||
int32_t getMaxArea(float _area0, float _area1, float _area2, float _area3) const;
|
||||
/// Return the index of the contact with the larger penetration depth.
|
||||
/**
|
||||
* @brief Return the index of the contact with the larger penetration depth.
|
||||
*
|
||||
* This corresponding contact will be kept in the cache. The method returns -1 is
|
||||
* the new contact is the deepest.
|
||||
*/
|
||||
int32_t getIndexOfDeepestPenetration(ContactPoint* _newContact) const;
|
||||
/// Return the index that will be removed.
|
||||
/**
|
||||
* @brief Return the index that will be removed.
|
||||
* The index of the contact point with the larger penetration
|
||||
* depth is given as a parameter. This contact won't be removed. Given this contact, we compute
|
||||
* the different area and we want to keep the contacts with the largest area. The new point is also
|
||||
* kept. In order to compute the area of a quadrilateral, we use the formula :
|
||||
* Area = 0.5 * | AC x BD | where AC and BD form the diagonals of the quadrilateral. Note that
|
||||
* when we compute this area, we do not calculate it exactly but we
|
||||
* only estimate it because we do not compute the actual diagonals of the quadrialteral. Therefore,
|
||||
* this is only a guess that is faster to compute. This idea comes from the Bullet Physics library
|
||||
* by Erwin Coumans (http://wwww.bulletphysics.org).
|
||||
*/
|
||||
int32_t getIndexToRemove(int32_t _indexMaxPenetration, const vec3& _newPoint) const;
|
||||
/// Remove a contact point from the manifold
|
||||
void removeContactPoint(uint32_t _index);
|
||||
/// Return true if the contact manifold has already been added int32_to an island
|
||||
bool isAlreadyInIsland() const;
|
||||
public:
|
||||
/// Constructor
|
||||
ContactManifold(ProxyShape* _shape1,
|
||||
ProxyShape* _shape2,
|
||||
int16_t _normalDirectionId);
|
||||
/// Destructor
|
||||
~ContactManifold();
|
||||
/// Return a pointer to the first proxy shape of the contact
|
||||
ProxyShape* getShape1() const;
|
||||
/// Return a pointer to the second proxy shape of the contact
|
||||
@ -92,7 +112,15 @@ namespace ephysics {
|
||||
int16_t getNormalDirectionId() const;
|
||||
/// Add a contact point to the manifold
|
||||
void addContactPoint(ContactPoint* _contact);
|
||||
/// Update the contact manifold.
|
||||
/**
|
||||
* @brief Update the contact manifold.
|
||||
*
|
||||
* First the world space coordinates of the current contacts in the manifold are recomputed from
|
||||
* the corresponding transforms of the bodies because they have moved. Then we remove the contacts
|
||||
* with a negative penetration depth (meaning that the bodies are not penetrating anymore) and also
|
||||
* the contacts with a too large distance between the contact points in the plane orthogonal to the
|
||||
* contact normal.
|
||||
*/
|
||||
void update(const etk::Transform3D& _transform1,
|
||||
const etk::Transform3D& _transform2);
|
||||
/// Clear the contact manifold
|
||||
|
@ -1,9 +1,11 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <ephysics/collision/ContactManifoldSet.hpp>
|
||||
|
||||
using namespace ephysics;
|
||||
@ -74,8 +76,8 @@ void ContactManifoldSet::addContactPoint(ContactPoint* contact) {
|
||||
// new contact point
|
||||
if (smallestDepthIndex == -1) {
|
||||
// Delete the new contact
|
||||
delete contact;
|
||||
contact = nullptr;
|
||||
ETK_DELETE(ContactPoint, contact);
|
||||
contact = null;
|
||||
return;
|
||||
}
|
||||
assert(smallestDepthIndex >= 0 && smallestDepthIndex < m_nbManifolds);
|
||||
@ -153,7 +155,7 @@ void ContactManifoldSet::clear() {
|
||||
|
||||
void ContactManifoldSet::createManifold(int16_t normalDirectionId) {
|
||||
assert(m_nbManifolds < m_nbMaxManifolds);
|
||||
m_manifolds[m_nbManifolds] = new ContactManifold(m_shape1, m_shape2, normalDirectionId);
|
||||
m_manifolds[m_nbManifolds] = ETK_NEW(ContactManifold, m_shape1, m_shape2, normalDirectionId);
|
||||
m_nbManifolds++;
|
||||
}
|
||||
|
||||
@ -161,8 +163,8 @@ void ContactManifoldSet::removeManifold(int32_t index) {
|
||||
assert(m_nbManifolds > 0);
|
||||
assert(index >= 0 && index < m_nbManifolds);
|
||||
// Delete the new contact
|
||||
delete m_manifolds[index];
|
||||
m_manifolds[index] = nullptr;
|
||||
ETK_DELETE(ContactManifold, m_manifolds[index]);
|
||||
m_manifolds[index] = null;
|
||||
for (int32_t i=index; (i+1) < m_nbManifolds; i++) {
|
||||
m_manifolds[i] = m_manifolds[i+1];
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
@ -1,10 +1,11 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
// Libraries
|
||||
#include <ephysics/collision/ProxyShape.hpp>
|
||||
|
||||
using namespace ephysics;
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
// Libraries
|
||||
|
||||
#include <ephysics/collision/RaycastInfo.hpp>
|
||||
#include <ephysics/collision/ProxyShape.hpp>
|
||||
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -33,8 +36,8 @@ namespace ephysics {
|
||||
RaycastInfo() :
|
||||
meshSubpart(-1),
|
||||
triangleIndex(-1),
|
||||
body(nullptr),
|
||||
proxyShape(nullptr) {
|
||||
body(null),
|
||||
proxyShape(null) {
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,11 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <ephysics/collision/TriangleMesh.hpp>
|
||||
|
||||
ephysics::TriangleMesh::TriangleMesh() {
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
#include <etk/Vector.hpp>
|
||||
|
@ -1,10 +1,11 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
// Libraries
|
||||
#include <ephysics/collision/TriangleVertexArray.hpp>
|
||||
|
||||
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
@ -1,60 +1,42 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
// Libraries
|
||||
#include <ephysics/collision/broadphase/BroadPhaseAlgorithm.hpp>
|
||||
#include <ephysics/collision/CollisionDetection.hpp>
|
||||
#include <ephysics/engine/Profiler.hpp>
|
||||
|
||||
using namespace ephysics;
|
||||
|
||||
BroadPhaseAlgorithm::BroadPhaseAlgorithm(CollisionDetection& collisionDetection)
|
||||
:m_dynamicAABBTree(DYNAMIC_TREE_AABB_GAP), m_numberMovedShapes(0), m_numberAllocatedMovedShapes(8),
|
||||
m_numberNonUsedMovedShapes(0), m_numberPotentialPairs(0), m_numberAllocatedPotentialPairs(8),
|
||||
m_collisionDetection(collisionDetection) {
|
||||
|
||||
// Allocate memory for the array of non-static proxy shapes IDs
|
||||
m_movedShapes = (int32_t*) malloc(m_numberAllocatedMovedShapes * sizeof(int32_t));
|
||||
assert(m_movedShapes != NULL);
|
||||
|
||||
// Allocate memory for the array of potential overlapping pairs
|
||||
m_potentialPairs = (BroadPhasePair*) malloc(m_numberAllocatedPotentialPairs * sizeof(BroadPhasePair));
|
||||
assert(m_potentialPairs != NULL);
|
||||
BroadPhaseAlgorithm::BroadPhaseAlgorithm(CollisionDetection& _collisionDetection):
|
||||
m_dynamicAABBTree(DYNAMIC_TREE_AABB_GAP),
|
||||
m_collisionDetection(_collisionDetection) {
|
||||
m_movedShapes.reserve(8);
|
||||
m_potentialPairs.reserve(8);
|
||||
}
|
||||
|
||||
BroadPhaseAlgorithm::~BroadPhaseAlgorithm() {
|
||||
|
||||
// Release the memory for the array of non-static proxy shapes IDs
|
||||
free(m_movedShapes);
|
||||
|
||||
// Release the memory for the array of potential overlapping pairs
|
||||
free(m_potentialPairs);
|
||||
|
||||
}
|
||||
|
||||
void BroadPhaseAlgorithm::addMovedCollisionShape(int32_t broadPhaseID) {
|
||||
void BroadPhaseAlgorithm::addMovedCollisionShape(int32_t _broadPhaseID) {
|
||||
m_movedShapes.pushBack(_broadPhaseID);
|
||||
}
|
||||
|
||||
// Allocate more elements in the array of shapes that have moved if necessary
|
||||
if (m_numberAllocatedMovedShapes == m_numberMovedShapes) {
|
||||
m_numberAllocatedMovedShapes *= 2;
|
||||
int32_t* oldArray = m_movedShapes;
|
||||
m_movedShapes = (int32_t*) malloc(m_numberAllocatedMovedShapes * sizeof(int32_t));
|
||||
assert(m_movedShapes != NULL);
|
||||
memcpy(m_movedShapes, oldArray, m_numberMovedShapes * sizeof(int32_t));
|
||||
free(oldArray);
|
||||
void BroadPhaseAlgorithm::removeMovedCollisionShape(int32_t _broadPhaseID) {
|
||||
auto it = m_movedShapes.begin();
|
||||
while (it != m_movedShapes.end()) {
|
||||
if (*it == _broadPhaseID) {
|
||||
it = m_movedShapes.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
// Store the broad-phase ID int32_to the array of shapes that have moved
|
||||
assert(m_numberMovedShapes < m_numberAllocatedMovedShapes);
|
||||
assert(m_movedShapes != NULL);
|
||||
m_movedShapes[m_numberMovedShapes] = broadPhaseID;
|
||||
m_numberMovedShapes++;
|
||||
}
|
||||
|
||||
void BroadPhaseAlgorithm::removeMovedCollisionShape(int32_t broadPhaseID) {
|
||||
|
||||
/*
|
||||
assert(m_numberNonUsedMovedShapes <= m_numberMovedShapes);
|
||||
|
||||
// If less than the quarter of allocated elements of the non-static shapes IDs array
|
||||
@ -86,28 +68,23 @@ void BroadPhaseAlgorithm::removeMovedCollisionShape(int32_t broadPhaseID) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void BroadPhaseAlgorithm::addProxyCollisionShape(ProxyShape* proxyShape, const AABB& aabb) {
|
||||
|
||||
void BroadPhaseAlgorithm::addProxyCollisionShape(ProxyShape* _proxyShape, const AABB& _aabb) {
|
||||
// Add the collision shape int32_to the dynamic AABB tree and get its broad-phase ID
|
||||
int32_t nodeId = m_dynamicAABBTree.addObject(aabb, proxyShape);
|
||||
|
||||
int32_t nodeId = m_dynamicAABBTree.addObject(_aabb, _proxyShape);
|
||||
// Set the broad-phase ID of the proxy shape
|
||||
proxyShape->m_broadPhaseID = nodeId;
|
||||
|
||||
_proxyShape->m_broadPhaseID = nodeId;
|
||||
// Add the collision shape int32_to the array of bodies that have moved (or have been created)
|
||||
// during the last simulation step
|
||||
addMovedCollisionShape(proxyShape->m_broadPhaseID);
|
||||
addMovedCollisionShape(_proxyShape->m_broadPhaseID);
|
||||
}
|
||||
|
||||
void BroadPhaseAlgorithm::removeProxyCollisionShape(ProxyShape* proxyShape) {
|
||||
|
||||
int32_t broadPhaseID = proxyShape->m_broadPhaseID;
|
||||
|
||||
void BroadPhaseAlgorithm::removeProxyCollisionShape(ProxyShape* _proxyShape) {
|
||||
int32_t broadPhaseID = _proxyShape->m_broadPhaseID;
|
||||
// Remove the collision shape from the dynamic AABB tree
|
||||
m_dynamicAABBTree.removeObject(broadPhaseID);
|
||||
|
||||
// Remove the collision shape int32_to the array of shapes that have moved (or have been created)
|
||||
// during the last simulation step
|
||||
removeMovedCollisionShape(broadPhaseID);
|
||||
@ -130,127 +107,80 @@ void BroadPhaseAlgorithm::updateProxyCollisionShape(ProxyShape* _proxyShape,
|
||||
}
|
||||
}
|
||||
|
||||
static bool sortFunction(const etk::Pair<int32_t,int32_t>& _pair1, const etk::Pair<int32_t,int32_t>& _pair2) {
|
||||
if (_pair1.first < _pair2.first) {
|
||||
return true;
|
||||
}
|
||||
if (_pair1.first == _pair2.first) {
|
||||
return _pair1.second < _pair2.second;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void BroadPhaseAlgorithm::computeOverlappingPairs() {
|
||||
|
||||
// Reset the potential overlapping pairs
|
||||
m_numberPotentialPairs = 0;
|
||||
|
||||
m_potentialPairs.clear();
|
||||
// For all collision shapes that have moved (or have been created) during the
|
||||
// last simulation step
|
||||
for (uint32_t i=0; i<m_numberMovedShapes; i++) {
|
||||
int32_t shapeID = m_movedShapes[i];
|
||||
|
||||
if (shapeID == -1) continue;
|
||||
|
||||
AABBOverlapCallback callback(*this, shapeID);
|
||||
|
||||
for (auto &it: m_movedShapes) {
|
||||
if (it == -1) {
|
||||
// impossible case ...
|
||||
continue;
|
||||
}
|
||||
// Get the AABB of the shape
|
||||
const AABB& shapeAABB = m_dynamicAABBTree.getFatAABB(shapeID);
|
||||
|
||||
const AABB& shapeAABB = m_dynamicAABBTree.getFatAABB(it);
|
||||
// Ask the dynamic AABB tree to report all collision shapes that overlap with
|
||||
// this AABB. The method BroadPhase::notifiyOverlappingPair() will be called
|
||||
// by the dynamic AABB tree for each potential overlapping pair.
|
||||
m_dynamicAABBTree.reportAllShapesOverlappingWithAABB(shapeAABB, callback);
|
||||
m_dynamicAABBTree.reportAllShapesOverlappingWithAABB(shapeAABB, [&](int32_t _nodeId) mutable {
|
||||
// If both the nodes are the same, we do not create store the overlapping pair
|
||||
if (it == _nodeId) {
|
||||
return;
|
||||
}
|
||||
// Add the new potential pair int32_to the array of potential overlapping pairs
|
||||
m_potentialPairs.pushBack(etk::makePair(etk::min(it, _nodeId), etk::max(it, _nodeId) ));
|
||||
});
|
||||
}
|
||||
|
||||
// Reset the array of collision shapes that have move (or have been created) during the
|
||||
// last simulation step
|
||||
m_numberMovedShapes = 0;
|
||||
|
||||
// Reset the array of collision shapes that have move (or have been created) during the last simulation step
|
||||
m_movedShapes.clear();
|
||||
// Sort the array of potential overlapping pairs in order to remove duplicate pairs
|
||||
std::sort(m_potentialPairs, m_potentialPairs + m_numberPotentialPairs, BroadPhasePair::smallerThan);
|
||||
|
||||
etk::algorithm::quickSort(m_potentialPairs, sortFunction);
|
||||
// Check all the potential overlapping pairs avoiding duplicates to report unique
|
||||
// overlapping pairs
|
||||
uint32_t i=0;
|
||||
while (i < m_numberPotentialPairs) {
|
||||
|
||||
uint32_t iii=0;
|
||||
while (iii < m_potentialPairs.size()) {
|
||||
// Get a potential overlapping pair
|
||||
BroadPhasePair* pair = m_potentialPairs + i;
|
||||
i++;
|
||||
|
||||
assert(pair->collisionShape1ID != pair->collisionShape2ID);
|
||||
|
||||
const etk::Pair<int32_t,int32_t>& pair = (m_potentialPairs[iii]);
|
||||
++iii;
|
||||
// Get the two collision shapes of the pair
|
||||
ProxyShape* shape1 = static_cast<ProxyShape*>(m_dynamicAABBTree.getNodeDataPointer(pair->collisionShape1ID));
|
||||
ProxyShape* shape2 = static_cast<ProxyShape*>(m_dynamicAABBTree.getNodeDataPointer(pair->collisionShape2ID));
|
||||
|
||||
ProxyShape* shape1 = static_cast<ProxyShape*>(m_dynamicAABBTree.getNodeDataPointer(pair.first));
|
||||
ProxyShape* shape2 = static_cast<ProxyShape*>(m_dynamicAABBTree.getNodeDataPointer(pair.second));
|
||||
// Notify the collision detection about the overlapping pair
|
||||
m_collisionDetection.broadPhaseNotifyOverlappingPair(shape1, shape2);
|
||||
|
||||
// Skip the duplicate overlapping pairs
|
||||
while (i < m_numberPotentialPairs) {
|
||||
|
||||
while (iii < m_potentialPairs.size()) {
|
||||
// Get the next pair
|
||||
BroadPhasePair* nextPair = m_potentialPairs + i;
|
||||
|
||||
const etk::Pair<int32_t,int32_t>& nextPair = m_potentialPairs[iii];
|
||||
// If the next pair is different from the previous one, we stop skipping pairs
|
||||
if (nextPair->collisionShape1ID != pair->collisionShape1ID ||
|
||||
nextPair->collisionShape2ID != pair->collisionShape2ID) {
|
||||
if ( nextPair.first != pair.first
|
||||
|| nextPair.second != pair.second) {
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
++iii;
|
||||
}
|
||||
}
|
||||
|
||||
// If the number of potential overlapping pairs is less than the quarter of allocated
|
||||
// number of overlapping pairs
|
||||
if (m_numberPotentialPairs < m_numberAllocatedPotentialPairs / 4 && m_numberPotentialPairs > 8) {
|
||||
|
||||
// Reduce the number of allocated potential overlapping pairs
|
||||
BroadPhasePair* oldPairs = m_potentialPairs;
|
||||
m_numberAllocatedPotentialPairs /= 2;
|
||||
m_potentialPairs = (BroadPhasePair*) malloc(m_numberAllocatedPotentialPairs * sizeof(BroadPhasePair));
|
||||
assert(m_potentialPairs);
|
||||
memcpy(m_potentialPairs, oldPairs, m_numberPotentialPairs * sizeof(BroadPhasePair));
|
||||
free(oldPairs);
|
||||
}
|
||||
}
|
||||
|
||||
void BroadPhaseAlgorithm::notifyOverlappingNodes(int32_t node1ID, int32_t node2ID) {
|
||||
|
||||
// If both the nodes are the same, we do not create store the overlapping pair
|
||||
if (node1ID == node2ID) return;
|
||||
|
||||
// If we need to allocate more memory for the array of potential overlapping pairs
|
||||
if (m_numberPotentialPairs == m_numberAllocatedPotentialPairs) {
|
||||
|
||||
// Allocate more memory for the array of potential pairs
|
||||
BroadPhasePair* oldPairs = m_potentialPairs;
|
||||
m_numberAllocatedPotentialPairs *= 2;
|
||||
m_potentialPairs = (BroadPhasePair*) malloc(m_numberAllocatedPotentialPairs * sizeof(BroadPhasePair));
|
||||
assert(m_potentialPairs);
|
||||
memcpy(m_potentialPairs, oldPairs, m_numberPotentialPairs * sizeof(BroadPhasePair));
|
||||
free(oldPairs);
|
||||
}
|
||||
|
||||
// Add the new potential pair int32_to the array of potential overlapping pairs
|
||||
m_potentialPairs[m_numberPotentialPairs].collisionShape1ID = etk::min(node1ID, node2ID);
|
||||
m_potentialPairs[m_numberPotentialPairs].collisionShape2ID = etk::max(node1ID, node2ID);
|
||||
m_numberPotentialPairs++;
|
||||
}
|
||||
|
||||
void AABBOverlapCallback::notifyOverlappingNode(int32_t nodeId) {
|
||||
|
||||
m_broadPhaseAlgorithm.notifyOverlappingNodes(m_referenceNodeId, nodeId);
|
||||
}
|
||||
|
||||
float BroadPhaseRaycastCallback::raycastBroadPhaseShape(int32_t nodeId, const Ray& ray) {
|
||||
|
||||
float BroadPhaseRaycastCallback::operator()(int32_t _nodeId, const Ray& _ray) {
|
||||
float hitFraction = float(-1.0);
|
||||
|
||||
// Get the proxy shape from the node
|
||||
ProxyShape* proxyShape = static_cast<ProxyShape*>(m_dynamicAABBTree.getNodeDataPointer(nodeId));
|
||||
|
||||
ProxyShape* proxyShape = static_cast<ProxyShape*>(m_dynamicAABBTree.getNodeDataPointer(_nodeId));
|
||||
// Check if the raycast filtering mask allows raycast against this shape
|
||||
if ((m_raycastWithCategoryMaskBits & proxyShape->getCollisionCategoryBits()) != 0) {
|
||||
|
||||
// Ask the collision detection to perform a ray cast test against
|
||||
// the proxy shape of this node because the ray is overlapping
|
||||
// with the shape in the broad-phase
|
||||
hitFraction = m_raycastTest.raycastAgainstShape(proxyShape, ray);
|
||||
hitFraction = m_raycastTest.raycastAgainstShape(proxyShape, _ray);
|
||||
}
|
||||
|
||||
return hitFraction;
|
||||
}
|
||||
|
||||
@ -259,7 +189,6 @@ bool BroadPhaseAlgorithm::testOverlappingShapes(const ProxyShape* _shape1,
|
||||
// Get the two AABBs of the collision shapes
|
||||
const AABB& aabb1 = m_dynamicAABBTree.getFatAABB(_shape1->m_broadPhaseID);
|
||||
const AABB& aabb2 = m_dynamicAABBTree.getFatAABB(_shape2->m_broadPhaseID);
|
||||
|
||||
// Check if the two AABBs are overlapping
|
||||
return aabb1.testCollision(aabb2);
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -16,49 +19,12 @@ namespace ephysics {
|
||||
class CollisionDetection;
|
||||
class BroadPhaseAlgorithm;
|
||||
|
||||
/**
|
||||
* @brief It represent a potential overlapping pair during the
|
||||
* broad-phase collision detection.
|
||||
*/
|
||||
struct BroadPhasePair {
|
||||
int32_t collisionShape1ID; //!< Broad-phase ID of the first collision shape
|
||||
int32_t collisionShape2ID; //!< Broad-phase ID of the second collision shape
|
||||
/**
|
||||
* @brief Method used to compare two pairs for sorting algorithm
|
||||
* @param[in] _pair1 first pair of element
|
||||
* @param[in] _pair2 Second pair of element
|
||||
* @return _pair1 is smaller than _pair2
|
||||
*/
|
||||
static bool smallerThan(const BroadPhasePair& _pair1, const BroadPhasePair& _pair2) {
|
||||
if (_pair1.collisionShape1ID < _pair2.collisionShape1ID) return true;
|
||||
if (_pair1.collisionShape1ID == _pair2.collisionShape1ID) {
|
||||
return _pair1.collisionShape2ID < _pair2.collisionShape2ID;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class AABBOverlapCallback : public DynamicAABBTreeOverlapCallback {
|
||||
private:
|
||||
BroadPhaseAlgorithm& m_broadPhaseAlgorithm;
|
||||
int32_t m_referenceNodeId;
|
||||
public:
|
||||
// Constructor
|
||||
AABBOverlapCallback(BroadPhaseAlgorithm& _broadPhaseAlgo, int32_t _referenceNodeId):
|
||||
m_broadPhaseAlgorithm(_broadPhaseAlgo),
|
||||
m_referenceNodeId(_referenceNodeId) {
|
||||
|
||||
}
|
||||
// Called when a overlapping node has been found during the call to
|
||||
// DynamicAABBTree:reportAllShapesOverlappingWithAABB()
|
||||
virtual void notifyOverlappingNode(int32_t nodeId);
|
||||
};
|
||||
|
||||
// TODO : remove this as callback ... DynamicAABBTreeOverlapCallback {
|
||||
/**
|
||||
* Callback called when the AABB of a leaf node is hit by a ray the
|
||||
* broad-phase Dynamic AABB Tree.
|
||||
*/
|
||||
class BroadPhaseRaycastCallback : public DynamicAABBTreeRaycastCallback {
|
||||
class BroadPhaseRaycastCallback {
|
||||
private :
|
||||
const DynamicAABBTree& m_dynamicAABBTree;
|
||||
unsigned short m_raycastWithCategoryMaskBits;
|
||||
@ -74,7 +40,7 @@ namespace ephysics {
|
||||
|
||||
}
|
||||
// Called for a broad-phase shape that has to be tested for raycast
|
||||
virtual float raycastBroadPhaseShape(int32_t _nodeId, const Ray& _ray);
|
||||
float operator()(int32_t _nodeId, const Ray& _ray);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -87,18 +53,13 @@ namespace ephysics {
|
||||
class BroadPhaseAlgorithm {
|
||||
protected :
|
||||
DynamicAABBTree m_dynamicAABBTree; //!< Dynamic AABB tree
|
||||
int32_t* m_movedShapes; //!< Array with the broad-phase IDs of all collision shapes that have moved (or have been created) during the last simulation step. Those are the shapes that need to be tested for overlapping in the next simulation step.
|
||||
uint32_t m_numberMovedShapes; //!< Number of collision shapes in the array of shapes that have moved during the last simulation step.
|
||||
uint32_t m_numberAllocatedMovedShapes; //!< Number of allocated elements for the array of shapes that have moved during the last simulation step.
|
||||
uint32_t m_numberNonUsedMovedShapes; //!< Number of non-used elements in the array of shapes that have moved during the last simulation step.
|
||||
BroadPhasePair* m_potentialPairs; //!< Temporary array of potential overlapping pairs (with potential duplicates)
|
||||
uint32_t m_numberPotentialPairs; //!< Number of potential overlapping pairs
|
||||
uint32_t m_numberAllocatedPotentialPairs; //!< Number of allocated elements for the array of potential overlapping pairs
|
||||
etk::Vector<int32_t> m_movedShapes; //!< Array with the broad-phase IDs of all collision shapes that have moved (or have been created) during the last simulation step. Those are the shapes that need to be tested for overlapping in the next simulation step.
|
||||
etk::Vector<etk::Pair<int32_t,int32_t>> m_potentialPairs; //!< Temporary array of potential overlapping pairs (with potential duplicates)
|
||||
CollisionDetection& m_collisionDetection; //!< Reference to the collision detection object
|
||||
/// Private copy-constructor
|
||||
BroadPhaseAlgorithm(const BroadPhaseAlgorithm& algorithm);
|
||||
BroadPhaseAlgorithm(const BroadPhaseAlgorithm& _obj);
|
||||
/// Private assignment operator
|
||||
BroadPhaseAlgorithm& operator=(const BroadPhaseAlgorithm& algorithm);
|
||||
BroadPhaseAlgorithm& operator=(const BroadPhaseAlgorithm& _obj);
|
||||
public :
|
||||
/// Constructor
|
||||
BroadPhaseAlgorithm(CollisionDetection& _collisionDetection);
|
||||
@ -119,8 +80,6 @@ namespace ephysics {
|
||||
/// Remove a collision shape from the array of shapes that have moved in the last simulation
|
||||
/// step and that need to be tested again for broad-phase overlapping.
|
||||
void removeMovedCollisionShape(int32_t _broadPhaseID);
|
||||
/// Notify the broad-phase about a potential overlapping pair in the dynamic AABB tree
|
||||
void notifyOverlappingNodes(int32_t _broadPhaseId1, int32_t _broadPhaseId2);
|
||||
/// Compute all the overlapping pairs of collision shapes
|
||||
void computeOverlappingPairs();
|
||||
/// Return true if the two broad-phase collision shapes are overlapping
|
||||
|
@ -1,9 +1,11 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <ephysics/collision/broadphase/DynamicAABBTree.hpp>
|
||||
#include <ephysics/collision/broadphase/BroadPhaseAlgorithm.hpp>
|
||||
#include <ephysics/memory/Stack.hpp>
|
||||
@ -14,28 +16,24 @@ using namespace ephysics;
|
||||
|
||||
const int32_t TreeNode::NULL_TREE_NODE = -1;
|
||||
|
||||
DynamicAABBTree::DynamicAABBTree(float extraAABBGap) : m_extraAABBGap(extraAABBGap) {
|
||||
|
||||
DynamicAABBTree::DynamicAABBTree(float _extraAABBGap):
|
||||
m_extraAABBGap(_extraAABBGap) {
|
||||
init();
|
||||
}
|
||||
|
||||
DynamicAABBTree::~DynamicAABBTree() {
|
||||
|
||||
free(m_nodes);
|
||||
}
|
||||
|
||||
// Initialize the tree
|
||||
void DynamicAABBTree::init() {
|
||||
|
||||
m_rootNodeID = TreeNode::NULL_TREE_NODE;
|
||||
m_numberNodes = 0;
|
||||
m_numberAllocatedNodes = 8;
|
||||
|
||||
// Allocate memory for the nodes of the tree
|
||||
m_nodes = (TreeNode*) malloc(m_numberAllocatedNodes * sizeof(TreeNode));
|
||||
assert(m_nodes);
|
||||
memset(m_nodes, 0, m_numberAllocatedNodes * sizeof(TreeNode));
|
||||
|
||||
// Initialize the allocated nodes
|
||||
for (int32_t i=0; i<m_numberAllocatedNodes - 1; i++) {
|
||||
m_nodes[i].nextNodeID = i + 1;
|
||||
@ -48,10 +46,8 @@ void DynamicAABBTree::init() {
|
||||
|
||||
// Clear all the nodes and reset the tree
|
||||
void DynamicAABBTree::reset() {
|
||||
|
||||
// Free the allocated memory for the nodes
|
||||
free(m_nodes);
|
||||
|
||||
// Initialize the tree
|
||||
init();
|
||||
}
|
||||
@ -88,7 +84,6 @@ int32_t DynamicAABBTree::allocateNode() {
|
||||
|
||||
// Release a node
|
||||
void DynamicAABBTree::releaseNode(int32_t _nodeID) {
|
||||
|
||||
assert(m_numberNodes > 0);
|
||||
assert(_nodeID >= 0 && _nodeID < m_numberAllocatedNodes);
|
||||
assert(m_nodes[_nodeID].height >= 0);
|
||||
@ -100,34 +95,26 @@ void DynamicAABBTree::releaseNode(int32_t _nodeID) {
|
||||
|
||||
// Internally add an object int32_to the tree
|
||||
int32_t DynamicAABBTree::addObjectInternal(const AABB& aabb) {
|
||||
|
||||
// Get the next available node (or allocate new ones if necessary)
|
||||
int32_t _nodeID = allocateNode();
|
||||
|
||||
// Create the fat aabb to use in the tree
|
||||
const vec3 gap(m_extraAABBGap, m_extraAABBGap, m_extraAABBGap);
|
||||
m_nodes[_nodeID].aabb.setMin(aabb.getMin() - gap);
|
||||
m_nodes[_nodeID].aabb.setMax(aabb.getMax() + gap);
|
||||
|
||||
// Set the height of the node in the tree
|
||||
m_nodes[_nodeID].height = 0;
|
||||
|
||||
// Insert the new leaf node in the tree
|
||||
insertLeafNode(_nodeID);
|
||||
assert(m_nodes[_nodeID].isLeaf());
|
||||
|
||||
assert(_nodeID >= 0);
|
||||
|
||||
// Return the Id of the node
|
||||
return _nodeID;
|
||||
}
|
||||
|
||||
// Remove an object from the tree
|
||||
void DynamicAABBTree::removeObject(int32_t _nodeID) {
|
||||
|
||||
assert(_nodeID >= 0 && _nodeID < m_numberAllocatedNodes);
|
||||
assert(m_nodes[_nodeID].isLeaf());
|
||||
|
||||
// Remove the node from the tree
|
||||
removeLeafNode(_nodeID);
|
||||
releaseNode(_nodeID);
|
||||
@ -142,30 +129,24 @@ void DynamicAABBTree::removeObject(int32_t _nodeID) {
|
||||
/// frames. If the "forceReinsert" parameter is true, we force a removal and reinsertion of the node
|
||||
/// (this can be useful if the shape AABB has become much smaller than the previous one for instance).
|
||||
bool DynamicAABBTree::updateObject(int32_t _nodeID, const AABB& _newAABB, const vec3& _displacement, bool _forceReinsert) {
|
||||
|
||||
PROFILE("DynamicAABBTree::updateObject()");
|
||||
|
||||
assert(_nodeID >= 0 && _nodeID < m_numberAllocatedNodes);
|
||||
assert(m_nodes[_nodeID].isLeaf());
|
||||
assert(m_nodes[_nodeID].height >= 0);
|
||||
|
||||
EPHY_INFO(" compare : " << m_nodes[_nodeID].aabb.m_minCoordinates << " " << m_nodes[_nodeID].aabb.m_maxCoordinates);
|
||||
EPHY_INFO(" : " << _newAABB.m_minCoordinates << " " << _newAABB.m_maxCoordinates);
|
||||
EPHY_VERBOSE(" compare : " << m_nodes[_nodeID].aabb.m_minCoordinates << " " << m_nodes[_nodeID].aabb.m_maxCoordinates);
|
||||
EPHY_VERBOSE(" : " << _newAABB.m_minCoordinates << " " << _newAABB.m_maxCoordinates);
|
||||
// If the new AABB is still inside the fat AABB of the node
|
||||
if ( _forceReinsert == false
|
||||
&& m_nodes[_nodeID].aabb.contains(_newAABB)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the new AABB is outside the fat AABB, we remove the corresponding node
|
||||
removeLeafNode(_nodeID);
|
||||
|
||||
// Compute the fat AABB by inflating the AABB with a constant gap
|
||||
m_nodes[_nodeID].aabb = _newAABB;
|
||||
const vec3 gap(m_extraAABBGap, m_extraAABBGap, m_extraAABBGap);
|
||||
m_nodes[_nodeID].aabb.m_minCoordinates -= gap;
|
||||
m_nodes[_nodeID].aabb.m_maxCoordinates += gap;
|
||||
|
||||
// Inflate the fat AABB in direction of the linear motion of the AABB
|
||||
if (_displacement.x() < 0.0f) {
|
||||
m_nodes[_nodeID].aabb.m_minCoordinates.setX(m_nodes[_nodeID].aabb.m_minCoordinates.x() + DYNAMIC_TREE_AABB_LIN_GAP_MULTIPLIER *_displacement.x());
|
||||
@ -188,10 +169,8 @@ bool DynamicAABBTree::updateObject(int32_t _nodeID, const AABB& _newAABB, const
|
||||
//EPHY_CRITICAL("ERROR");
|
||||
}
|
||||
assert(m_nodes[_nodeID].aabb.contains(_newAABB));
|
||||
|
||||
// Reinsert the node int32_to the tree
|
||||
insertLeafNode(_nodeID);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -199,75 +178,61 @@ bool DynamicAABBTree::updateObject(int32_t _nodeID, const AABB& _newAABB, const
|
||||
// in the dynamic tree is described in the book "Introduction to Game Physics
|
||||
// with Box2D" by Ian Parberry.
|
||||
void DynamicAABBTree::insertLeafNode(int32_t _nodeID) {
|
||||
|
||||
// If the tree is empty
|
||||
if (m_rootNodeID == TreeNode::NULL_TREE_NODE) {
|
||||
m_rootNodeID = _nodeID;
|
||||
m_nodes[m_rootNodeID].parentID = TreeNode::NULL_TREE_NODE;
|
||||
return;
|
||||
}
|
||||
|
||||
assert(m_rootNodeID != TreeNode::NULL_TREE_NODE);
|
||||
|
||||
// Find the best sibling node for the new node
|
||||
AABB newNodeAABB = m_nodes[_nodeID].aabb;
|
||||
int32_t currentNodeID = m_rootNodeID;
|
||||
while (!m_nodes[currentNodeID].isLeaf()) {
|
||||
|
||||
int32_t leftChild = m_nodes[currentNodeID].children[0];
|
||||
int32_t rightChild = m_nodes[currentNodeID].children[1];
|
||||
|
||||
// Compute the merged AABB
|
||||
float volumeAABB = m_nodes[currentNodeID].aabb.getVolume();
|
||||
AABB mergedAABBs;
|
||||
mergedAABBs.mergeTwoAABBs(m_nodes[currentNodeID].aabb, newNodeAABB);
|
||||
float mergedVolume = mergedAABBs.getVolume();
|
||||
|
||||
// Compute the cost of making the current node the sibbling of the new node
|
||||
float costS = float(2.0) * mergedVolume;
|
||||
|
||||
// Compute the minimum cost of pushing the new node further down the tree (inheritance cost)
|
||||
float costI = float(2.0) * (mergedVolume - volumeAABB);
|
||||
|
||||
// Compute the cost of descending int32_to the left child
|
||||
float costLeft;
|
||||
AABB currentAndLeftAABB;
|
||||
currentAndLeftAABB.mergeTwoAABBs(newNodeAABB, m_nodes[leftChild].aabb);
|
||||
if (m_nodes[leftChild].isLeaf()) { // If the left child is a leaf
|
||||
costLeft = currentAndLeftAABB.getVolume() + costI;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
float leftChildVolume = m_nodes[leftChild].aabb.getVolume();
|
||||
costLeft = costI + currentAndLeftAABB.getVolume() - leftChildVolume;
|
||||
}
|
||||
|
||||
// Compute the cost of descending int32_to the right child
|
||||
float costRight;
|
||||
AABB currentAndRightAABB;
|
||||
currentAndRightAABB.mergeTwoAABBs(newNodeAABB, m_nodes[rightChild].aabb);
|
||||
if (m_nodes[rightChild].isLeaf()) { // If the right child is a leaf
|
||||
costRight = currentAndRightAABB.getVolume() + costI;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
float rightChildVolume = m_nodes[rightChild].aabb.getVolume();
|
||||
costRight = costI + currentAndRightAABB.getVolume() - rightChildVolume;
|
||||
}
|
||||
|
||||
// If the cost of making the current node a sibbling of the new node is smaller than
|
||||
// the cost of going down int32_to the left or right child
|
||||
if (costS < costLeft && costS < costRight) break;
|
||||
|
||||
if (costS < costLeft && costS < costRight) {
|
||||
break;
|
||||
}
|
||||
// It is cheaper to go down int32_to a child of the current node, choose the best child
|
||||
if (costLeft < costRight) {
|
||||
currentNodeID = leftChild;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
currentNodeID = rightChild;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t siblingNode = currentNodeID;
|
||||
|
||||
// Create a new parent for the new node and the sibling node
|
||||
int32_t oldParentNode = m_nodes[siblingNode].parentID;
|
||||
int32_t newParentNode = allocateNode();
|
||||
@ -275,120 +240,96 @@ void DynamicAABBTree::insertLeafNode(int32_t _nodeID) {
|
||||
m_nodes[newParentNode].aabb.mergeTwoAABBs(m_nodes[siblingNode].aabb, newNodeAABB);
|
||||
m_nodes[newParentNode].height = m_nodes[siblingNode].height + 1;
|
||||
assert(m_nodes[newParentNode].height > 0);
|
||||
|
||||
// If the sibling node was not the root node
|
||||
if (oldParentNode != TreeNode::NULL_TREE_NODE) {
|
||||
assert(!m_nodes[oldParentNode].isLeaf());
|
||||
if (m_nodes[oldParentNode].children[0] == siblingNode) {
|
||||
m_nodes[oldParentNode].children[0] = newParentNode;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
m_nodes[oldParentNode].children[1] = newParentNode;
|
||||
}
|
||||
m_nodes[newParentNode].children[0] = siblingNode;
|
||||
m_nodes[newParentNode].children[1] = _nodeID;
|
||||
m_nodes[siblingNode].parentID = newParentNode;
|
||||
m_nodes[_nodeID].parentID = newParentNode;
|
||||
}
|
||||
else { // If the sibling node was the root node
|
||||
} else {
|
||||
// If the sibling node was the root node
|
||||
m_nodes[newParentNode].children[0] = siblingNode;
|
||||
m_nodes[newParentNode].children[1] = _nodeID;
|
||||
m_nodes[siblingNode].parentID = newParentNode;
|
||||
m_nodes[_nodeID].parentID = newParentNode;
|
||||
m_rootNodeID = newParentNode;
|
||||
}
|
||||
|
||||
// Move up in the tree to change the AABBs that have changed
|
||||
currentNodeID = m_nodes[_nodeID].parentID;
|
||||
assert(!m_nodes[currentNodeID].isLeaf());
|
||||
while (currentNodeID != TreeNode::NULL_TREE_NODE) {
|
||||
|
||||
// Balance the sub-tree of the current node if it is not balanced
|
||||
currentNodeID = balanceSubTreeAtNode(currentNodeID);
|
||||
assert(m_nodes[_nodeID].isLeaf());
|
||||
|
||||
assert(!m_nodes[currentNodeID].isLeaf());
|
||||
int32_t leftChild = m_nodes[currentNodeID].children[0];
|
||||
int32_t rightChild = m_nodes[currentNodeID].children[1];
|
||||
assert(leftChild != TreeNode::NULL_TREE_NODE);
|
||||
assert(rightChild != TreeNode::NULL_TREE_NODE);
|
||||
|
||||
// Recompute the height of the node in the tree
|
||||
m_nodes[currentNodeID].height = etk::max(m_nodes[leftChild].height,
|
||||
m_nodes[rightChild].height) + 1;
|
||||
assert(m_nodes[currentNodeID].height > 0);
|
||||
|
||||
// Recompute the AABB of the node
|
||||
m_nodes[currentNodeID].aabb.mergeTwoAABBs(m_nodes[leftChild].aabb, m_nodes[rightChild].aabb);
|
||||
|
||||
currentNodeID = m_nodes[currentNodeID].parentID;
|
||||
}
|
||||
|
||||
assert(m_nodes[_nodeID].isLeaf());
|
||||
}
|
||||
|
||||
// Remove a leaf node from the tree
|
||||
void DynamicAABBTree::removeLeafNode(int32_t _nodeID) {
|
||||
|
||||
assert(_nodeID >= 0 && _nodeID < m_numberAllocatedNodes);
|
||||
assert(m_nodes[_nodeID].isLeaf());
|
||||
|
||||
// If we are removing the root node (root node is a leaf in this case)
|
||||
if (m_rootNodeID == _nodeID) {
|
||||
m_rootNodeID = TreeNode::NULL_TREE_NODE;
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t parentNodeID = m_nodes[_nodeID].parentID;
|
||||
int32_t grandParentNodeID = m_nodes[parentNodeID].parentID;
|
||||
int32_t siblingNodeID;
|
||||
if (m_nodes[parentNodeID].children[0] == _nodeID) {
|
||||
siblingNodeID = m_nodes[parentNodeID].children[1];
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
siblingNodeID = m_nodes[parentNodeID].children[0];
|
||||
}
|
||||
|
||||
// If the parent of the node to remove is not the root node
|
||||
if (grandParentNodeID != TreeNode::NULL_TREE_NODE) {
|
||||
|
||||
// Destroy the parent node
|
||||
if (m_nodes[grandParentNodeID].children[0] == parentNodeID) {
|
||||
m_nodes[grandParentNodeID].children[0] = siblingNodeID;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
assert(m_nodes[grandParentNodeID].children[1] == parentNodeID);
|
||||
m_nodes[grandParentNodeID].children[1] = siblingNodeID;
|
||||
}
|
||||
m_nodes[siblingNodeID].parentID = grandParentNodeID;
|
||||
releaseNode(parentNodeID);
|
||||
|
||||
// Now, we need to recompute the AABBs of the node on the path back to the root
|
||||
// and make sure that the tree is still balanced
|
||||
int32_t currentNodeID = grandParentNodeID;
|
||||
while(currentNodeID != TreeNode::NULL_TREE_NODE) {
|
||||
|
||||
// Balance the current sub-tree if necessary
|
||||
currentNodeID = balanceSubTreeAtNode(currentNodeID);
|
||||
|
||||
assert(!m_nodes[currentNodeID].isLeaf());
|
||||
|
||||
// Get the two children of the current node
|
||||
int32_t leftChildID = m_nodes[currentNodeID].children[0];
|
||||
int32_t rightChildID = m_nodes[currentNodeID].children[1];
|
||||
|
||||
// Recompute the AABB and the height of the current node
|
||||
m_nodes[currentNodeID].aabb.mergeTwoAABBs(m_nodes[leftChildID].aabb,
|
||||
m_nodes[rightChildID].aabb);
|
||||
m_nodes[currentNodeID].height = etk::max(m_nodes[leftChildID].height,
|
||||
m_nodes[rightChildID].height) + 1;
|
||||
assert(m_nodes[currentNodeID].height > 0);
|
||||
|
||||
currentNodeID = m_nodes[currentNodeID].parentID;
|
||||
}
|
||||
}
|
||||
else { // If the parent of the node to remove is the root node
|
||||
|
||||
} else { // If the parent of the node to remove is the root node
|
||||
// The sibling node becomes the new root node
|
||||
m_rootNodeID = siblingNodeID;
|
||||
m_nodes[siblingNodeID].parentID = TreeNode::NULL_TREE_NODE;
|
||||
@ -400,18 +341,13 @@ void DynamicAABBTree::removeLeafNode(int32_t _nodeID) {
|
||||
/// The rotation schemes are described in the book "Introduction to Game Physics
|
||||
/// with Box2D" by Ian Parberry. This method returns the new root node ID.
|
||||
int32_t DynamicAABBTree::balanceSubTreeAtNode(int32_t _nodeID) {
|
||||
|
||||
assert(_nodeID != TreeNode::NULL_TREE_NODE);
|
||||
|
||||
TreeNode* nodeA = m_nodes + _nodeID;
|
||||
|
||||
// If the node is a leaf or the height of A's sub-tree is less than 2
|
||||
if (nodeA->isLeaf() || nodeA->height < 2) {
|
||||
|
||||
// Do not perform any rotation
|
||||
return _nodeID;
|
||||
}
|
||||
|
||||
// Get the two children nodes
|
||||
int32_t nodeBID = nodeA->children[0];
|
||||
int32_t nodeCID = nodeA->children[1];
|
||||
@ -419,185 +355,147 @@ int32_t DynamicAABBTree::balanceSubTreeAtNode(int32_t _nodeID) {
|
||||
assert(nodeCID >= 0 && nodeCID < m_numberAllocatedNodes);
|
||||
TreeNode* nodeB = m_nodes + nodeBID;
|
||||
TreeNode* nodeC = m_nodes + nodeCID;
|
||||
|
||||
// Compute the factor of the left and right sub-trees
|
||||
int32_t balanceFactor = nodeC->height - nodeB->height;
|
||||
|
||||
// If the right node C is 2 higher than left node B
|
||||
if (balanceFactor > 1) {
|
||||
|
||||
assert(!nodeC->isLeaf());
|
||||
|
||||
int32_t nodeFID = nodeC->children[0];
|
||||
int32_t nodeGID = nodeC->children[1];
|
||||
assert(nodeFID >= 0 && nodeFID < m_numberAllocatedNodes);
|
||||
assert(nodeGID >= 0 && nodeGID < m_numberAllocatedNodes);
|
||||
TreeNode* nodeF = m_nodes + nodeFID;
|
||||
TreeNode* nodeG = m_nodes + nodeGID;
|
||||
|
||||
nodeC->children[0] = _nodeID;
|
||||
nodeC->parentID = nodeA->parentID;
|
||||
nodeA->parentID = nodeCID;
|
||||
|
||||
if (nodeC->parentID != TreeNode::NULL_TREE_NODE) {
|
||||
|
||||
if (m_nodes[nodeC->parentID].children[0] == _nodeID) {
|
||||
m_nodes[nodeC->parentID].children[0] = nodeCID;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
assert(m_nodes[nodeC->parentID].children[1] == _nodeID);
|
||||
m_nodes[nodeC->parentID].children[1] = nodeCID;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
m_rootNodeID = nodeCID;
|
||||
}
|
||||
|
||||
assert(!nodeC->isLeaf());
|
||||
assert(!nodeA->isLeaf());
|
||||
|
||||
// If the right node C was higher than left node B because of the F node
|
||||
if (nodeF->height > nodeG->height) {
|
||||
|
||||
nodeC->children[1] = nodeFID;
|
||||
nodeA->children[1] = nodeGID;
|
||||
nodeG->parentID = _nodeID;
|
||||
|
||||
// Recompute the AABB of node A and C
|
||||
nodeA->aabb.mergeTwoAABBs(nodeB->aabb, nodeG->aabb);
|
||||
nodeC->aabb.mergeTwoAABBs(nodeA->aabb, nodeF->aabb);
|
||||
|
||||
// Recompute the height of node A and C
|
||||
nodeA->height = etk::max(nodeB->height, nodeG->height) + 1;
|
||||
nodeC->height = etk::max(nodeA->height, nodeF->height) + 1;
|
||||
assert(nodeA->height > 0);
|
||||
assert(nodeC->height > 0);
|
||||
}
|
||||
else { // If the right node C was higher than left node B because of node G
|
||||
} else {
|
||||
// If the right node C was higher than left node B because of node G
|
||||
nodeC->children[1] = nodeGID;
|
||||
nodeA->children[1] = nodeFID;
|
||||
nodeF->parentID = _nodeID;
|
||||
|
||||
// Recompute the AABB of node A and C
|
||||
nodeA->aabb.mergeTwoAABBs(nodeB->aabb, nodeF->aabb);
|
||||
nodeC->aabb.mergeTwoAABBs(nodeA->aabb, nodeG->aabb);
|
||||
|
||||
// Recompute the height of node A and C
|
||||
nodeA->height = etk::max(nodeB->height, nodeF->height) + 1;
|
||||
nodeC->height = etk::max(nodeA->height, nodeG->height) + 1;
|
||||
assert(nodeA->height > 0);
|
||||
assert(nodeC->height > 0);
|
||||
}
|
||||
|
||||
// Return the new root of the sub-tree
|
||||
return nodeCID;
|
||||
}
|
||||
|
||||
// If the left node B is 2 higher than right node C
|
||||
if (balanceFactor < -1) {
|
||||
|
||||
assert(!nodeB->isLeaf());
|
||||
|
||||
int32_t nodeFID = nodeB->children[0];
|
||||
int32_t nodeGID = nodeB->children[1];
|
||||
assert(nodeFID >= 0 && nodeFID < m_numberAllocatedNodes);
|
||||
assert(nodeGID >= 0 && nodeGID < m_numberAllocatedNodes);
|
||||
TreeNode* nodeF = m_nodes + nodeFID;
|
||||
TreeNode* nodeG = m_nodes + nodeGID;
|
||||
|
||||
nodeB->children[0] = _nodeID;
|
||||
nodeB->parentID = nodeA->parentID;
|
||||
nodeA->parentID = nodeBID;
|
||||
|
||||
if (nodeB->parentID != TreeNode::NULL_TREE_NODE) {
|
||||
|
||||
if (m_nodes[nodeB->parentID].children[0] == _nodeID) {
|
||||
m_nodes[nodeB->parentID].children[0] = nodeBID;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
assert(m_nodes[nodeB->parentID].children[1] == _nodeID);
|
||||
m_nodes[nodeB->parentID].children[1] = nodeBID;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
m_rootNodeID = nodeBID;
|
||||
}
|
||||
|
||||
assert(!nodeB->isLeaf());
|
||||
assert(!nodeA->isLeaf());
|
||||
|
||||
// If the left node B was higher than right node C because of the F node
|
||||
if (nodeF->height > nodeG->height) {
|
||||
|
||||
nodeB->children[1] = nodeFID;
|
||||
nodeA->children[0] = nodeGID;
|
||||
nodeG->parentID = _nodeID;
|
||||
|
||||
// Recompute the AABB of node A and B
|
||||
nodeA->aabb.mergeTwoAABBs(nodeC->aabb, nodeG->aabb);
|
||||
nodeB->aabb.mergeTwoAABBs(nodeA->aabb, nodeF->aabb);
|
||||
|
||||
// Recompute the height of node A and B
|
||||
nodeA->height = etk::max(nodeC->height, nodeG->height) + 1;
|
||||
nodeB->height = etk::max(nodeA->height, nodeF->height) + 1;
|
||||
assert(nodeA->height > 0);
|
||||
assert(nodeB->height > 0);
|
||||
}
|
||||
else { // If the left node B was higher than right node C because of node G
|
||||
} else {
|
||||
// If the left node B was higher than right node C because of node G
|
||||
nodeB->children[1] = nodeGID;
|
||||
nodeA->children[0] = nodeFID;
|
||||
nodeF->parentID = _nodeID;
|
||||
|
||||
// Recompute the AABB of node A and B
|
||||
nodeA->aabb.mergeTwoAABBs(nodeC->aabb, nodeF->aabb);
|
||||
nodeB->aabb.mergeTwoAABBs(nodeA->aabb, nodeG->aabb);
|
||||
|
||||
// Recompute the height of node A and B
|
||||
nodeA->height = etk::max(nodeC->height, nodeF->height) + 1;
|
||||
nodeB->height = etk::max(nodeA->height, nodeG->height) + 1;
|
||||
assert(nodeA->height > 0);
|
||||
assert(nodeB->height > 0);
|
||||
}
|
||||
|
||||
// Return the new root of the sub-tree
|
||||
return nodeBID;
|
||||
}
|
||||
|
||||
// If the sub-tree is balanced, return the current root node
|
||||
return _nodeID;
|
||||
}
|
||||
|
||||
/// Report all shapes overlapping with the AABB given in parameter.
|
||||
void DynamicAABBTree::reportAllShapesOverlappingWithAABB(const AABB& aabb,
|
||||
DynamicAABBTreeOverlapCallback& callback) const {
|
||||
|
||||
void DynamicAABBTree::reportAllShapesOverlappingWithAABB(const AABB& _aabb, etk::Function<void(int32_t nodeId)> _callback) const {
|
||||
if (_callback == null) {
|
||||
EPHY_ERROR("call with null callback");
|
||||
return;
|
||||
}
|
||||
// Create a stack with the nodes to visit
|
||||
Stack<int32_t, 64> stack;
|
||||
stack.push(m_rootNodeID);
|
||||
|
||||
// While there are still nodes to visit
|
||||
while(stack.getNbElements() > 0) {
|
||||
|
||||
// Get the next node ID to visit
|
||||
int32_t nodeIDToVisit = stack.pop();
|
||||
|
||||
// Skip it if it is a null node
|
||||
if (nodeIDToVisit == TreeNode::NULL_TREE_NODE) continue;
|
||||
|
||||
if (nodeIDToVisit == TreeNode::NULL_TREE_NODE) {
|
||||
continue;
|
||||
}
|
||||
// Get the corresponding node
|
||||
const TreeNode* nodeToVisit = m_nodes + nodeIDToVisit;
|
||||
|
||||
// If the AABB in parameter overlaps with the AABB of the node to visit
|
||||
if (aabb.testCollision(nodeToVisit->aabb)) {
|
||||
|
||||
if (_aabb.testCollision(nodeToVisit->aabb)) {
|
||||
// If the node is a leaf
|
||||
if (nodeToVisit->isLeaf()) {
|
||||
|
||||
// Notify the broad-phase about a new potential overlapping pair
|
||||
callback.notifyOverlappingNode(nodeIDToVisit);
|
||||
}
|
||||
else { // If the node is not a leaf
|
||||
|
||||
_callback(nodeIDToVisit);
|
||||
} else {
|
||||
// If the node is not a leaf
|
||||
// We need to visit its children
|
||||
stack.push(nodeToVisit->children[0]);
|
||||
stack.push(nodeToVisit->children[1]);
|
||||
@ -607,60 +505,51 @@ void DynamicAABBTree::reportAllShapesOverlappingWithAABB(const AABB& aabb,
|
||||
}
|
||||
|
||||
// Ray casting method
|
||||
void DynamicAABBTree::raycast(const Ray& ray, DynamicAABBTreeRaycastCallback &callback) const {
|
||||
|
||||
void DynamicAABBTree::raycast(const ephysics::Ray& _ray, etk::Function<float(int32_t _nodeId, const ephysics::Ray& _ray)> _callback) const {
|
||||
PROFILE("DynamicAABBTree::raycast()");
|
||||
|
||||
float maxFraction = ray.maxFraction;
|
||||
|
||||
if (_callback == null) {
|
||||
EPHY_ERROR("call with null callback");
|
||||
return;
|
||||
}
|
||||
float maxFraction = _ray.maxFraction;
|
||||
Stack<int32_t, 128> stack;
|
||||
stack.push(m_rootNodeID);
|
||||
|
||||
// Walk through the tree from the root looking for proxy shapes
|
||||
// that overlap with the ray AABB
|
||||
while (stack.getNbElements() > 0) {
|
||||
|
||||
// Get the next node in the stack
|
||||
int32_t nodeID = stack.pop();
|
||||
|
||||
// If it is a null node, skip it
|
||||
if (nodeID == TreeNode::NULL_TREE_NODE) continue;
|
||||
|
||||
if (nodeID == TreeNode::NULL_TREE_NODE) {
|
||||
continue;
|
||||
}
|
||||
// Get the corresponding node
|
||||
const TreeNode* node = m_nodes + nodeID;
|
||||
|
||||
Ray rayTemp(ray.point1, ray.point2, maxFraction);
|
||||
|
||||
Ray rayTemp(_ray.point1, _ray.point2, maxFraction);
|
||||
// Test if the ray int32_tersects with the current node AABB
|
||||
if (!node->aabb.testRayIntersect(rayTemp)) continue;
|
||||
|
||||
if (node->aabb.testRayIntersect(rayTemp) == false) {
|
||||
continue;
|
||||
}
|
||||
// If the node is a leaf of the tree
|
||||
if (node->isLeaf()) {
|
||||
|
||||
// Call the callback that will raycast again the broad-phase shape
|
||||
float hitFraction = callback.raycastBroadPhaseShape(nodeID, rayTemp);
|
||||
|
||||
float hitFraction = _callback(nodeID, rayTemp);
|
||||
// If the user returned a hitFraction of zero, it means that
|
||||
// the raycasting should stop here
|
||||
if (hitFraction == 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the user returned a positive fraction
|
||||
if (hitFraction > 0.0f) {
|
||||
|
||||
// We update the maxFraction value and the ray
|
||||
// AABB using the new maximum fraction
|
||||
if (hitFraction < maxFraction) {
|
||||
maxFraction = hitFraction;
|
||||
}
|
||||
}
|
||||
|
||||
// If the user returned a negative fraction, we continue
|
||||
// the raycasting as if the proxy shape did not exist
|
||||
}
|
||||
else { // If the node has children
|
||||
|
||||
} else { // If the node has children
|
||||
// Push its children in the stack of nodes to explore
|
||||
stack.push(node->children[0]);
|
||||
stack.push(node->children[1]);
|
||||
@ -701,95 +590,75 @@ AABB DynamicAABBTree::getRootAABB() const {
|
||||
// Add an object int32_to the tree. This method creates a new leaf node in the tree and
|
||||
// returns the ID of the corresponding node.
|
||||
int32_t DynamicAABBTree::addObject(const AABB& aabb, int32_t data1, int32_t data2) {
|
||||
|
||||
int32_t nodeId = addObjectInternal(aabb);
|
||||
|
||||
m_nodes[nodeId].dataInt[0] = data1;
|
||||
m_nodes[nodeId].dataInt[1] = data2;
|
||||
|
||||
return nodeId;
|
||||
}
|
||||
|
||||
// Add an object int32_to the tree. This method creates a new leaf node in the tree and
|
||||
// returns the ID of the corresponding node.
|
||||
int32_t DynamicAABBTree::addObject(const AABB& aabb, void* data) {
|
||||
|
||||
int32_t nodeId = addObjectInternal(aabb);
|
||||
|
||||
m_nodes[nodeId].dataPointer = data;
|
||||
|
||||
return nodeId;
|
||||
}
|
||||
|
||||
|
||||
#ifndef NDEBUG
|
||||
#ifdef DEBUG
|
||||
|
||||
// Check if the tree structure is valid (for debugging purpose)
|
||||
void DynamicAABBTree::check() const {
|
||||
|
||||
// Recursively check each node
|
||||
checkNode(m_rootNodeID);
|
||||
|
||||
int32_t nbFreeNodes = 0;
|
||||
int32_t freeNodeID = m_freeNodeID;
|
||||
|
||||
// Check the free nodes
|
||||
while(freeNodeID != TreeNode::NULL_TREE_NODE) {
|
||||
assert(0 <= freeNodeID && freeNodeID < m_numberAllocatedNodes);
|
||||
freeNodeID = m_nodes[freeNodeID].nextNodeID;
|
||||
nbFreeNodes++;
|
||||
}
|
||||
|
||||
assert(m_numberNodes + nbFreeNodes == m_numberAllocatedNodes);
|
||||
}
|
||||
|
||||
// Check if the node structure is valid (for debugging purpose)
|
||||
void DynamicAABBTree::checkNode(int32_t _nodeID) const {
|
||||
|
||||
if (_nodeID == TreeNode::NULL_TREE_NODE) return;
|
||||
|
||||
if (_nodeID == TreeNode::NULL_TREE_NODE) {
|
||||
return;
|
||||
}
|
||||
// If it is the root
|
||||
if (_nodeID == m_rootNodeID) {
|
||||
assert(m_nodes[_nodeID].parentID == TreeNode::NULL_TREE_NODE);
|
||||
}
|
||||
|
||||
// Get the children nodes
|
||||
TreeNode* pNode = m_nodes + _nodeID;
|
||||
assert(!pNode->isLeaf());
|
||||
int32_t leftChild = pNode->children[0];
|
||||
int32_t rightChild = pNode->children[1];
|
||||
|
||||
assert(pNode->height >= 0);
|
||||
assert(pNode->aabb.getVolume() > 0);
|
||||
|
||||
// If the current node is a leaf
|
||||
if (pNode->isLeaf()) {
|
||||
|
||||
// Check that there are no children
|
||||
assert(leftChild == TreeNode::NULL_TREE_NODE);
|
||||
assert(rightChild == TreeNode::NULL_TREE_NODE);
|
||||
assert(pNode->height == 0);
|
||||
}
|
||||
else {
|
||||
|
||||
} else {
|
||||
// Check that the children node IDs are valid
|
||||
assert(0 <= leftChild && leftChild < m_numberAllocatedNodes);
|
||||
assert(0 <= rightChild && rightChild < m_numberAllocatedNodes);
|
||||
|
||||
// Check that the children nodes have the correct parent node
|
||||
assert(m_nodes[leftChild].parentID == _nodeID);
|
||||
assert(m_nodes[rightChild].parentID == _nodeID);
|
||||
|
||||
// Check the height of node
|
||||
int32_t height = 1 + etk::max(m_nodes[leftChild].height, m_nodes[rightChild].height);
|
||||
assert(m_nodes[_nodeID].height == height);
|
||||
|
||||
// Check the AABB of the node
|
||||
AABB aabb;
|
||||
aabb.mergeTwoAABBs(m_nodes[leftChild].aabb, m_nodes[rightChild].aabb);
|
||||
assert(aabb.getMin() == m_nodes[_nodeID].aabb.getMin());
|
||||
assert(aabb.getMax() == m_nodes[_nodeID].aabb.getMax());
|
||||
|
||||
// Recursively check the children nodes
|
||||
checkNode(leftChild);
|
||||
checkNode(rightChild);
|
||||
@ -798,23 +667,20 @@ void DynamicAABBTree::checkNode(int32_t _nodeID) const {
|
||||
|
||||
// Compute the height of the tree
|
||||
int32_t DynamicAABBTree::computeHeight() {
|
||||
return computeHeight(m_rootNodeID);
|
||||
return computeHeight(m_rootNodeID);
|
||||
}
|
||||
|
||||
// Compute the height of a given node in the tree
|
||||
int32_t DynamicAABBTree::computeHeight(int32_t _nodeID) {
|
||||
assert(_nodeID >= 0 && _nodeID < m_numberAllocatedNodes);
|
||||
TreeNode* node = m_nodes + _nodeID;
|
||||
|
||||
// If the node is a leaf, its height is zero
|
||||
if (node->isLeaf()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Compute the height of the left and right sub-tree
|
||||
int32_t leftHeight = computeHeight(node->children[0]);
|
||||
int32_t rightHeight = computeHeight(node->children[1]);
|
||||
|
||||
// Return the height of the node
|
||||
return 1 + etk::max(leftHeight, rightHeight);
|
||||
}
|
||||
|
@ -1,19 +1,20 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <ephysics/configuration.hpp>
|
||||
#include <ephysics/collision/shapes/AABB.hpp>
|
||||
#include <ephysics/body/CollisionBody.hpp>
|
||||
#include <etk/Function.hpp>
|
||||
|
||||
namespace ephysics {
|
||||
class BroadPhaseAlgorithm;
|
||||
class BroadPhaseRaycastTestCallback;
|
||||
class DynamicAABBTreeOverlapCallback;
|
||||
struct RaycastTest;
|
||||
// TODO: to replace this, create a Tree<T> template (multiple child) or TreeRedBlack<T>
|
||||
/**
|
||||
* @brief It represents a node of the dynamic AABB tree.
|
||||
*/
|
||||
@ -43,29 +44,6 @@ namespace ephysics {
|
||||
bool isLeaf() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Overlapping callback method that has to be used as parameter of the
|
||||
* reportAllShapesOverlappingWithNode() method.
|
||||
*/
|
||||
class DynamicAABBTreeOverlapCallback {
|
||||
public :
|
||||
virtual ~DynamicAABBTreeOverlapCallback() = default;
|
||||
// Called when a overlapping node has been found during the call to
|
||||
// DynamicAABBTree:reportAllShapesOverlappingWithAABB()
|
||||
virtual void notifyOverlappingNode(int32_t nodeId)=0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Raycast callback in the Dynamic AABB Tree called when the AABB of a leaf
|
||||
* node is hit by the ray.
|
||||
*/
|
||||
class DynamicAABBTreeRaycastCallback {
|
||||
public:
|
||||
virtual ~DynamicAABBTreeRaycastCallback() = default;
|
||||
// Called when the AABB of a leaf node is hit by a ray
|
||||
virtual float raycastBroadPhaseShape(int32_t nodeId, const Ray& ray)=0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief It implements a dynamic AABB tree that is used for broad-phase
|
||||
* collision detection. This data structure is inspired by Nathanael Presson's
|
||||
@ -123,10 +101,9 @@ namespace ephysics {
|
||||
/// Return the data pointer of a given leaf node of the tree
|
||||
void* getNodeDataPointer(int32_t _nodeID) const;
|
||||
/// Report all shapes overlapping with the AABB given in parameter.
|
||||
void reportAllShapesOverlappingWithAABB(const AABB& _aabb,
|
||||
DynamicAABBTreeOverlapCallback& _callback) const;
|
||||
void reportAllShapesOverlappingWithAABB(const AABB& _aabb, etk::Function<void(int32_t _nodeId)> _callback) const;
|
||||
/// Ray casting method
|
||||
void raycast(const Ray& _ray, DynamicAABBTreeRaycastCallback& _callback) const;
|
||||
void raycast(const Ray& _ray, etk::Function<float(int32_t _nodeId, const ephysics::Ray& _ray)> _callback) const;
|
||||
/// Compute the height of the tree
|
||||
int32_t computeHeight();
|
||||
/// Return the root AABB of the tree
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
@ -1,14 +1,17 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <ephysics/collision/shapes/ConcaveShape.hpp>
|
||||
#include <ephysics/collision/shapes/TriangleShape.hpp>
|
||||
#include <ephysics/collision/narrowphase/ConcaveVsConvexAlgorithm.hpp>
|
||||
#include <ephysics/collision/CollisionDetection.hpp>
|
||||
#include <ephysics/engine/CollisionWorld.hpp>
|
||||
#include <etk/algorithm.hpp>
|
||||
|
||||
using namespace ephysics;
|
||||
|
||||
@ -16,29 +19,25 @@ ConcaveVsConvexAlgorithm::ConcaveVsConvexAlgorithm() {
|
||||
|
||||
}
|
||||
|
||||
ConcaveVsConvexAlgorithm::~ConcaveVsConvexAlgorithm() {
|
||||
|
||||
}
|
||||
|
||||
void ConcaveVsConvexAlgorithm::testCollision(const CollisionShapeInfo& shape1Info,
|
||||
const CollisionShapeInfo& shape2Info,
|
||||
NarrowPhaseCallback* narrowPhaseCallback) {
|
||||
void ConcaveVsConvexAlgorithm::testCollision(const CollisionShapeInfo& _shape1Info,
|
||||
const CollisionShapeInfo& _shape2Info,
|
||||
NarrowPhaseCallback* _callback) {
|
||||
ProxyShape* convexProxyShape;
|
||||
ProxyShape* concaveProxyShape;
|
||||
const ConvexShape* convexShape;
|
||||
const ConcaveShape* concaveShape;
|
||||
// Collision shape 1 is convex, collision shape 2 is concave
|
||||
if (shape1Info.collisionShape->isConvex()) {
|
||||
convexProxyShape = shape1Info.proxyShape;
|
||||
convexShape = static_cast<const ConvexShape*>(shape1Info.collisionShape);
|
||||
concaveProxyShape = shape2Info.proxyShape;
|
||||
concaveShape = static_cast<const ConcaveShape*>(shape2Info.collisionShape);
|
||||
if (_shape1Info.collisionShape->isConvex()) {
|
||||
convexProxyShape = _shape1Info.proxyShape;
|
||||
convexShape = static_cast<const ConvexShape*>(_shape1Info.collisionShape);
|
||||
concaveProxyShape = _shape2Info.proxyShape;
|
||||
concaveShape = static_cast<const ConcaveShape*>(_shape2Info.collisionShape);
|
||||
} else {
|
||||
// Collision shape 2 is convex, collision shape 1 is concave
|
||||
convexProxyShape = shape2Info.proxyShape;
|
||||
convexShape = static_cast<const ConvexShape*>(shape2Info.collisionShape);
|
||||
concaveProxyShape = shape1Info.proxyShape;
|
||||
concaveShape = static_cast<const ConcaveShape*>(shape1Info.collisionShape);
|
||||
convexProxyShape = _shape2Info.proxyShape;
|
||||
convexShape = static_cast<const ConvexShape*>(_shape2Info.collisionShape);
|
||||
concaveProxyShape = _shape1Info.proxyShape;
|
||||
concaveShape = static_cast<const ConcaveShape*>(_shape1Info.collisionShape);
|
||||
}
|
||||
// Set the parameters of the callback object
|
||||
ConvexVsTriangleCallback convexVsTriangleCallback;
|
||||
@ -46,7 +45,7 @@ void ConcaveVsConvexAlgorithm::testCollision(const CollisionShapeInfo& shape1Inf
|
||||
convexVsTriangleCallback.setConvexShape(convexShape);
|
||||
convexVsTriangleCallback.setConcaveShape(concaveShape);
|
||||
convexVsTriangleCallback.setProxyShapes(convexProxyShape, concaveProxyShape);
|
||||
convexVsTriangleCallback.setOverlappingPair(shape1Info.overlappingPair);
|
||||
convexVsTriangleCallback.setOverlappingPair(_shape1Info.overlappingPair);
|
||||
// Compute the convex shape AABB in the local-space of the convex shape
|
||||
AABB aabb;
|
||||
convexShape->computeAABB(aabb, convexProxyShape->getLocalToWorldTransform());
|
||||
@ -58,51 +57,55 @@ void ConcaveVsConvexAlgorithm::testCollision(const CollisionShapeInfo& shape1Inf
|
||||
// Call the convex vs triangle callback for each triangle of the concave shape
|
||||
concaveShape->testAllTriangles(convexVsTriangleCallback, aabb);
|
||||
// Run the smooth mesh collision algorithm
|
||||
processSmoothMeshCollision(shape1Info.overlappingPair, contactPoints, narrowPhaseCallback);
|
||||
processSmoothMeshCollision(_shape1Info.overlappingPair, contactPoints, _callback);
|
||||
} else {
|
||||
convexVsTriangleCallback.setNarrowPhaseCallback(narrowPhaseCallback);
|
||||
convexVsTriangleCallback.setNarrowPhaseCallback(_callback);
|
||||
// Call the convex vs triangle callback for each triangle of the concave shape
|
||||
concaveShape->testAllTriangles(convexVsTriangleCallback, aabb);
|
||||
}
|
||||
}
|
||||
|
||||
void ConvexVsTriangleCallback::testTriangle(const vec3* trianglePoints) {
|
||||
void ConvexVsTriangleCallback::testTriangle(const vec3* _trianglePoints) {
|
||||
// Create a triangle collision shape
|
||||
float margin = m_concaveShape->getTriangleMargin();
|
||||
TriangleShape triangleShape(trianglePoints[0], trianglePoints[1], trianglePoints[2], margin);
|
||||
TriangleShape triangleShape(_trianglePoints[0], _trianglePoints[1], _trianglePoints[2], margin);
|
||||
// Select the collision algorithm to use between the triangle and the convex shape
|
||||
NarrowPhaseAlgorithm* algo = m_collisionDetection->getCollisionAlgorithm(triangleShape.getType(),
|
||||
m_convexShape->getType());
|
||||
NarrowPhaseAlgorithm* algo = m_collisionDetection->getCollisionAlgorithm(triangleShape.getType(), m_convexShape->getType());
|
||||
// If there is no collision algorithm between those two kinds of shapes
|
||||
if (algo == nullptr) {
|
||||
if (algo == null) {
|
||||
return;
|
||||
}
|
||||
// Notify the narrow-phase algorithm about the overlapping pair we are going to test
|
||||
algo->setCurrentOverlappingPair(m_overlappingPair);
|
||||
// Create the CollisionShapeInfo objects
|
||||
CollisionShapeInfo shapeConvexInfo(m_convexProxyShape, m_convexShape, m_convexProxyShape->getLocalToWorldTransform(),
|
||||
m_overlappingPair, m_convexProxyShape->getCachedCollisionData());
|
||||
CollisionShapeInfo shapeConcaveInfo(m_concaveProxyShape, &triangleShape,
|
||||
m_concaveProxyShape->getLocalToWorldTransform(),
|
||||
m_overlappingPair, m_concaveProxyShape->getCachedCollisionData());
|
||||
CollisionShapeInfo shapeConvexInfo(m_convexProxyShape,
|
||||
m_convexShape,
|
||||
m_convexProxyShape->getLocalToWorldTransform(),
|
||||
m_overlappingPair,
|
||||
m_convexProxyShape->getCachedCollisionData());
|
||||
CollisionShapeInfo shapeConcaveInfo(m_concaveProxyShape,
|
||||
&triangleShape,
|
||||
m_concaveProxyShape->getLocalToWorldTransform(),
|
||||
m_overlappingPair,
|
||||
m_concaveProxyShape->getCachedCollisionData());
|
||||
// Use the collision algorithm to test collision between the triangle and the other convex shape
|
||||
algo->testCollision(shapeConvexInfo, shapeConcaveInfo, m_narrowPhaseCallback);
|
||||
}
|
||||
|
||||
void ConcaveVsConvexAlgorithm::processSmoothMeshCollision(OverlappingPair* overlappingPair,
|
||||
etk::Vector<SmoothMeshContactInfo> contactPoints,
|
||||
NarrowPhaseCallback* narrowPhaseCallback) {
|
||||
static bool sortFunction(const SmoothMeshContactInfo& _contact1, const SmoothMeshContactInfo& _contact2) {
|
||||
return _contact1.contactInfo.penetrationDepth <= _contact2.contactInfo.penetrationDepth;
|
||||
}
|
||||
|
||||
void ConcaveVsConvexAlgorithm::processSmoothMeshCollision(OverlappingPair* _overlappingPair,
|
||||
etk::Vector<SmoothMeshContactInfo> _contactPoints,
|
||||
NarrowPhaseCallback* _callback) {
|
||||
// Set with the triangle vertices already processed to void further contacts with same triangle
|
||||
etk::Vector<etk::Pair<int32_t, vec3>> processTriangleVertices;
|
||||
// Sort the list of narrow-phase contacts according to their penetration depth
|
||||
contactPoints.sort(0,
|
||||
contactPoints.size()-1,
|
||||
[](const SmoothMeshContactInfo& _contact1, const SmoothMeshContactInfo& _contact2) {
|
||||
return _contact1.contactInfo.penetrationDepth < _contact2.contactInfo.penetrationDepth;
|
||||
});
|
||||
etk::algorithm::quickSort(_contactPoints, sortFunction);
|
||||
// For each contact point (from smaller penetration depth to larger)
|
||||
etk::Vector<SmoothMeshContactInfo>::Iterator it;
|
||||
for (it = contactPoints.begin(); it != contactPoints.end(); ++it) {
|
||||
for (it = _contactPoints.begin(); it != _contactPoints.end(); ++it) {
|
||||
const SmoothMeshContactInfo info = *it;
|
||||
const vec3& contactPoint = info.isFirstShapeTriangle ? info.contactInfo.localPoint1 : info.contactInfo.localPoint2;
|
||||
// Compute the barycentric coordinates of the point in the triangle
|
||||
@ -130,7 +133,7 @@ void ConcaveVsConvexAlgorithm::processSmoothMeshCollision(OverlappingPair* overl
|
||||
// Check that this triangle vertex has not been processed yet
|
||||
if (!hasVertexBeenProcessed(processTriangleVertices, contactVertex)) {
|
||||
// Keep the contact as it is and report it
|
||||
narrowPhaseCallback->notifyContact(overlappingPair, info.contactInfo);
|
||||
_callback->notifyContact(_overlappingPair, info.contactInfo);
|
||||
}
|
||||
} else if (nbZeros == 1) {
|
||||
// If it is an edge contact
|
||||
@ -140,7 +143,7 @@ void ConcaveVsConvexAlgorithm::processSmoothMeshCollision(OverlappingPair* overl
|
||||
if (!hasVertexBeenProcessed(processTriangleVertices, contactVertex1) &&
|
||||
!hasVertexBeenProcessed(processTriangleVertices, contactVertex2)) {
|
||||
// Keep the contact as it is and report it
|
||||
narrowPhaseCallback->notifyContact(overlappingPair, info.contactInfo);
|
||||
_callback->notifyContact(_overlappingPair, info.contactInfo);
|
||||
}
|
||||
} else {
|
||||
// If it is a face contact
|
||||
@ -148,11 +151,11 @@ void ConcaveVsConvexAlgorithm::processSmoothMeshCollision(OverlappingPair* overl
|
||||
ProxyShape* firstShape;
|
||||
ProxyShape* secondShape;
|
||||
if (info.isFirstShapeTriangle) {
|
||||
firstShape = overlappingPair->getShape1();
|
||||
secondShape = overlappingPair->getShape2();
|
||||
firstShape = _overlappingPair->getShape1();
|
||||
secondShape = _overlappingPair->getShape2();
|
||||
} else {
|
||||
firstShape = overlappingPair->getShape2();
|
||||
secondShape = overlappingPair->getShape1();
|
||||
firstShape = _overlappingPair->getShape2();
|
||||
secondShape = _overlappingPair->getShape1();
|
||||
}
|
||||
// We use the triangle normal as the contact normal
|
||||
vec3 a = info.triangleVertices[1] - info.triangleVertices[0];
|
||||
@ -177,7 +180,7 @@ void ConcaveVsConvexAlgorithm::processSmoothMeshCollision(OverlappingPair* overl
|
||||
newContactInfo.localPoint1 = worldToLocalSecondPoint * newSecondWorldPoint;
|
||||
}
|
||||
// Report the contact
|
||||
narrowPhaseCallback->notifyContact(overlappingPair, newContactInfo);
|
||||
_callback->notifyContact(_overlappingPair, newContactInfo);
|
||||
}
|
||||
// Add the three vertices of the triangle to the set of processed
|
||||
// triangle vertices
|
||||
@ -212,7 +215,7 @@ bool ConcaveVsConvexAlgorithm::hasVertexBeenProcessed(const etk::Vector<etk::Pai
|
||||
}
|
||||
|
||||
void SmoothCollisionNarrowPhaseCallback::notifyContact(OverlappingPair* _overlappingPair,
|
||||
const ContactPointInfo& _contactInfo) {
|
||||
const ContactPointInfo& _contactInfo) {
|
||||
vec3 triangleVertices[3];
|
||||
bool isFirstShapeTriangle;
|
||||
// If the collision shape 1 is the triangle
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -135,8 +138,6 @@ namespace ephysics {
|
||||
public :
|
||||
/// Constructor
|
||||
ConcaveVsConvexAlgorithm();
|
||||
/// Destructor
|
||||
virtual ~ConcaveVsConvexAlgorithm();
|
||||
/// Compute a contact info if the two bounding volume collide
|
||||
virtual void testCollision(const CollisionShapeInfo& _shape1Info,
|
||||
const CollisionShapeInfo& _shape2Info,
|
||||
|
@ -1,9 +1,11 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
// Libraries
|
||||
#include <ephysics/collision/narrowphase/DefaultCollisionDispatch.hpp>
|
||||
#include <ephysics/collision/shapes/CollisionShape.hpp>
|
||||
@ -40,6 +42,6 @@ NarrowPhaseAlgorithm* DefaultCollisionDispatch::selectAlgorithm(int32_t _type1,
|
||||
// Convex vs Convex algorithm (GJK algorithm)
|
||||
return &m_GJKAlgorithm;
|
||||
} else {
|
||||
return nullptr;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#include <ephysics/collision/narrowphase/EPA/EPAAlgorithm.hpp>
|
||||
#include <ephysics/engine/Profiler.hpp>
|
||||
@ -18,64 +21,63 @@ EPAAlgorithm::~EPAAlgorithm() {
|
||||
|
||||
}
|
||||
|
||||
int32_t EPAAlgorithm::isOriginInTetrahedron(const vec3& p1, const vec3& p2, const vec3& p3, const vec3& p4) const {
|
||||
int32_t EPAAlgorithm::isOriginInTetrahedron(const vec3& _p1, const vec3& _p2, const vec3& _p3, const vec3& _p4) const {
|
||||
// Check vertex 1
|
||||
vec3 normal1 = (p2-p1).cross(p3-p1);
|
||||
if ((normal1.dot(p1) > 0.0) == (normal1.dot(p4) > 0.0)) {
|
||||
vec3 normal1 = (_p2-_p1).cross(_p3-_p1);
|
||||
if ((normal1.dot(_p1) > 0.0) == (normal1.dot(_p4) > 0.0)) {
|
||||
return 4;
|
||||
}
|
||||
// Check vertex 2
|
||||
vec3 normal2 = (p4-p2).cross(p3-p2);
|
||||
if ((normal2.dot(p2) > 0.0) == (normal2.dot(p1) > 0.0)) {
|
||||
vec3 normal2 = (_p4-_p2).cross(_p3-_p2);
|
||||
if ((normal2.dot(_p2) > 0.0) == (normal2.dot(_p1) > 0.0)) {
|
||||
return 1;
|
||||
}
|
||||
// Check vertex 3
|
||||
vec3 normal3 = (p4-p3).cross(p1-p3);
|
||||
if ((normal3.dot(p3) > 0.0) == (normal3.dot(p2) > 0.0)) {
|
||||
vec3 normal3 = (_p4-_p3).cross(_p1-_p3);
|
||||
if ((normal3.dot(_p3) > 0.0) == (normal3.dot(_p2) > 0.0)) {
|
||||
return 2;
|
||||
}
|
||||
// Check vertex 4
|
||||
vec3 normal4 = (p2-p4).cross(p1-p4);
|
||||
if ((normal4.dot(p4) > 0.0) == (normal4.dot(p3) > 0.0)) {
|
||||
vec3 normal4 = (_p2-_p4).cross(_p1-_p4);
|
||||
if ((normal4.dot(_p4) > 0.0) == (normal4.dot(_p3) > 0.0)) {
|
||||
return 3;
|
||||
}
|
||||
// The origin is in the tetrahedron, we return 0
|
||||
return 0;
|
||||
}
|
||||
|
||||
void EPAAlgorithm::computePenetrationDepthAndContactPoints(const Simplex& simplex,
|
||||
CollisionShapeInfo shape1Info,
|
||||
const etk::Transform3D& transform1,
|
||||
CollisionShapeInfo shape2Info,
|
||||
const etk::Transform3D& transform2,
|
||||
vec3& v,
|
||||
NarrowPhaseCallback* narrowPhaseCallback) {
|
||||
void EPAAlgorithm::computePenetrationDepthAndContactPoints(const Simplex& _simplex,
|
||||
CollisionShapeInfo _shape1Info,
|
||||
const etk::Transform3D& _transform1,
|
||||
CollisionShapeInfo _shape2Info,
|
||||
const etk::Transform3D& _transform2,
|
||||
vec3& _vector,
|
||||
NarrowPhaseCallback* narrowPhaseCallback) {
|
||||
PROFILE("EPAAlgorithm::computePenetrationDepthAndContactPoints()");
|
||||
assert(shape1Info.collisionShape->isConvex());
|
||||
assert(shape2Info.collisionShape->isConvex());
|
||||
const ConvexShape* shape1 = static_cast<const ConvexShape*>(shape1Info.collisionShape);
|
||||
const ConvexShape* shape2 = static_cast<const ConvexShape*>(shape2Info.collisionShape);
|
||||
void** shape1CachedCollisionData = shape1Info.cachedCollisionData;
|
||||
void** shape2CachedCollisionData = shape2Info.cachedCollisionData;
|
||||
assert(_shape1Info.collisionShape->isConvex());
|
||||
assert(_shape2Info.collisionShape->isConvex());
|
||||
const ConvexShape* shape1 = static_cast<const ConvexShape*>(_shape1Info.collisionShape);
|
||||
const ConvexShape* shape2 = static_cast<const ConvexShape*>(_shape2Info.collisionShape);
|
||||
void** shape1CachedCollisionData = _shape1Info.cachedCollisionData;
|
||||
void** shape2CachedCollisionData = _shape2Info.cachedCollisionData;
|
||||
vec3 suppPointsA[MAX_SUPPORT_POINTS]; // Support points of object A in local coordinates
|
||||
vec3 suppPointsB[MAX_SUPPORT_POINTS]; // Support points of object B in local coordinates
|
||||
vec3 points[MAX_SUPPORT_POINTS]; // Current points
|
||||
TrianglesStore triangleStore; // Store the triangles
|
||||
TriangleEPA* triangleHeap[MAX_FACETS]; // Heap that contains the face
|
||||
// candidate of the EPA algorithm
|
||||
etk::Set<TriangleEPA*> triangleHeap; // list of face candidate of the EPA algorithm sorted lower square dist to upper square dist
|
||||
triangleHeap.setComparator([](TriangleEPA * const & _face1, TriangleEPA * const & _face2) {
|
||||
return (_face1->getDistSquare() < _face2->getDistSquare());
|
||||
});
|
||||
// etk::Transform3D a point from local space of body 2 to local
|
||||
// space of body 1 (the GJK algorithm is done in local space of body 1)
|
||||
etk::Transform3D body2Tobody1 = transform1.getInverse() * transform2;
|
||||
etk::Transform3D body2Tobody1 = _transform1.getInverse() * _transform2;
|
||||
// Matrix that transform a direction from local
|
||||
// space of body 1 int32_to local space of body 2
|
||||
etk::Quaternion rotateToBody2 = transform2.getOrientation().getInverse() *
|
||||
transform1.getOrientation();
|
||||
etk::Quaternion rotateToBody2 = _transform2.getOrientation().getInverse() * _transform1.getOrientation();
|
||||
// Get the simplex computed previously by the GJK algorithm
|
||||
uint32_t nbVertices = simplex.getSimplex(suppPointsA, suppPointsB, points);
|
||||
uint32_t nbVertices = _simplex.getSimplex(suppPointsA, suppPointsB, points);
|
||||
// Compute the tolerance
|
||||
float tolerance = FLT_EPSILON * simplex.getMaxLengthSquareOfAPoint();
|
||||
// Number of triangles in the polytope
|
||||
uint32_t nbTriangles = 0;
|
||||
float tolerance = FLT_EPSILON * _simplex.getMaxLengthSquareOfAPoint();
|
||||
// Clear the storing of triangles
|
||||
triangleStore.clear();
|
||||
// Select an action according to the number of points in the simplex
|
||||
@ -177,10 +179,10 @@ void EPAAlgorithm::computePenetrationDepthAndContactPoints(const Simplex& simple
|
||||
link(EdgeEPA(face1, 1), EdgeEPA(face3, 0));
|
||||
link(EdgeEPA(face2, 1), EdgeEPA(face3, 1));
|
||||
// Add the triangle faces in the candidate heap
|
||||
addFaceCandidate(face0, triangleHeap, nbTriangles, FLT_MAX);
|
||||
addFaceCandidate(face1, triangleHeap, nbTriangles, FLT_MAX);
|
||||
addFaceCandidate(face2, triangleHeap, nbTriangles, FLT_MAX);
|
||||
addFaceCandidate(face3, triangleHeap, nbTriangles, FLT_MAX);
|
||||
addFaceCandidate(face0, triangleHeap, FLT_MAX);
|
||||
addFaceCandidate(face1, triangleHeap, FLT_MAX);
|
||||
addFaceCandidate(face2, triangleHeap, FLT_MAX);
|
||||
addFaceCandidate(face3, triangleHeap, FLT_MAX);
|
||||
break;
|
||||
}
|
||||
// The tetrahedron contains a wrong vertex (the origin is not inside the tetrahedron)
|
||||
@ -213,10 +215,10 @@ void EPAAlgorithm::computePenetrationDepthAndContactPoints(const Simplex& simple
|
||||
suppPointsB[4] = body2Tobody1 *
|
||||
shape2->getLocalSupportPointWithMargin(rotateToBody2 * n, shape2CachedCollisionData);
|
||||
points[4] = suppPointsA[4] - suppPointsB[4];
|
||||
TriangleEPA* face0 = NULL;
|
||||
TriangleEPA* face1 = NULL;
|
||||
TriangleEPA* face2 = NULL;
|
||||
TriangleEPA* face3 = NULL;
|
||||
TriangleEPA* face0 = null;
|
||||
TriangleEPA* face1 = null;
|
||||
TriangleEPA* face2 = null;
|
||||
TriangleEPA* face3 = null;
|
||||
// If the origin is in the first tetrahedron
|
||||
if (isOriginInTetrahedron(points[0], points[1],
|
||||
points[2], points[3]) == 0) {
|
||||
@ -242,9 +244,14 @@ void EPAAlgorithm::computePenetrationDepthAndContactPoints(const Simplex& simple
|
||||
return;
|
||||
}
|
||||
// If the constructed tetrahedron is not correct
|
||||
if (!((face0 != NULL) && (face1 != NULL) && (face2 != NULL) && (face3 != NULL)
|
||||
&& face0->getDistSquare() > 0.0 && face1->getDistSquare() > 0.0
|
||||
&& face2->getDistSquare() > 0.0 && face3->getDistSquare() > 0.0)) {
|
||||
if (!( face0 != null
|
||||
&& face1 != null
|
||||
&& face2 != null
|
||||
&& face3 != null
|
||||
&& face0->getDistSquare() > 0.0
|
||||
&& face1->getDistSquare() > 0.0
|
||||
&& face2->getDistSquare() > 0.0
|
||||
&& face3->getDistSquare() > 0.0) ) {
|
||||
return;
|
||||
}
|
||||
// Associate the edges of neighbouring triangle faces
|
||||
@ -255,26 +262,28 @@ void EPAAlgorithm::computePenetrationDepthAndContactPoints(const Simplex& simple
|
||||
link(EdgeEPA(face1, 1), EdgeEPA(face3, 0));
|
||||
link(EdgeEPA(face2, 1), EdgeEPA(face3, 1));
|
||||
// Add the triangle faces in the candidate heap
|
||||
addFaceCandidate(face0, triangleHeap, nbTriangles, FLT_MAX);
|
||||
addFaceCandidate(face1, triangleHeap, nbTriangles, FLT_MAX);
|
||||
addFaceCandidate(face2, triangleHeap, nbTriangles, FLT_MAX);
|
||||
addFaceCandidate(face3, triangleHeap, nbTriangles, FLT_MAX);
|
||||
addFaceCandidate(face0, triangleHeap, FLT_MAX);
|
||||
addFaceCandidate(face1, triangleHeap, FLT_MAX);
|
||||
addFaceCandidate(face2, triangleHeap, FLT_MAX);
|
||||
addFaceCandidate(face3, triangleHeap, FLT_MAX);
|
||||
nbVertices = 4;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// At this point, we have a polytope that contains the origin. Therefore, we
|
||||
// can run the EPA algorithm.
|
||||
if (nbTriangles == 0) {
|
||||
if (triangleHeap.size() == 0) {
|
||||
return;
|
||||
}
|
||||
TriangleEPA* triangle = 0;
|
||||
float upperBoundSquarePenDepth = FLT_MAX;
|
||||
do {
|
||||
triangle = triangleHeap[0];
|
||||
// Get the next candidate face (the face closest to the origin)
|
||||
std::pop_heap(&triangleHeap[0], &triangleHeap[nbTriangles], m_triangleComparison);
|
||||
nbTriangles--;
|
||||
triangleHeap.popFront();
|
||||
EPHY_INFO("rm from heap:");
|
||||
for (size_t iii=0; iii<triangleHeap.size(); ++iii) {
|
||||
EPHY_INFO(" [" << iii << "] " << triangleHeap[iii]->getDistSquare());
|
||||
}
|
||||
// If the candidate face in the heap is not obsolete
|
||||
if (!triangle->getIsObsolete()) {
|
||||
// If we have reached the maximum number of support points
|
||||
@ -284,17 +293,21 @@ void EPAAlgorithm::computePenetrationDepthAndContactPoints(const Simplex& simple
|
||||
}
|
||||
// Compute the support point of the Minkowski
|
||||
// difference (A-B) in the closest point direction
|
||||
suppPointsA[nbVertices] = shape1->getLocalSupportPointWithMargin(
|
||||
triangle->getClosestPoint(), shape1CachedCollisionData);
|
||||
suppPointsB[nbVertices] = body2Tobody1 *
|
||||
shape2->getLocalSupportPointWithMargin(rotateToBody2 *
|
||||
(-triangle->getClosestPoint()), shape2CachedCollisionData);
|
||||
suppPointsA[nbVertices] = shape1->getLocalSupportPointWithMargin(triangle->getClosestPoint(), shape1CachedCollisionData);
|
||||
suppPointsB[nbVertices] = body2Tobody1 * shape2->getLocalSupportPointWithMargin(rotateToBody2 * (-triangle->getClosestPoint()), shape2CachedCollisionData);
|
||||
points[nbVertices] = suppPointsA[nbVertices] - suppPointsB[nbVertices];
|
||||
int32_t indexNewVertex = nbVertices;
|
||||
nbVertices++;
|
||||
// Update the upper bound of the penetration depth
|
||||
float wDotv = points[indexNewVertex].dot(triangle->getClosestPoint());
|
||||
assert(wDotv > 0.0);
|
||||
EPHY_INFO(" point=" << points[indexNewVertex]);
|
||||
EPHY_INFO("close point=" << triangle->getClosestPoint());
|
||||
EPHY_INFO(" ==>" << wDotv);
|
||||
if (wDotv < 0.0) {
|
||||
EPHY_ERROR("depth penetration error " << wDotv);
|
||||
continue;
|
||||
}
|
||||
EPHY_ASSERT(wDotv >= 0.0, "depth penetration error " << wDotv);
|
||||
float wDotVSquare = wDotv * wDotv / triangle->getDistSquare();
|
||||
if (wDotVSquare < upperBoundSquarePenDepth) {
|
||||
upperBoundSquarePenDepth = wDotVSquare;
|
||||
@ -310,7 +323,7 @@ void EPAAlgorithm::computePenetrationDepthAndContactPoints(const Simplex& simple
|
||||
// Now, we compute the silhouette cast by the new vertex. The current triangle
|
||||
// face will not be in the convex hull. We start the local recursive silhouette
|
||||
// algorithm from the current triangle face.
|
||||
int32_t i = triangleStore.getNbTriangles();
|
||||
size_t i = triangleStore.getNbTriangles();
|
||||
if (!triangle->computeSilhouette(points, indexNewVertex, triangleStore)) {
|
||||
break;
|
||||
}
|
||||
@ -318,22 +331,23 @@ void EPAAlgorithm::computePenetrationDepthAndContactPoints(const Simplex& simple
|
||||
// to the candidates list of faces of the current polytope
|
||||
while(i != triangleStore.getNbTriangles()) {
|
||||
TriangleEPA* newTriangle = &triangleStore[i];
|
||||
addFaceCandidate(newTriangle, triangleHeap, nbTriangles, upperBoundSquarePenDepth);
|
||||
addFaceCandidate(newTriangle, triangleHeap, upperBoundSquarePenDepth);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
} while(nbTriangles > 0 && triangleHeap[0]->getDistSquare() <= upperBoundSquarePenDepth);
|
||||
} while( triangleHeap.size() > 0
|
||||
&& triangleHeap[0]->getDistSquare() <= upperBoundSquarePenDepth);
|
||||
// Compute the contact info
|
||||
v = transform1.getOrientation() * triangle->getClosestPoint();
|
||||
_vector = _transform1.getOrientation() * triangle->getClosestPoint();
|
||||
vec3 pALocal = triangle->computeClosestPointOfObject(suppPointsA);
|
||||
vec3 pBLocal = body2Tobody1.getInverse() * triangle->computeClosestPointOfObject(suppPointsB);
|
||||
vec3 normal = v.safeNormalized();
|
||||
float penetrationDepth = v.length();
|
||||
assert(penetrationDepth > 0.0);
|
||||
vec3 normal = _vector.safeNormalized();
|
||||
float penetrationDepth = _vector.length();
|
||||
EPHY_ASSERT(penetrationDepth >= 0.0, "penetration depth <0");
|
||||
if (normal.length2() < FLT_EPSILON) {
|
||||
return;
|
||||
}
|
||||
// Create the contact info object
|
||||
ContactPointInfo contactInfo(shape1Info.proxyShape, shape2Info.proxyShape, shape1Info.collisionShape, shape2Info.collisionShape, normal, penetrationDepth, pALocal, pBLocal);
|
||||
narrowPhaseCallback->notifyContact(shape1Info.overlappingPair, contactInfo);
|
||||
ContactPointInfo contactInfo(_shape1Info.proxyShape, _shape2Info.proxyShape, _shape1Info.collisionShape, _shape2Info.collisionShape, normal, penetrationDepth, pALocal, pBLocal);
|
||||
narrowPhaseCallback->notifyContact(_shape1Info.overlappingPair, contactInfo);
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
#include <ephysics/collision/narrowphase/GJK/Simplex.hpp>
|
||||
@ -11,29 +14,14 @@
|
||||
#include <ephysics/collision/narrowphase/NarrowPhaseAlgorithm.hpp>
|
||||
#include <ephysics/mathematics/mathematics.hpp>
|
||||
#include <ephysics/collision/narrowphase/EPA/TriangleEPA.hpp>
|
||||
#include <algorithm>
|
||||
#include <ephysics/debug.hpp>
|
||||
#include <etk/Set.hpp>
|
||||
|
||||
namespace ephysics {
|
||||
/// Maximum number of support points of the polytope
|
||||
const uint32_t MAX_SUPPORT_POINTS = 100;
|
||||
/// Maximum number of facets of the polytope
|
||||
const uint32_t MAX_FACETS = 200;
|
||||
/**
|
||||
* @brief Class TriangleComparison
|
||||
* This class allows the comparison of two triangles in the heap
|
||||
* The comparison between two triangles is made using their square distance to the closest
|
||||
* point to the origin. The goal is that in the heap, the first triangle is the one with the
|
||||
* smallest square distance.
|
||||
*/
|
||||
class TriangleComparison {
|
||||
public:
|
||||
/**
|
||||
* @brief Comparison operator
|
||||
*/
|
||||
bool operator()(const TriangleEPA* face1, const TriangleEPA* face2) {
|
||||
return (face1->getDistSquare() > face2->getDistSquare());
|
||||
}
|
||||
};
|
||||
/**
|
||||
* @brief Class EPAAlgorithm
|
||||
* This class is the implementation of the Expanding Polytope Algorithm (EPA).
|
||||
@ -50,15 +38,13 @@ namespace ephysics {
|
||||
*/
|
||||
class EPAAlgorithm {
|
||||
private:
|
||||
TriangleComparison m_triangleComparison; //!< Triangle comparison operator
|
||||
/// Private copy-constructor
|
||||
EPAAlgorithm(const EPAAlgorithm& _algorithm);
|
||||
/// Private assignment operator
|
||||
EPAAlgorithm& operator=(const EPAAlgorithm& _algorithm);
|
||||
/// Add a triangle face in the candidate triangle heap
|
||||
void addFaceCandidate(TriangleEPA* _triangle,
|
||||
TriangleEPA** _heap,
|
||||
uint32_t& _nbTriangles,
|
||||
etk::Set<TriangleEPA*>& _heap,
|
||||
float _upperBoundSquarePenDepth) {
|
||||
// If the closest point of the affine hull of triangle
|
||||
// points is int32_ternal to the triangle and if the distance
|
||||
@ -67,9 +53,11 @@ namespace ephysics {
|
||||
if ( _triangle->isClosestPointInternalToTriangle()
|
||||
&& _triangle->getDistSquare() <= _upperBoundSquarePenDepth) {
|
||||
// Add the triangle face to the list of candidates
|
||||
_heap[_nbTriangles] = _triangle;
|
||||
_nbTriangles++;
|
||||
std::push_heap(&_heap[0], &_heap[_nbTriangles], m_triangleComparison);
|
||||
_heap.add(_triangle);
|
||||
EPHY_INFO("add in heap:");
|
||||
for (size_t iii=0; iii<_heap.size(); ++iii) {
|
||||
EPHY_INFO(" [" << iii << "] " << _heap[iii]->getDistSquare());
|
||||
}
|
||||
}
|
||||
}
|
||||
// Decide if the origin is in the tetrahedron.
|
||||
|
@ -1,11 +1,15 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#include <ephysics/collision/narrowphase/EPA/EdgeEPA.hpp>
|
||||
#include <ephysics/collision/narrowphase/EPA/TriangleEPA.hpp>
|
||||
#include <ephysics/collision/narrowphase/EPA/TrianglesStore.hpp>
|
||||
#include <etk/types.hpp>
|
||||
|
||||
using namespace ephysics;
|
||||
|
||||
@ -14,18 +18,22 @@ EdgeEPA::EdgeEPA() {
|
||||
|
||||
}
|
||||
|
||||
EdgeEPA::EdgeEPA(TriangleEPA* ownerTriangle, int32_t index)
|
||||
: m_ownerTriangle(ownerTriangle), m_index(index) {
|
||||
EdgeEPA::EdgeEPA(TriangleEPA* ownerTriangle, int32_t index):
|
||||
m_ownerTriangle(ownerTriangle),
|
||||
m_index(index) {
|
||||
assert(index >= 0 && index < 3);
|
||||
}
|
||||
|
||||
EdgeEPA::EdgeEPA(const EdgeEPA& edge) {
|
||||
m_ownerTriangle = edge.m_ownerTriangle;
|
||||
m_index = edge.m_index;
|
||||
EdgeEPA::EdgeEPA(const EdgeEPA& _obj):
|
||||
m_ownerTriangle(_obj.m_ownerTriangle),
|
||||
m_index(_obj.m_index) {
|
||||
|
||||
}
|
||||
|
||||
EdgeEPA::~EdgeEPA() {
|
||||
|
||||
EdgeEPA::EdgeEPA(EdgeEPA&& _obj):
|
||||
m_ownerTriangle(null) {
|
||||
etk::swap(m_ownerTriangle, _obj.m_ownerTriangle);
|
||||
etk::swap(m_index, _obj.m_index);
|
||||
}
|
||||
|
||||
uint32_t EdgeEPA::getSourceVertexIndex() const {
|
||||
@ -36,17 +44,17 @@ uint32_t EdgeEPA::getTargetVertexIndex() const {
|
||||
return (*m_ownerTriangle)[indexOfNextCounterClockwiseEdge(m_index)];
|
||||
}
|
||||
|
||||
bool EdgeEPA::computeSilhouette(const vec3* vertices, uint32_t indexNewVertex,
|
||||
TrianglesStore& triangleStore) {
|
||||
bool EdgeEPA::computeSilhouette(const vec3* _vertices, uint32_t _indexNewVertex,
|
||||
TrianglesStore& _triangleStore) {
|
||||
// If the edge has not already been visited
|
||||
if (!m_ownerTriangle->getIsObsolete()) {
|
||||
// If the triangle of this edge is not visible from the given point
|
||||
if (!m_ownerTriangle->isVisibleFromVertex(vertices, indexNewVertex)) {
|
||||
TriangleEPA* triangle = triangleStore.newTriangle(vertices, indexNewVertex,
|
||||
if (!m_ownerTriangle->isVisibleFromVertex(_vertices, _indexNewVertex)) {
|
||||
TriangleEPA* triangle = _triangleStore.newTriangle(_vertices, _indexNewVertex,
|
||||
getTargetVertexIndex(),
|
||||
getSourceVertexIndex());
|
||||
// If the triangle has been created
|
||||
if (triangle != nullptr) {
|
||||
if (triangle != null) {
|
||||
halfLink(EdgeEPA(triangle, 1), *this);
|
||||
return true;
|
||||
}
|
||||
@ -54,28 +62,26 @@ bool EdgeEPA::computeSilhouette(const vec3* vertices, uint32_t indexNewVertex,
|
||||
} else {
|
||||
// The current triangle is visible and therefore obsolete
|
||||
m_ownerTriangle->setIsObsolete(true);
|
||||
int32_t backup = triangleStore.getNbTriangles();
|
||||
if(!m_ownerTriangle->getAdjacentEdge(indexOfNextCounterClockwiseEdge(
|
||||
this->m_index)).computeSilhouette(vertices,
|
||||
indexNewVertex,
|
||||
triangleStore)) {
|
||||
int32_t backup = _triangleStore.getNbTriangles();
|
||||
if(!m_ownerTriangle->getAdjacentEdge(indexOfNextCounterClockwiseEdge(this->m_index)).computeSilhouette(_vertices,
|
||||
_indexNewVertex,
|
||||
_triangleStore)) {
|
||||
m_ownerTriangle->setIsObsolete(false);
|
||||
TriangleEPA* triangle = triangleStore.newTriangle(vertices, indexNewVertex,
|
||||
TriangleEPA* triangle = _triangleStore.newTriangle(_vertices, _indexNewVertex,
|
||||
getTargetVertexIndex(),
|
||||
getSourceVertexIndex());
|
||||
// If the triangle has been created
|
||||
if (triangle != nullptr) {
|
||||
if (triangle != null) {
|
||||
halfLink(EdgeEPA(triangle, 1), *this);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} else if (!m_ownerTriangle->getAdjacentEdge(indexOfPreviousCounterClockwiseEdge(
|
||||
this->m_index)).computeSilhouette(vertices,
|
||||
indexNewVertex,
|
||||
triangleStore)) {
|
||||
} else if (!m_ownerTriangle->getAdjacentEdge(indexOfPreviousCounterClockwiseEdge(this->m_index)).computeSilhouette(_vertices,
|
||||
_indexNewVertex,
|
||||
_triangleStore)) {
|
||||
m_ownerTriangle->setIsObsolete(false);
|
||||
triangleStore.setNbTriangles(backup);
|
||||
TriangleEPA* triangle = triangleStore.newTriangle(vertices, indexNewVertex,
|
||||
_triangleStore.resize(backup);
|
||||
TriangleEPA* triangle = _triangleStore.newTriangle(_vertices, _indexNewVertex,
|
||||
getTargetVertexIndex(),
|
||||
getSourceVertexIndex());
|
||||
if (triangle != NULL) {
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
#include <ephysics/mathematics/mathematics.hpp>
|
||||
@ -26,9 +29,9 @@ class EdgeEPA {
|
||||
/// Constructor
|
||||
EdgeEPA(TriangleEPA* ownerTriangle, int32_t index);
|
||||
/// Copy-constructor
|
||||
EdgeEPA(const EdgeEPA& edge);
|
||||
/// Destructor
|
||||
~EdgeEPA();
|
||||
EdgeEPA(const EdgeEPA& _obj);
|
||||
/// Move-constructor
|
||||
EdgeEPA(EdgeEPA&& _obj);
|
||||
/// Return the pointer to the owner triangle
|
||||
TriangleEPA* getOwnerTriangle() const {
|
||||
return m_ownerTriangle;
|
||||
@ -44,9 +47,15 @@ class EdgeEPA {
|
||||
/// Execute the recursive silhouette algorithm from this edge
|
||||
bool computeSilhouette(const vec3* vertices, uint32_t index, TrianglesStore& triangleStore);
|
||||
/// Assignment operator
|
||||
EdgeEPA& operator=(const EdgeEPA& edge) {
|
||||
m_ownerTriangle = edge.m_ownerTriangle;
|
||||
m_index = edge.m_index;
|
||||
EdgeEPA& operator=(const EdgeEPA& _obj) {
|
||||
m_ownerTriangle = _obj.m_ownerTriangle;
|
||||
m_index = _obj.m_index;
|
||||
return *this;
|
||||
}
|
||||
/// Move operator
|
||||
EdgeEPA& operator=(EdgeEPA&& _obj) {
|
||||
etk::swap(m_ownerTriangle, _obj.m_ownerTriangle);
|
||||
etk::swap(m_index, _obj.m_index);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
@ -1,9 +1,11 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <ephysics/collision/narrowphase/EPA/TriangleEPA.hpp>
|
||||
#include <ephysics/collision/narrowphase/EPA/EdgeEPA.hpp>
|
||||
#include <ephysics/collision/narrowphase/EPA/TrianglesStore.hpp>
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
/** @file
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
#include <ephysics/mathematics/mathematics.hpp>
|
||||
@ -24,11 +27,38 @@ namespace ephysics {
|
||||
float m_lambda1; //!< Lambda1 value such that v = lambda0 * y_0 + lambda1 * y_1 + lambda2 * y_2
|
||||
float m_lambda2; //!< Lambda1 value such that v = lambda0 * y_0 + lambda1 * y_1 + lambda2 * y_2
|
||||
float m_distSquare; //!< Square distance of the point closest point v to the origin
|
||||
/// Private copy-constructor
|
||||
TriangleEPA(const TriangleEPA& _triangle);
|
||||
/// Private assignment operator
|
||||
TriangleEPA& operator=(const TriangleEPA& _triangle);
|
||||
public:
|
||||
/// Private copy-constructor
|
||||
TriangleEPA(const TriangleEPA& _triangle) {
|
||||
m_indicesVertices[0] = _triangle.m_indicesVertices[0];
|
||||
m_indicesVertices[1] = _triangle.m_indicesVertices[1];
|
||||
m_indicesVertices[2] = _triangle.m_indicesVertices[2];
|
||||
m_adjacentEdges[0] = _triangle.m_adjacentEdges[0];
|
||||
m_adjacentEdges[1] = _triangle.m_adjacentEdges[1];
|
||||
m_adjacentEdges[2] = _triangle.m_adjacentEdges[2];
|
||||
m_isObsolete = _triangle.m_isObsolete;
|
||||
m_determinant = _triangle.m_determinant;
|
||||
m_closestPoint = _triangle.m_closestPoint;
|
||||
m_lambda1 = _triangle.m_lambda1;
|
||||
m_lambda2 = _triangle.m_lambda2;
|
||||
m_distSquare = _triangle.m_distSquare;
|
||||
}
|
||||
/// Private assignment operator
|
||||
TriangleEPA& operator=(const TriangleEPA& _triangle) {
|
||||
m_indicesVertices[0] = _triangle.m_indicesVertices[0];
|
||||
m_indicesVertices[1] = _triangle.m_indicesVertices[1];
|
||||
m_indicesVertices[2] = _triangle.m_indicesVertices[2];
|
||||
m_adjacentEdges[0] = _triangle.m_adjacentEdges[0];
|
||||
m_adjacentEdges[1] = _triangle.m_adjacentEdges[1];
|
||||
m_adjacentEdges[2] = _triangle.m_adjacentEdges[2];
|
||||
m_isObsolete = _triangle.m_isObsolete;
|
||||
m_determinant = _triangle.m_determinant;
|
||||
m_closestPoint = _triangle.m_closestPoint;
|
||||
m_lambda1 = _triangle.m_lambda1;
|
||||
m_lambda2 = _triangle.m_lambda2;
|
||||
m_distSquare = _triangle.m_distSquare;
|
||||
return *this;
|
||||
}
|
||||
/// Constructor
|
||||
TriangleEPA();
|
||||
/// Constructor
|
||||
|
@ -1,15 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <ephysics/collision/narrowphase/EPA/TrianglesStore.hpp>
|
||||
|
||||
ephysics::TrianglesStore::TrianglesStore() : m_numberTriangles(0) {
|
||||
|
||||
}
|
||||
|
||||
ephysics::TrianglesStore::~TrianglesStore() {
|
||||
|
||||
}
|
||||
|
@ -1,10 +1,16 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
#include <ephysics/collision/narrowphase/EPA/TriangleEPA.hpp>
|
||||
#include <ephysics/debug.hpp>
|
||||
#include <etk/Array.hpp>
|
||||
|
||||
namespace ephysics {
|
||||
const uint32_t MAX_TRIANGLES = 200; // Maximum number of triangles
|
||||
/**
|
||||
@ -12,48 +18,46 @@ namespace ephysics {
|
||||
*/
|
||||
class TrianglesStore {
|
||||
private:
|
||||
TriangleEPA m_triangles[MAX_TRIANGLES]; //!< Triangles
|
||||
int32_t m_numberTriangles; //!< Number of triangles
|
||||
etk::Array<TriangleEPA, MAX_TRIANGLES> m_triangles; //!< Triangles
|
||||
/// Private copy-constructor
|
||||
TrianglesStore(const TrianglesStore& triangleStore);
|
||||
TrianglesStore(const TrianglesStore& triangleStore) = delete;
|
||||
/// Private assignment operator
|
||||
TrianglesStore& operator=(const TrianglesStore& triangleStore);
|
||||
TrianglesStore& operator=(const TrianglesStore& triangleStore) = delete;
|
||||
public:
|
||||
/// Constructor
|
||||
TrianglesStore();
|
||||
/// Destructor
|
||||
~TrianglesStore();
|
||||
TrianglesStore() = default;
|
||||
/// Clear all the storage
|
||||
void clear() {
|
||||
m_numberTriangles = 0;
|
||||
m_triangles.clear();
|
||||
}
|
||||
/// Return the number of triangles
|
||||
int32_t getNbTriangles() const {
|
||||
return m_numberTriangles;
|
||||
size_t getNbTriangles() const {
|
||||
return m_triangles.size();
|
||||
}
|
||||
/// Set the number of triangles
|
||||
void setNbTriangles(int32_t _backup) {
|
||||
m_numberTriangles = _backup;
|
||||
void resize(int32_t _backup) {
|
||||
if (_backup > m_triangles.size()) {
|
||||
EPHY_ERROR("RESIZE BIGGER : " << _backup << " > " << m_triangles.size());
|
||||
}
|
||||
m_triangles.resize(_backup);
|
||||
}
|
||||
/// Return the last triangle
|
||||
TriangleEPA& last() {
|
||||
assert(m_numberTriangles > 0);
|
||||
return m_triangles[m_numberTriangles - 1];
|
||||
return m_triangles.back();
|
||||
}
|
||||
/// Create a new triangle
|
||||
TriangleEPA* newTriangle(const vec3* _vertices, uint32_t _v0, uint32_t _v1, uint32_t _v2) {
|
||||
TriangleEPA* newTriangle = nullptr;
|
||||
// If we have not reached the maximum number of triangles
|
||||
if (m_numberTriangles != MAX_TRIANGLES) {
|
||||
newTriangle = &m_triangles[m_numberTriangles++];
|
||||
newTriangle->set(_v0, _v1, _v2);
|
||||
if (!newTriangle->computeClosestPoint(_vertices)) {
|
||||
m_numberTriangles--;
|
||||
newTriangle = nullptr;
|
||||
if (m_triangles.size() < MAX_TRIANGLES) {
|
||||
TriangleEPA tmp(_v0, _v1, _v2);
|
||||
if (!tmp.computeClosestPoint(_vertices)) {
|
||||
return null;
|
||||
}
|
||||
m_triangles.pushBack(etk::move(tmp));
|
||||
return &m_triangles.back();
|
||||
}
|
||||
// Return the new triangle
|
||||
return newTriangle;
|
||||
// We are at the limit (internal)
|
||||
return null;
|
||||
}
|
||||
/// Access operator
|
||||
TriangleEPA& operator[](int32_t _id) {
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#include <ephysics/collision/narrowphase/GJK/GJKAlgorithm.hpp>
|
||||
#include <ephysics/collision/narrowphase/GJK/Simplex.hpp>
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
@ -1,25 +1,19 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
// Libraries
|
||||
#include <ephysics/collision/narrowphase/GJK/Simplex.hpp>
|
||||
|
||||
// We want to use the ReactPhysics3D namespace
|
||||
using namespace ephysics;
|
||||
|
||||
// Constructor
|
||||
Simplex::Simplex() : mBitsCurrentSimplex(0x0), mAllBits(0x0) {
|
||||
|
||||
}
|
||||
|
||||
// Destructor
|
||||
Simplex::~Simplex() {
|
||||
|
||||
}
|
||||
|
||||
// Add a new support point of (A-B) int32_to the simplex
|
||||
/// suppPointA : support point of object A in a direction -v
|
||||
/// suppPointB : support point of object B in a direction v
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -103,9 +106,6 @@ class Simplex {
|
||||
/// Constructor
|
||||
Simplex();
|
||||
|
||||
/// Destructor
|
||||
~Simplex();
|
||||
|
||||
/// Return true if the simplex contains 4 points
|
||||
bool isFull() const;
|
||||
|
||||
|
@ -1,15 +1,17 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <ephysics/collision/narrowphase/NarrowPhaseAlgorithm.hpp>
|
||||
|
||||
using namespace ephysics;
|
||||
|
||||
NarrowPhaseAlgorithm::NarrowPhaseAlgorithm():
|
||||
m_currentOverlappingPair(nullptr) {
|
||||
m_currentOverlappingPair(null) {
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
@ -1,9 +1,11 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <ephysics/collision/narrowphase/SphereVsSphereAlgorithm.hpp>
|
||||
#include <ephysics/collision/shapes/SphereShape.hpp>
|
||||
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
@ -1,10 +1,12 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
|
||||
// Libraries
|
||||
#include <ephysics/collision/shapes/AABB.hpp>
|
||||
#include <ephysics/configuration.hpp>
|
||||
@ -149,13 +151,19 @@ void AABB::inflate(float _dx, float _dy, float _dz) {
|
||||
m_minCoordinates -= vec3(_dx, _dy, _dz);
|
||||
}
|
||||
|
||||
bool AABB::testCollision(const AABB& aabb) const {
|
||||
if (m_maxCoordinates.x() < aabb.m_minCoordinates.x() ||
|
||||
aabb.m_maxCoordinates.x() < m_minCoordinates.x()) return false;
|
||||
if (m_maxCoordinates.y() < aabb.m_minCoordinates.y() ||
|
||||
aabb.m_maxCoordinates.y() < m_minCoordinates.y()) return false;
|
||||
if (m_maxCoordinates.z() < aabb.m_minCoordinates.z()||
|
||||
aabb.m_maxCoordinates.z() < m_minCoordinates.z()) return false;
|
||||
bool AABB::testCollision(const AABB& _aabb) const {
|
||||
if ( m_maxCoordinates.x() < _aabb.m_minCoordinates.x()
|
||||
|| _aabb.m_maxCoordinates.x() < m_minCoordinates.x()) {
|
||||
return false;
|
||||
}
|
||||
if ( m_maxCoordinates.y() < _aabb.m_minCoordinates.y()
|
||||
|| _aabb.m_maxCoordinates.y() < m_minCoordinates.y()) {
|
||||
return false;
|
||||
}
|
||||
if ( m_maxCoordinates.z() < _aabb.m_minCoordinates.z()
|
||||
|| _aabb.m_maxCoordinates.z() < m_minCoordinates.z()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
#include <ephysics/mathematics/mathematics.hpp>
|
||||
|
@ -1,9 +1,11 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
// Libraries
|
||||
#include <ephysics/collision/shapes/BoxShape.hpp>
|
||||
#include <ephysics/collision/ProxyShape.hpp>
|
||||
@ -12,11 +14,6 @@
|
||||
|
||||
using namespace ephysics;
|
||||
|
||||
// Constructor
|
||||
/**
|
||||
* @param extent The vector with the three extents of the box (in meters)
|
||||
* @param margin The collision margin (in meters) around the collision shape
|
||||
*/
|
||||
BoxShape::BoxShape(const vec3& _extent, float _margin):
|
||||
ConvexShape(BOX, _margin),
|
||||
m_extent(_extent - vec3(_margin, _margin, _margin)) {
|
||||
@ -25,27 +22,19 @@ BoxShape::BoxShape(const vec3& _extent, float _margin):
|
||||
assert(_extent.z() > 0.0f && _extent.z() > _margin);
|
||||
}
|
||||
|
||||
// Return the local inertia tensor of the collision shape
|
||||
/**
|
||||
* @param[out] tensor The 3x3 inertia tensor matrix of the shape in local-space
|
||||
* coordinates
|
||||
* @param mass Mass to use to compute the inertia tensor of the collision shape
|
||||
*/
|
||||
void BoxShape::computeLocalInertiaTensor(etk::Matrix3x3& tensor, float mass) const {
|
||||
float factor = (1.0f / float(3.0)) * mass;
|
||||
void BoxShape::computeLocalInertiaTensor(etk::Matrix3x3& _tensor, float _mass) const {
|
||||
float factor = (1.0f / float(3.0)) * _mass;
|
||||
vec3 realExtent = m_extent + vec3(m_margin, m_margin, m_margin);
|
||||
float xSquare = realExtent.x() * realExtent.x();
|
||||
float ySquare = realExtent.y() * realExtent.y();
|
||||
float zSquare = realExtent.z() * realExtent.z();
|
||||
tensor.setValue(factor * (ySquare + zSquare), 0.0, 0.0,
|
||||
0.0, factor * (xSquare + zSquare), 0.0,
|
||||
0.0, 0.0, factor * (xSquare + ySquare));
|
||||
_tensor.setValue(factor * (ySquare + zSquare), 0.0, 0.0,
|
||||
0.0, factor * (xSquare + zSquare), 0.0,
|
||||
0.0, 0.0, factor * (xSquare + ySquare));
|
||||
}
|
||||
|
||||
// Raycast method with feedback information
|
||||
bool BoxShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const {
|
||||
|
||||
vec3 rayDirection = ray.point2 - ray.point1;
|
||||
bool BoxShape::raycast(const Ray& _ray, RaycastInfo& _raycastInfo, ProxyShape* _proxyShape) const {
|
||||
vec3 rayDirection = _ray.point2 - _ray.point1;
|
||||
float tMin = FLT_MIN;
|
||||
float tMax = FLT_MAX;
|
||||
vec3 normalDirection(0,0,0);
|
||||
@ -55,14 +44,14 @@ bool BoxShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* pro
|
||||
// If ray is parallel to the slab
|
||||
if (etk::abs(rayDirection[iii]) < FLT_EPSILON) {
|
||||
// If the ray's origin is not inside the slab, there is no hit
|
||||
if (ray.point1[iii] > m_extent[iii] || ray.point1[iii] < -m_extent[iii]) {
|
||||
if (_ray.point1[iii] > m_extent[iii] || _ray.point1[iii] < -m_extent[iii]) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Compute the intersection of the ray with the near and far plane of the slab
|
||||
float oneOverD = 1.0f / rayDirection[iii];
|
||||
float t1 = (-m_extent[iii] - ray.point1[iii]) * oneOverD;
|
||||
float t2 = (m_extent[iii] - ray.point1[iii]) * oneOverD;
|
||||
float t1 = (-m_extent[iii] - _ray.point1[iii]) * oneOverD;
|
||||
float t2 = (m_extent[iii] - _ray.point1[iii]) * oneOverD;
|
||||
currentNormal[0] = (iii == 0) ? -m_extent[iii] : 0.0f;
|
||||
currentNormal[1] = (iii == 1) ? -m_extent[iii] : 0.0f;
|
||||
currentNormal[2] = (iii == 2) ? -m_extent[iii] : 0.0f;
|
||||
@ -79,7 +68,7 @@ bool BoxShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* pro
|
||||
}
|
||||
tMax = etk::min(tMax, t2);
|
||||
// If tMin is larger than the maximum raycasting fraction, we return no hit
|
||||
if (tMin > ray.maxFraction) {
|
||||
if (tMin > _ray.maxFraction) {
|
||||
return false;
|
||||
}
|
||||
// If the slabs intersection is empty, there is no hit
|
||||
@ -90,71 +79,55 @@ bool BoxShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* pro
|
||||
}
|
||||
// If tMin is negative, we return no hit
|
||||
if ( tMin < 0.0f
|
||||
|| tMin > ray.maxFraction) {
|
||||
|| tMin > _ray.maxFraction) {
|
||||
return false;
|
||||
}
|
||||
if (normalDirection == vec3(0,0,0)) {
|
||||
return false;
|
||||
}
|
||||
// The ray int32_tersects the three slabs, we compute the hit point
|
||||
vec3 localHitPoint = ray.point1 + tMin * rayDirection;
|
||||
raycastInfo.body = proxyShape->getBody();
|
||||
raycastInfo.proxyShape = proxyShape;
|
||||
raycastInfo.hitFraction = tMin;
|
||||
raycastInfo.worldPoint = localHitPoint;
|
||||
raycastInfo.worldNormal = normalDirection;
|
||||
vec3 localHitPoint = _ray.point1 + tMin * rayDirection;
|
||||
_raycastInfo.body = _proxyShape->getBody();
|
||||
_raycastInfo.proxyShape = _proxyShape;
|
||||
_raycastInfo.hitFraction = tMin;
|
||||
_raycastInfo.worldPoint = localHitPoint;
|
||||
_raycastInfo.worldNormal = normalDirection;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return the extents of the box
|
||||
/**
|
||||
* @return The vector with the three extents of the box shape (in meters)
|
||||
*/
|
||||
vec3 BoxShape::getExtent() const {
|
||||
return m_extent + vec3(m_margin, m_margin, m_margin);
|
||||
}
|
||||
|
||||
// Set the scaling vector of the collision shape
|
||||
void BoxShape::setLocalScaling(const vec3& scaling) {
|
||||
|
||||
m_extent = (m_extent / m_scaling) * scaling;
|
||||
|
||||
CollisionShape::setLocalScaling(scaling);
|
||||
void BoxShape::setLocalScaling(const vec3& _scaling) {
|
||||
m_extent = (m_extent / m_scaling) * _scaling;
|
||||
CollisionShape::setLocalScaling(_scaling);
|
||||
}
|
||||
|
||||
// Return the local bounds of the shape in x, y and z directions
|
||||
/// This method is used to compute the AABB of the box
|
||||
/**
|
||||
* @param min The minimum bounds of the shape in local-space coordinates
|
||||
* @param max The maximum bounds of the shape in local-space coordinates
|
||||
*/
|
||||
void BoxShape::getLocalBounds(vec3& _min, vec3& _max) const {
|
||||
|
||||
// Maximum bounds
|
||||
_max = m_extent + vec3(m_margin, m_margin, m_margin);
|
||||
|
||||
// Minimum bounds
|
||||
_min = -_max;
|
||||
}
|
||||
|
||||
// Return the number of bytes used by the collision shape
|
||||
size_t BoxShape::getSizeInBytes() const {
|
||||
return sizeof(BoxShape);
|
||||
}
|
||||
|
||||
// Return a local support point in a given direction without the objec margin
|
||||
vec3 BoxShape::getLocalSupportPointWithoutMargin(const vec3& direction,
|
||||
void** cachedCollisionData) const {
|
||||
|
||||
return vec3(direction.x() < 0.0 ? -m_extent.x() : m_extent.x(),
|
||||
direction.y() < 0.0 ? -m_extent.y() : m_extent.y(),
|
||||
direction.z() < 0.0 ? -m_extent.z() : m_extent.z());
|
||||
vec3 BoxShape::getLocalSupportPointWithoutMargin(const vec3& _direction,
|
||||
void** _cachedCollisionData) const {
|
||||
return vec3(_direction.x() < 0.0 ? -m_extent.x() : m_extent.x(),
|
||||
_direction.y() < 0.0 ? -m_extent.y() : m_extent.y(),
|
||||
_direction.z() < 0.0 ? -m_extent.z() : m_extent.z());
|
||||
}
|
||||
|
||||
// Return true if a point is inside the collision shape
|
||||
bool BoxShape::testPointInside(const vec3& localPoint, ProxyShape* proxyShape) const {
|
||||
return (localPoint.x() < m_extent[0] && localPoint.x() > -m_extent[0] &&
|
||||
localPoint.y() < m_extent[1] && localPoint.y() > -m_extent[1] &&
|
||||
localPoint.z() < m_extent[2] && localPoint.z() > -m_extent[2]);
|
||||
bool BoxShape::testPointInside(const vec3& _localPoint, ProxyShape* _proxyShape) const {
|
||||
return ( _localPoint.x() < m_extent[0]
|
||||
&& _localPoint.x() > -m_extent[0]
|
||||
&& _localPoint.y() < m_extent[1]
|
||||
&& _localPoint.y() > -m_extent[1]
|
||||
&& _localPoint.z() < m_extent[2]
|
||||
&& _localPoint.z() > -m_extent[2]);
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -25,24 +28,31 @@ namespace ephysics {
|
||||
* default margin distance by not using the "margin" parameter in the constructor.
|
||||
*/
|
||||
class BoxShape : public ConvexShape {
|
||||
protected :
|
||||
vec3 m_extent; //!< Extent sizes of the box in the x, y and z direction
|
||||
/// Private copy-constructor
|
||||
BoxShape(const BoxShape& _shape) = delete;
|
||||
/// Private assignment operator
|
||||
BoxShape& operator=(const BoxShape& _shape) = delete;
|
||||
vec3 getLocalSupportPointWithoutMargin(const vec3& _direction, void** _cachedCollisionData) const override;
|
||||
bool testPointInside(const vec3& _localPoint, ProxyShape* _proxyShape) const override;
|
||||
bool raycast(const Ray& _ray, RaycastInfo& _raycastInfo, ProxyShape* _proxyShape) const override;
|
||||
size_t getSizeInBytes() const override;
|
||||
public :
|
||||
/// Constructor
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param extent The vector with the three extents of the box (in meters)
|
||||
* @param margin The collision margin (in meters) around the collision shape
|
||||
*/
|
||||
BoxShape(const vec3& _extent, float _margin = OBJECT_MARGIN);
|
||||
/// Return the extents of the box
|
||||
/// DELETE copy-constructor
|
||||
BoxShape(const BoxShape& _shape) = delete;
|
||||
/// DELETE assignment operator
|
||||
BoxShape& operator=(const BoxShape& _shape) = delete;
|
||||
/**
|
||||
* @brief Return the extents of the box
|
||||
* @return The vector with the three extents of the box shape (in meters)
|
||||
*/
|
||||
vec3 getExtent() const;
|
||||
void setLocalScaling(const vec3& _scaling) override;
|
||||
void getLocalBounds(vec3& _min, vec3& _max) const override;
|
||||
void computeLocalInertiaTensor(etk::Matrix3x3& _tensor, float _mass) const override;
|
||||
protected:
|
||||
vec3 m_extent; //!< Extent sizes of the box in the x, y and z direction
|
||||
vec3 getLocalSupportPointWithoutMargin(const vec3& _direction, void** _cachedCollisionData) const override;
|
||||
bool testPointInside(const vec3& _localPoint, ProxyShape* _proxyShape) const override;
|
||||
bool raycast(const Ray& _ray, RaycastInfo& _raycastInfo, ProxyShape* _proxyShape) const override;
|
||||
size_t getSizeInBytes() const override;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -1,21 +1,17 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
// Libraries
|
||||
#include <ephysics/collision/shapes/CapsuleShape.hpp>
|
||||
#include <ephysics/collision/ProxyShape.hpp>
|
||||
#include <ephysics/configuration.hpp>
|
||||
|
||||
using namespace ephysics;
|
||||
|
||||
// Constructor
|
||||
/**
|
||||
* @param _radius The radius of the capsule (in meters)
|
||||
* @param _height The height of the capsule (in meters)
|
||||
*/
|
||||
CapsuleShape::CapsuleShape(float _radius, float _height):
|
||||
ConvexShape(CAPSULE, _radius),
|
||||
m_halfHeight(_height * 0.5f) {
|
||||
@ -23,21 +19,8 @@ CapsuleShape::CapsuleShape(float _radius, float _height):
|
||||
assert(_height > 0.0f);
|
||||
}
|
||||
|
||||
// Destructor
|
||||
CapsuleShape::~CapsuleShape() {
|
||||
|
||||
}
|
||||
|
||||
// Return the local inertia tensor of the capsule
|
||||
/**
|
||||
* @param[out] tensor The 3x3 inertia tensor matrix of the shape in local-space
|
||||
* coordinates
|
||||
* @param mass Mass to use to compute the inertia tensor of the collision shape
|
||||
*/
|
||||
void CapsuleShape::computeLocalInertiaTensor(etk::Matrix3x3& tensor, float mass) const {
|
||||
|
||||
void CapsuleShape::computeLocalInertiaTensor(etk::Matrix3x3& _tensor, float _mass) const {
|
||||
// The inertia tensor formula for a capsule can be found in : Game Engine Gems, Volume 1
|
||||
|
||||
float height = m_halfHeight + m_halfHeight;
|
||||
float radiusSquare = m_margin * m_margin;
|
||||
float heightSquare = height * height;
|
||||
@ -47,292 +30,231 @@ void CapsuleShape::computeLocalInertiaTensor(etk::Matrix3x3& tensor, float mass)
|
||||
float sum1 = float(0.4) * radiusSquareDouble;
|
||||
float sum2 = float(0.75) * height * m_margin + 0.5f * heightSquare;
|
||||
float sum3 = float(0.25) * radiusSquare + float(1.0 / 12.0) * heightSquare;
|
||||
float IxxAndzz = factor1 * mass * (sum1 + sum2) + factor2 * mass * sum3;
|
||||
float Iyy = factor1 * mass * sum1 + factor2 * mass * float(0.25) * radiusSquareDouble;
|
||||
tensor.setValue(IxxAndzz, 0.0, 0.0,
|
||||
0.0, Iyy, 0.0,
|
||||
0.0, 0.0, IxxAndzz);
|
||||
float IxxAndzz = factor1 * _mass * (sum1 + sum2) + factor2 * _mass * sum3;
|
||||
float Iyy = factor1 * _mass * sum1 + factor2 * _mass * float(0.25) * radiusSquareDouble;
|
||||
_tensor.setValue(IxxAndzz, 0.0, 0.0,
|
||||
0.0, Iyy, 0.0,
|
||||
0.0, 0.0, IxxAndzz);
|
||||
}
|
||||
|
||||
// Return true if a point is inside the collision shape
|
||||
bool CapsuleShape::testPointInside(const vec3& localPoint, ProxyShape* proxyShape) const {
|
||||
|
||||
const float diffYCenterSphere1 = localPoint.y() - m_halfHeight;
|
||||
const float diffYCenterSphere2 = localPoint.y() + m_halfHeight;
|
||||
const float xSquare = localPoint.x() * localPoint.x();
|
||||
const float zSquare = localPoint.z() * localPoint.z();
|
||||
bool CapsuleShape::testPointInside(const vec3& _localPoint, ProxyShape* _proxyShape) const {
|
||||
const float diffYCenterSphere1 = _localPoint.y() - m_halfHeight;
|
||||
const float diffYCenterSphere2 = _localPoint.y() + m_halfHeight;
|
||||
const float xSquare = _localPoint.x() * _localPoint.x();
|
||||
const float zSquare = _localPoint.z() * _localPoint.z();
|
||||
const float squareRadius = m_margin * m_margin;
|
||||
|
||||
// Return true if the point is inside the cylinder or one of the two spheres of the capsule
|
||||
return ((xSquare + zSquare) < squareRadius &&
|
||||
localPoint.y() < m_halfHeight && localPoint.y() > -m_halfHeight) ||
|
||||
_localPoint.y() < m_halfHeight && _localPoint.y() > -m_halfHeight) ||
|
||||
(xSquare + zSquare + diffYCenterSphere1 * diffYCenterSphere1) < squareRadius ||
|
||||
(xSquare + zSquare + diffYCenterSphere2 * diffYCenterSphere2) < squareRadius;
|
||||
}
|
||||
|
||||
// Raycast method with feedback information
|
||||
bool CapsuleShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const {
|
||||
|
||||
const vec3 n = ray.point2 - ray.point1;
|
||||
|
||||
bool CapsuleShape::raycast(const Ray& _ray, RaycastInfo& _raycastInfo, ProxyShape* _proxyShape) const {
|
||||
const vec3 n = _ray.point2 - _ray.point1;
|
||||
const float epsilon = float(0.01);
|
||||
vec3 p(float(0), -m_halfHeight, float(0));
|
||||
vec3 q(float(0), m_halfHeight, float(0));
|
||||
vec3 d = q - p;
|
||||
vec3 m = ray.point1 - p;
|
||||
vec3 m = _ray.point1 - p;
|
||||
float t;
|
||||
|
||||
float mDotD = m.dot(d);
|
||||
float nDotD = n.dot(d);
|
||||
float dDotD = d.dot(d);
|
||||
|
||||
// Test if the segment is outside the cylinder
|
||||
float vec1DotD = (ray.point1 - vec3(0.0f, -m_halfHeight - m_margin, float(0.0))).dot(d);
|
||||
if (vec1DotD < 0.0f && vec1DotD + nDotD < float(0.0)) return false;
|
||||
float vec1DotD = (_ray.point1 - vec3(0.0f, -m_halfHeight - m_margin, float(0.0))).dot(d);
|
||||
if ( vec1DotD < 0.0f
|
||||
&& vec1DotD + nDotD < float(0.0)) {
|
||||
return false;
|
||||
}
|
||||
float ddotDExtraCaps = float(2.0) * m_margin * d.y();
|
||||
if (vec1DotD > dDotD + ddotDExtraCaps && vec1DotD + nDotD > dDotD + ddotDExtraCaps) return false;
|
||||
|
||||
if ( vec1DotD > dDotD + ddotDExtraCaps
|
||||
&& vec1DotD + nDotD > dDotD + ddotDExtraCaps) {
|
||||
return false;
|
||||
}
|
||||
float nDotN = n.dot(n);
|
||||
float mDotN = m.dot(n);
|
||||
|
||||
float a = dDotD * nDotN - nDotD * nDotD;
|
||||
float k = m.dot(m) - m_margin * m_margin;
|
||||
float c = dDotD * k - mDotD * mDotD;
|
||||
|
||||
// If the ray is parallel to the capsule axis
|
||||
if (etk::abs(a) < epsilon) {
|
||||
|
||||
// If the origin is outside the surface of the capusle's cylinder, we return no hit
|
||||
if (c > 0.0f) return false;
|
||||
|
||||
if (c > 0.0f) {
|
||||
return false;
|
||||
}
|
||||
// Here we know that the segment int32_tersect an endcap of the capsule
|
||||
|
||||
// If the ray int32_tersects with the "p" endcap of the capsule
|
||||
if (mDotD < 0.0f) {
|
||||
|
||||
// Check int32_tersection between the ray and the "p" sphere endcap of the capsule
|
||||
vec3 hitLocalPoint;
|
||||
float hitFraction;
|
||||
if (raycastWithSphereEndCap(ray.point1, ray.point2, p, ray.maxFraction, hitLocalPoint, hitFraction)) {
|
||||
raycastInfo.body = proxyShape->getBody();
|
||||
raycastInfo.proxyShape = proxyShape;
|
||||
raycastInfo.hitFraction = hitFraction;
|
||||
raycastInfo.worldPoint = hitLocalPoint;
|
||||
if (raycastWithSphereEndCap(_ray.point1, _ray.point2, p, _ray.maxFraction, hitLocalPoint, hitFraction)) {
|
||||
_raycastInfo.body = _proxyShape->getBody();
|
||||
_raycastInfo.proxyShape = _proxyShape;
|
||||
_raycastInfo.hitFraction = hitFraction;
|
||||
_raycastInfo.worldPoint = hitLocalPoint;
|
||||
vec3 normalDirection = hitLocalPoint - p;
|
||||
raycastInfo.worldNormal = normalDirection;
|
||||
|
||||
_raycastInfo.worldNormal = normalDirection;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
else if (mDotD > dDotD) { // If the ray int32_tersects with the "q" endcap of the cylinder
|
||||
|
||||
} else if (mDotD > dDotD) { // If the ray int32_tersects with the "q" endcap of the cylinder
|
||||
// Check int32_tersection between the ray and the "q" sphere endcap of the capsule
|
||||
vec3 hitLocalPoint;
|
||||
float hitFraction;
|
||||
if (raycastWithSphereEndCap(ray.point1, ray.point2, q, ray.maxFraction, hitLocalPoint, hitFraction)) {
|
||||
raycastInfo.body = proxyShape->getBody();
|
||||
raycastInfo.proxyShape = proxyShape;
|
||||
raycastInfo.hitFraction = hitFraction;
|
||||
raycastInfo.worldPoint = hitLocalPoint;
|
||||
if (raycastWithSphereEndCap(_ray.point1, _ray.point2, q, _ray.maxFraction, hitLocalPoint, hitFraction)) {
|
||||
_raycastInfo.body = _proxyShape->getBody();
|
||||
_raycastInfo.proxyShape = _proxyShape;
|
||||
_raycastInfo.hitFraction = hitFraction;
|
||||
_raycastInfo.worldPoint = hitLocalPoint;
|
||||
vec3 normalDirection = hitLocalPoint - q;
|
||||
raycastInfo.worldNormal = normalDirection;
|
||||
|
||||
_raycastInfo.worldNormal = normalDirection;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
else { // If the origin is inside the cylinder, we return no hit
|
||||
} else {
|
||||
// If the origin is inside the cylinder, we return no hit
|
||||
return false;
|
||||
}
|
||||
}
|
||||
float b = dDotD * mDotN - nDotD * mDotD;
|
||||
float discriminant = b * b - a * c;
|
||||
|
||||
// If the discriminant is negative, no real roots and therfore, no hit
|
||||
if (discriminant < 0.0f) return false;
|
||||
|
||||
if (discriminant < 0.0f) {
|
||||
return false;
|
||||
}
|
||||
// Compute the smallest root (first int32_tersection along the ray)
|
||||
float t0 = t = (-b - etk::sqrt(discriminant)) / a;
|
||||
|
||||
// If the int32_tersection is outside the finite cylinder of the capsule on "p" endcap side
|
||||
float value = mDotD + t * nDotD;
|
||||
if (value < 0.0f) {
|
||||
|
||||
// Check int32_tersection between the ray and the "p" sphere endcap of the capsule
|
||||
vec3 hitLocalPoint;
|
||||
float hitFraction;
|
||||
if (raycastWithSphereEndCap(ray.point1, ray.point2, p, ray.maxFraction, hitLocalPoint, hitFraction)) {
|
||||
raycastInfo.body = proxyShape->getBody();
|
||||
raycastInfo.proxyShape = proxyShape;
|
||||
raycastInfo.hitFraction = hitFraction;
|
||||
raycastInfo.worldPoint = hitLocalPoint;
|
||||
if (raycastWithSphereEndCap(_ray.point1, _ray.point2, p, _ray.maxFraction, hitLocalPoint, hitFraction)) {
|
||||
_raycastInfo.body = _proxyShape->getBody();
|
||||
_raycastInfo.proxyShape = _proxyShape;
|
||||
_raycastInfo.hitFraction = hitFraction;
|
||||
_raycastInfo.worldPoint = hitLocalPoint;
|
||||
vec3 normalDirection = hitLocalPoint - p;
|
||||
raycastInfo.worldNormal = normalDirection;
|
||||
|
||||
_raycastInfo.worldNormal = normalDirection;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
else if (value > dDotD) { // If the int32_tersection is outside the finite cylinder on the "q" side
|
||||
|
||||
} else if (value > dDotD) { // If the int32_tersection is outside the finite cylinder on the "q" side
|
||||
// Check int32_tersection between the ray and the "q" sphere endcap of the capsule
|
||||
vec3 hitLocalPoint;
|
||||
float hitFraction;
|
||||
if (raycastWithSphereEndCap(ray.point1, ray.point2, q, ray.maxFraction, hitLocalPoint, hitFraction)) {
|
||||
raycastInfo.body = proxyShape->getBody();
|
||||
raycastInfo.proxyShape = proxyShape;
|
||||
raycastInfo.hitFraction = hitFraction;
|
||||
raycastInfo.worldPoint = hitLocalPoint;
|
||||
if (raycastWithSphereEndCap(_ray.point1, _ray.point2, q, _ray.maxFraction, hitLocalPoint, hitFraction)) {
|
||||
_raycastInfo.body = _proxyShape->getBody();
|
||||
_raycastInfo.proxyShape = _proxyShape;
|
||||
_raycastInfo.hitFraction = hitFraction;
|
||||
_raycastInfo.worldPoint = hitLocalPoint;
|
||||
vec3 normalDirection = hitLocalPoint - q;
|
||||
raycastInfo.worldNormal = normalDirection;
|
||||
|
||||
_raycastInfo.worldNormal = normalDirection;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
t = t0;
|
||||
|
||||
// If the int32_tersection is behind the origin of the ray or beyond the maximum
|
||||
// raycasting distance, we return no hit
|
||||
if (t < 0.0f || t > ray.maxFraction) return false;
|
||||
|
||||
if (t < 0.0f || t > _ray.maxFraction) {
|
||||
return false;
|
||||
}
|
||||
// Compute the hit information
|
||||
vec3 localHitPoint = ray.point1 + t * n;
|
||||
raycastInfo.body = proxyShape->getBody();
|
||||
raycastInfo.proxyShape = proxyShape;
|
||||
raycastInfo.hitFraction = t;
|
||||
raycastInfo.worldPoint = localHitPoint;
|
||||
vec3 localHitPoint = _ray.point1 + t * n;
|
||||
_raycastInfo.body = _proxyShape->getBody();
|
||||
_raycastInfo.proxyShape = _proxyShape;
|
||||
_raycastInfo.hitFraction = t;
|
||||
_raycastInfo.worldPoint = localHitPoint;
|
||||
vec3 v = localHitPoint - p;
|
||||
vec3 w = (v.dot(d) / d.length2()) * d;
|
||||
vec3 normalDirection = (localHitPoint - (p + w)).safeNormalized();
|
||||
raycastInfo.worldNormal = normalDirection;
|
||||
|
||||
_raycastInfo.worldNormal = normalDirection;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Raycasting method between a ray one of the two spheres end cap of the capsule
|
||||
bool CapsuleShape::raycastWithSphereEndCap(const vec3& point1, const vec3& point2,
|
||||
const vec3& sphereCenter, float maxFraction,
|
||||
vec3& hitLocalPoint, float& hitFraction) const {
|
||||
|
||||
const vec3 m = point1 - sphereCenter;
|
||||
bool CapsuleShape::raycastWithSphereEndCap(const vec3& _point1,
|
||||
const vec3& _point2,
|
||||
const vec3& _sphereCenter,
|
||||
float _maxFraction,
|
||||
vec3& _hitLocalPoint,
|
||||
float& _hitFraction) const {
|
||||
const vec3 m = _point1 - _sphereCenter;
|
||||
float c = m.dot(m) - m_margin * m_margin;
|
||||
|
||||
// If the origin of the ray is inside the sphere, we return no int32_tersection
|
||||
if (c < 0.0f) return false;
|
||||
|
||||
const vec3 rayDirection = point2 - point1;
|
||||
if (c < 0.0f) {
|
||||
return false;
|
||||
}
|
||||
const vec3 rayDirection = _point2 - _point1;
|
||||
float b = m.dot(rayDirection);
|
||||
|
||||
// If the origin of the ray is outside the sphere and the ray
|
||||
// is pointing away from the sphere, there is no int32_tersection
|
||||
if (b > 0.0f) return false;
|
||||
|
||||
if (b > 0.0f) {
|
||||
return false;
|
||||
}
|
||||
float raySquareLength = rayDirection.length2();
|
||||
|
||||
// Compute the discriminant of the quadratic equation
|
||||
float discriminant = b * b - raySquareLength * c;
|
||||
|
||||
// If the discriminant is negative or the ray length is very small, there is no int32_tersection
|
||||
if (discriminant < 0.0f || raySquareLength < FLT_EPSILON) return false;
|
||||
|
||||
if ( discriminant < 0.0f
|
||||
|| raySquareLength < FLT_EPSILON) {
|
||||
return false;
|
||||
}
|
||||
// Compute the solution "t" closest to the origin
|
||||
float t = -b - etk::sqrt(discriminant);
|
||||
|
||||
assert(t >= 0.0f);
|
||||
|
||||
// If the hit point is withing the segment ray fraction
|
||||
if (t < maxFraction * raySquareLength) {
|
||||
|
||||
if (t < _maxFraction * raySquareLength) {
|
||||
// Compute the int32_tersection information
|
||||
t /= raySquareLength;
|
||||
hitFraction = t;
|
||||
hitLocalPoint = point1 + t * rayDirection;
|
||||
|
||||
_hitFraction = t;
|
||||
_hitLocalPoint = _point1 + t * rayDirection;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Get the radius of the capsule
|
||||
/**
|
||||
* @return The radius of the capsule shape (in meters)
|
||||
*/
|
||||
float CapsuleShape::getRadius() const {
|
||||
return m_margin;
|
||||
}
|
||||
|
||||
// Return the height of the capsule
|
||||
/**
|
||||
* @return The height of the capsule shape (in meters)
|
||||
*/
|
||||
float CapsuleShape::getHeight() const {
|
||||
return m_halfHeight + m_halfHeight;
|
||||
}
|
||||
|
||||
// Set the scaling vector of the collision shape
|
||||
void CapsuleShape::setLocalScaling(const vec3& scaling) {
|
||||
|
||||
m_halfHeight = (m_halfHeight / m_scaling.y()) * scaling.y();
|
||||
m_margin = (m_margin / m_scaling.x()) * scaling.x();
|
||||
|
||||
CollisionShape::setLocalScaling(scaling);
|
||||
void CapsuleShape::setLocalScaling(const vec3& _scaling) {
|
||||
m_halfHeight = (m_halfHeight / m_scaling.y()) * _scaling.y();
|
||||
m_margin = (m_margin / m_scaling.x()) * _scaling.x();
|
||||
CollisionShape::setLocalScaling(_scaling);
|
||||
}
|
||||
|
||||
// Return the number of bytes used by the collision shape
|
||||
size_t CapsuleShape::getSizeInBytes() const {
|
||||
return sizeof(CapsuleShape);
|
||||
}
|
||||
|
||||
// Return the local bounds of the shape in x, y and z directions
|
||||
// This method is used to compute the AABB of the box
|
||||
/**
|
||||
* @param min The minimum bounds of the shape in local-space coordinates
|
||||
* @param max The maximum bounds of the shape in local-space coordinates
|
||||
*/
|
||||
void CapsuleShape::getLocalBounds(vec3& min, vec3& max) const {
|
||||
|
||||
void CapsuleShape::getLocalBounds(vec3& _min, vec3& _max) const {
|
||||
// Maximum bounds
|
||||
max.setX(m_margin);
|
||||
max.setY(m_halfHeight + m_margin);
|
||||
max.setZ(m_margin);
|
||||
|
||||
_max.setX(m_margin);
|
||||
_max.setY(m_halfHeight + m_margin);
|
||||
_max.setZ(m_margin);
|
||||
// Minimum bounds
|
||||
min.setX(-m_margin);
|
||||
min.setY(-max.y());
|
||||
min.setZ(min.x());
|
||||
_min.setX(-m_margin);
|
||||
_min.setY(-_max.y());
|
||||
_min.setZ(_min.x());
|
||||
}
|
||||
|
||||
// Return a local support point in a given direction without the object margin.
|
||||
/// A capsule is the convex hull of two spheres S1 and S2. The support point in the direction "d"
|
||||
/// of the convex hull of a set of convex objects is the support point "p" in the set of all
|
||||
/// support points from all the convex objects with the maximum dot product with the direction "d".
|
||||
/// Therefore, in this method, we compute the support points of both top and bottom spheres of
|
||||
/// the capsule and return the point with the maximum dot product with the direction vector. Note
|
||||
/// that the object margin is implicitly the radius and height of the capsule.
|
||||
vec3 CapsuleShape::getLocalSupportPointWithoutMargin(const vec3& direction,
|
||||
void** cachedCollisionData) const {
|
||||
|
||||
vec3 CapsuleShape::getLocalSupportPointWithoutMargin(const vec3& _direction,
|
||||
void** _cachedCollisionData) const {
|
||||
// Support point top sphere
|
||||
float dotProductTop = m_halfHeight * direction.y();
|
||||
|
||||
float dotProductTop = m_halfHeight * _direction.y();
|
||||
// Support point bottom sphere
|
||||
float dotProductBottom = -m_halfHeight * direction.y();
|
||||
|
||||
float dotProductBottom = -m_halfHeight * _direction.y();
|
||||
// Return the point with the maximum dot product
|
||||
if (dotProductTop > dotProductBottom) {
|
||||
return vec3(0, m_halfHeight, 0);
|
||||
}
|
||||
else {
|
||||
return vec3(0, -m_halfHeight, 0);
|
||||
}
|
||||
}
|
||||
return vec3(0, -m_halfHeight, 0);
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -20,31 +23,44 @@ namespace ephysics {
|
||||
* capsule shape.
|
||||
*/
|
||||
class CapsuleShape : public ConvexShape {
|
||||
protected:
|
||||
float m_halfHeight; //!< Half height of the capsule (height = distance between the centers of the two spheres)
|
||||
/// Private copy-constructor
|
||||
CapsuleShape(const CapsuleShape& _shape);
|
||||
/// Private assignment operator
|
||||
CapsuleShape& operator=(const CapsuleShape& _shape);
|
||||
vec3 getLocalSupportPointWithoutMargin(const vec3& _direction, void** _cachedCollisionData) const override;
|
||||
bool testPointInside(const vec3& _localPoint, ProxyShape* _proxyShape) const override;
|
||||
bool raycast(const Ray& _ray, RaycastInfo& _raycastInfo, ProxyShape* _proxyShape) const override;
|
||||
/// Raycasting method between a ray one of the two spheres end cap of the capsule
|
||||
bool raycastWithSphereEndCap(const vec3& _point1, const vec3& _point2,
|
||||
const vec3& _sphereCenter, float _maxFraction,
|
||||
vec3& _hitLocalPoint, float& _hitFraction) const;
|
||||
size_t getSizeInBytes() const override;
|
||||
public :
|
||||
/// Constructor
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param _radius The radius of the capsule (in meters)
|
||||
* @param _height The height of the capsule (in meters)
|
||||
*/
|
||||
CapsuleShape(float _radius, float _height);
|
||||
/// Destructor
|
||||
virtual ~CapsuleShape();
|
||||
/// Return the radius of the capsule
|
||||
/// DELETE copy-constructor
|
||||
CapsuleShape(const CapsuleShape& _shape) = delete;
|
||||
/// DELETE assignment operator
|
||||
CapsuleShape& operator=(const CapsuleShape& _shape) = delete;
|
||||
/**
|
||||
* Get the radius of the capsule
|
||||
* @return The radius of the capsule shape (in meters)
|
||||
*/
|
||||
float getRadius() const;
|
||||
/// Return the height of the capsule
|
||||
/**
|
||||
* @brief Return the height of the capsule
|
||||
* @return The height of the capsule shape (in meters)
|
||||
*/
|
||||
float getHeight() const;
|
||||
void setLocalScaling(const vec3& _scaling) override;
|
||||
void getLocalBounds(vec3& _min, vec3& _max) const override;
|
||||
void computeLocalInertiaTensor(etk::Matrix3x3& _tensor, float _mass) const override;
|
||||
protected:
|
||||
float m_halfHeight; //!< Half height of the capsule (height = distance between the centers of the two spheres)
|
||||
vec3 getLocalSupportPointWithoutMargin(const vec3& _direction, void** _cachedCollisionData) const override;
|
||||
bool testPointInside(const vec3& _localPoint, ProxyShape* _proxyShape) const override;
|
||||
bool raycast(const Ray& _ray, RaycastInfo& _raycastInfo, ProxyShape* _proxyShape) const override;
|
||||
/**
|
||||
* @brief Raycasting method between a ray one of the two spheres end cap of the capsule
|
||||
*/
|
||||
bool raycastWithSphereEndCap(const vec3& _point1,
|
||||
const vec3& _point2,
|
||||
const vec3& _sphereCenter,
|
||||
float _maxFraction,
|
||||
vec3& _hitLocalPoint,
|
||||
float& _hitFraction) const;
|
||||
size_t getSizeInBytes() const override;
|
||||
};
|
||||
}
|
||||
|
@ -1,10 +1,11 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
// Libraries
|
||||
#include <ephysics/collision/shapes/CollisionShape.hpp>
|
||||
#include <ephysics/engine/Profiler.hpp>
|
||||
#include <ephysics/body/CollisionBody.hpp>
|
||||
@ -18,50 +19,35 @@ CollisionShape::CollisionShape(CollisionShapeType type) :
|
||||
|
||||
}
|
||||
|
||||
CollisionShape::~CollisionShape() {
|
||||
|
||||
}
|
||||
|
||||
// Compute the world-space AABB of the collision shape given a transform
|
||||
/**
|
||||
* @param[out] aabb The axis-aligned bounding box (AABB) of the collision shape
|
||||
* computed in world-space coordinates
|
||||
* @param transform etk::Transform3D used to compute the AABB of the collision shape
|
||||
*/
|
||||
void CollisionShape::computeAABB(AABB& aabb, const etk::Transform3D& transform) const {
|
||||
|
||||
void CollisionShape::computeAABB(AABB& _aabb, const etk::Transform3D& _transform) const {
|
||||
PROFILE("CollisionShape::computeAABB()");
|
||||
|
||||
// Get the local bounds in x,y and z direction
|
||||
vec3 minBounds(0,0,0);
|
||||
vec3 maxBounds(0,0,0);
|
||||
getLocalBounds(minBounds, maxBounds);
|
||||
|
||||
// Rotate the local bounds according to the orientation of the body
|
||||
etk::Matrix3x3 worldAxis = transform.getOrientation().getMatrix().getAbsolute();
|
||||
etk::Matrix3x3 worldAxis = _transform.getOrientation().getMatrix().getAbsolute();
|
||||
vec3 worldMinBounds(worldAxis.getColumn(0).dot(minBounds),
|
||||
worldAxis.getColumn(1).dot(minBounds),
|
||||
worldAxis.getColumn(2).dot(minBounds));
|
||||
vec3 worldMaxBounds(worldAxis.getColumn(0).dot(maxBounds),
|
||||
worldAxis.getColumn(1).dot(maxBounds),
|
||||
worldAxis.getColumn(2).dot(maxBounds));
|
||||
|
||||
// Compute the minimum and maximum coordinates of the rotated extents
|
||||
vec3 minCoordinates = transform.getPosition() + worldMinBounds;
|
||||
vec3 maxCoordinates = transform.getPosition() + worldMaxBounds;
|
||||
|
||||
vec3 minCoordinates = _transform.getPosition() + worldMinBounds;
|
||||
vec3 maxCoordinates = _transform.getPosition() + worldMaxBounds;
|
||||
// Update the AABB with the new minimum and maximum coordinates
|
||||
aabb.setMin(minCoordinates);
|
||||
aabb.setMax(maxCoordinates);
|
||||
_aabb.setMin(minCoordinates);
|
||||
_aabb.setMax(maxCoordinates);
|
||||
}
|
||||
|
||||
int32_t CollisionShape::computeNbMaxContactManifolds(CollisionShapeType shapeType1,
|
||||
CollisionShapeType shapeType2) {
|
||||
int32_t CollisionShape::computeNbMaxContactManifolds(CollisionShapeType _shapeType1,
|
||||
CollisionShapeType _shapeType2) {
|
||||
// If both shapes are convex
|
||||
if (isConvex(shapeType1) && isConvex(shapeType2)) {
|
||||
if (isConvex(_shapeType1) && isConvex(_shapeType2)) {
|
||||
return NB_MAX_CONTACT_MANIFOLDS_CONVEX_SHAPE;
|
||||
} // If there is at least one concave shape
|
||||
else {
|
||||
return NB_MAX_CONTACT_MANIFOLDS_CONCAVE_SHAPE;
|
||||
}
|
||||
}
|
||||
// If there is at least one concave shape
|
||||
return NB_MAX_CONTACT_MANIFOLDS_CONCAVE_SHAPE;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -25,24 +28,15 @@ class CollisionBody;
|
||||
* body that is used during the narrow-phase collision detection.
|
||||
*/
|
||||
class CollisionShape {
|
||||
protected :
|
||||
CollisionShapeType m_type; //!< Type of the collision shape
|
||||
vec3 m_scaling; //!< Scaling vector of the collision shape
|
||||
/// Private copy-constructor
|
||||
CollisionShape(const CollisionShape& shape) = delete;
|
||||
/// Private assignment operator
|
||||
CollisionShape& operator=(const CollisionShape& shape) = delete;
|
||||
/// Return true if a point is inside the collision shape
|
||||
virtual bool testPointInside(const vec3& worldPoint, ProxyShape* proxyShape) const=0;
|
||||
/// Raycast method with feedback information
|
||||
virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const=0;
|
||||
/// Return the number of bytes used by the collision shape
|
||||
virtual size_t getSizeInBytes() const = 0;
|
||||
public :
|
||||
/// Constructor
|
||||
CollisionShape(CollisionShapeType _type);
|
||||
/// Destructor
|
||||
virtual ~CollisionShape();
|
||||
/// DELETE copy-constructor
|
||||
CollisionShape(const CollisionShape& shape) = delete;
|
||||
/// DELETE assignment operator
|
||||
CollisionShape& operator=(const CollisionShape& shape) = delete;
|
||||
/// Virtualize destructor
|
||||
virtual ~CollisionShape() {};
|
||||
/**
|
||||
* @brief Get the type of the collision shapes
|
||||
* @return The type of the collision shape (box, sphere, cylinder, ...)
|
||||
@ -103,6 +97,15 @@ class CollisionShape {
|
||||
CollisionShapeType _shapeType2);
|
||||
friend class ProxyShape;
|
||||
friend class CollisionWorld;
|
||||
protected :
|
||||
CollisionShapeType m_type; //!< Type of the collision shape
|
||||
vec3 m_scaling; //!< Scaling vector of the collision shape
|
||||
/// Return true if a point is inside the collision shape
|
||||
virtual bool testPointInside(const vec3& worldPoint, ProxyShape* proxyShape) const = 0;
|
||||
/// Raycast method with feedback information
|
||||
virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const = 0;
|
||||
/// Return the number of bytes used by the collision shape
|
||||
virtual size_t getSizeInBytes() const = 0;
|
||||
};
|
||||
|
||||
|
||||
|
@ -1,9 +1,11 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <ephysics/collision/shapes/ConcaveMeshShape.hpp>
|
||||
#include <ephysics/debug.hpp>
|
||||
|
||||
@ -39,12 +41,11 @@ void ConcaveMeshShape::initBVHTree() {
|
||||
}
|
||||
|
||||
void ConcaveMeshShape::getTriangleVerticesWithIndexPointer(int32_t _subPart, int32_t _triangleIndex, vec3* _outTriangleVertices) const {
|
||||
EPHY_ASSERT(_outTriangleVertices != nullptr, "Input check error");
|
||||
|
||||
EPHY_ASSERT(_outTriangleVertices != null, "Input check error");
|
||||
// Get the triangle vertex array of the current sub-part
|
||||
TriangleVertexArray* triangleVertexArray = m_triangleMesh->getSubpart(_subPart);
|
||||
if (triangleVertexArray == nullptr) {
|
||||
EPHY_ERROR("get nullptr ...");
|
||||
if (triangleVertexArray == null) {
|
||||
EPHY_ERROR("get null ...");
|
||||
}
|
||||
ephysics::Triangle trianglePoints = triangleVertexArray->getTriangle(_triangleIndex);
|
||||
_outTriangleVertices[0] = trianglePoints[0] * m_scaling;
|
||||
@ -53,10 +54,17 @@ void ConcaveMeshShape::getTriangleVerticesWithIndexPointer(int32_t _subPart, int
|
||||
}
|
||||
|
||||
void ConcaveMeshShape::testAllTriangles(TriangleCallback& _callback, const AABB& _localAABB) const {
|
||||
ConvexTriangleAABBOverlapCallback overlapCallback(_callback, *this, m_dynamicAABBTree);
|
||||
// Ask the Dynamic AABB Tree to report all the triangles that are overlapping
|
||||
// with the AABB of the convex shape.
|
||||
m_dynamicAABBTree.reportAllShapesOverlappingWithAABB(_localAABB, overlapCallback);
|
||||
m_dynamicAABBTree.reportAllShapesOverlappingWithAABB(_localAABB, [&](int32_t _nodeId) {
|
||||
// Get the node data (triangle index and mesh subpart index)
|
||||
int32_t* data = m_dynamicAABBTree.getNodeDataInt(_nodeId);
|
||||
// Get the triangle vertices for this node from the concave mesh shape
|
||||
vec3 trianglePoints[3];
|
||||
getTriangleVerticesWithIndexPointer(data[0], data[1], trianglePoints);
|
||||
// Call the callback to test narrow-phase collision with this triangle
|
||||
_callback.testTriangle(trianglePoints);
|
||||
});
|
||||
}
|
||||
|
||||
bool ConcaveMeshShape::raycast(const Ray& _ray, RaycastInfo& _raycastInfo, ProxyShape* _proxyShape) const {
|
||||
@ -66,12 +74,12 @@ bool ConcaveMeshShape::raycast(const Ray& _ray, RaycastInfo& _raycastInfo, Proxy
|
||||
// Ask the Dynamic AABB Tree to report all AABB nodes that are hit by the ray.
|
||||
// The raycastCallback object will then compute ray casting against the triangles
|
||||
// in the hit AABBs.
|
||||
m_dynamicAABBTree.raycast(_ray, raycastCallback);
|
||||
m_dynamicAABBTree.raycast(_ray, [&](int32_t _nodeId, const ephysics::Ray& _ray) mutable { return raycastCallback(_nodeId, _ray);});
|
||||
raycastCallback.raycastTriangles();
|
||||
return raycastCallback.getIsHit();
|
||||
}
|
||||
|
||||
float ConcaveMeshRaycastCallback::raycastBroadPhaseShape(int32_t _nodeId, const Ray& _ray) {
|
||||
float ConcaveMeshRaycastCallback::operator()(int32_t _nodeId, const Ray& _ray) {
|
||||
// Add the id of the hit AABB node int32_to
|
||||
m_hitAABBNodes.pushBack(_nodeId);
|
||||
return _ray.maxFraction;
|
||||
@ -104,7 +112,7 @@ void ConcaveMeshRaycastCallback::raycastTriangles() {
|
||||
m_raycastInfo.meshSubpart = data[0];
|
||||
m_raycastInfo.triangleIndex = data[1];
|
||||
smallestHitFraction = raycastInfo.hitFraction;
|
||||
mIsHit = true;
|
||||
m_isHit = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -136,17 +144,4 @@ void ConcaveMeshShape::computeLocalInertiaTensor(etk::Matrix3x3& _tensor, float
|
||||
0, 0, _mass);
|
||||
}
|
||||
|
||||
void ConvexTriangleAABBOverlapCallback::notifyOverlappingNode(int32_t _nodeId) {
|
||||
|
||||
// Get the node data (triangle index and mesh subpart index)
|
||||
int32_t* data = m_dynamicAABBTree.getNodeDataInt(_nodeId);
|
||||
|
||||
// Get the triangle vertices for this node from the concave mesh shape
|
||||
vec3 trianglePoints[3];
|
||||
m_concaveMeshShape.getTriangleVerticesWithIndexPointer(data[0], data[1], trianglePoints);
|
||||
|
||||
// Call the callback to test narrow-phase collision with this triangle
|
||||
m_triangleTestCallback.testTriangle(trianglePoints);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -13,35 +16,15 @@
|
||||
|
||||
namespace ephysics {
|
||||
class ConcaveMeshShape;
|
||||
class ConvexTriangleAABBOverlapCallback : public DynamicAABBTreeOverlapCallback {
|
||||
class ConcaveMeshRaycastCallback {
|
||||
private:
|
||||
TriangleCallback& m_triangleTestCallback; //!<
|
||||
const ConcaveMeshShape& m_concaveMeshShape; //!< Reference to the concave mesh shape
|
||||
const DynamicAABBTree& m_dynamicAABBTree; //!< Reference to the Dynamic AABB tree
|
||||
public:
|
||||
// Constructor
|
||||
ConvexTriangleAABBOverlapCallback(TriangleCallback& _triangleCallback,
|
||||
const ConcaveMeshShape& _concaveShape,
|
||||
const DynamicAABBTree& _dynamicAABBTree):
|
||||
m_triangleTestCallback(_triangleCallback),
|
||||
m_concaveMeshShape(_concaveShape),
|
||||
m_dynamicAABBTree(_dynamicAABBTree) {
|
||||
|
||||
}
|
||||
// Called when a overlapping node has been found during the call to
|
||||
// DynamicAABBTree:reportAllShapesOverlappingWithAABB()
|
||||
virtual void notifyOverlappingNode(int32_t _nodeId);
|
||||
};
|
||||
|
||||
class ConcaveMeshRaycastCallback : public DynamicAABBTreeRaycastCallback {
|
||||
private :
|
||||
etk::Vector<int32_t> m_hitAABBNodes;
|
||||
const DynamicAABBTree& m_dynamicAABBTree;
|
||||
const ConcaveMeshShape& m_concaveMeshShape;
|
||||
ProxyShape* m_proxyShape;
|
||||
RaycastInfo& m_raycastInfo;
|
||||
const Ray& m_ray;
|
||||
bool mIsHit;
|
||||
bool m_isHit;
|
||||
public:
|
||||
// Constructor
|
||||
ConcaveMeshRaycastCallback(const DynamicAABBTree& _dynamicAABBTree,
|
||||
@ -54,16 +37,16 @@ namespace ephysics {
|
||||
m_proxyShape(_proxyShape),
|
||||
m_raycastInfo(_raycastInfo),
|
||||
m_ray(_ray),
|
||||
mIsHit(false) {
|
||||
m_isHit(false) {
|
||||
|
||||
}
|
||||
/// Collect all the AABB nodes that are hit by the ray in the Dynamic AABB Tree
|
||||
virtual float raycastBroadPhaseShape(int32_t _nodeId, const Ray& _ray);
|
||||
float operator()(int32_t _nodeId, const ephysics::Ray& _ray);
|
||||
/// Raycast all collision shapes that have been collected
|
||||
void raycastTriangles();
|
||||
/// Return true if a raycast hit has been found
|
||||
bool getIsHit() const {
|
||||
return mIsHit;
|
||||
return m_isHit;
|
||||
}
|
||||
};
|
||||
/**
|
||||
@ -72,13 +55,22 @@ namespace ephysics {
|
||||
* this shape for a static mesh.
|
||||
*/
|
||||
class ConcaveMeshShape : public ConcaveShape {
|
||||
public:
|
||||
/// Constructor
|
||||
ConcaveMeshShape(TriangleMesh* _triangleMesh);
|
||||
/// DELETE copy-constructor
|
||||
ConcaveMeshShape(const ConcaveMeshShape& _shape) = delete;
|
||||
/// DELETE assignment operator
|
||||
ConcaveMeshShape& operator=(const ConcaveMeshShape& _shape) = delete;
|
||||
virtual void getLocalBounds(vec3& _min, vec3& _max) const override;
|
||||
virtual void setLocalScaling(const vec3& _scaling) override;
|
||||
virtual void computeLocalInertiaTensor(etk::Matrix3x3& _tensor, float _mass) const override;
|
||||
virtual void testAllTriangles(TriangleCallback& _callback, const AABB& _localAABB) const override;
|
||||
friend class ConvexTriangleAABBOverlapCallback;
|
||||
friend class ConcaveMeshRaycastCallback;
|
||||
protected:
|
||||
TriangleMesh* m_triangleMesh; //!< Triangle mesh
|
||||
DynamicAABBTree m_dynamicAABBTree; //!< Dynamic AABB tree to accelerate collision with the triangles
|
||||
/// Private copy-constructor
|
||||
ConcaveMeshShape(const ConcaveMeshShape& _shape) = delete;
|
||||
/// Private assignment operator
|
||||
ConcaveMeshShape& operator=(const ConcaveMeshShape& _shape) = delete;
|
||||
virtual bool raycast(const Ray& _ray, RaycastInfo& _raycastInfo, ProxyShape* _proxyShape) const override;
|
||||
virtual size_t getSizeInBytes() const override;
|
||||
/// Insert all the triangles int32_to the dynamic AABB tree
|
||||
@ -88,16 +80,6 @@ namespace ephysics {
|
||||
void getTriangleVerticesWithIndexPointer(int32_t _subPart,
|
||||
int32_t _triangleIndex,
|
||||
vec3* _outTriangleVertices) const;
|
||||
public:
|
||||
/// Constructor
|
||||
ConcaveMeshShape(TriangleMesh* triangleMesh);
|
||||
virtual void getLocalBounds(vec3& min, vec3& max) const override;
|
||||
virtual void setLocalScaling(const vec3& scaling) override;
|
||||
virtual void computeLocalInertiaTensor(etk::Matrix3x3& tensor, float mass) const override;
|
||||
/// Use a callback method on all triangles of the concave shape inside a given AABB
|
||||
virtual void testAllTriangles(TriangleCallback& callback, const AABB& localAABB) const override;
|
||||
friend class ConvexTriangleAABBOverlapCallback;
|
||||
friend class ConcaveMeshRaycastCallback;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -1,10 +1,11 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
// Libraries
|
||||
#include <ephysics/collision/shapes/ConcaveShape.hpp>
|
||||
|
||||
|
||||
@ -12,54 +13,38 @@
|
||||
using namespace ephysics;
|
||||
|
||||
// Constructor
|
||||
ConcaveShape::ConcaveShape(CollisionShapeType type)
|
||||
: CollisionShape(type), m_isSmoothMeshCollisionEnabled(false),
|
||||
m_triangleMargin(0), m_raycastTestType(FRONT) {
|
||||
|
||||
ConcaveShape::ConcaveShape(CollisionShapeType _type):
|
||||
CollisionShape(_type),
|
||||
m_isSmoothMeshCollisionEnabled(false),
|
||||
m_triangleMargin(0),
|
||||
m_raycastTestType(FRONT) {
|
||||
|
||||
}
|
||||
|
||||
// Destructor
|
||||
ConcaveShape::~ConcaveShape() {
|
||||
|
||||
}
|
||||
|
||||
// Return the triangle margin
|
||||
float ConcaveShape::getTriangleMargin() const {
|
||||
return m_triangleMargin;
|
||||
}
|
||||
|
||||
/// Return true if the collision shape is convex, false if it is concave
|
||||
bool ConcaveShape::isConvex() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return true if a point is inside the collision shape
|
||||
bool ConcaveShape::testPointInside(const vec3& localPoint, ProxyShape* proxyShape) const {
|
||||
bool ConcaveShape::testPointInside(const vec3& _localPoint, ProxyShape* _proxyShape) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return true if the smooth mesh collision is enabled
|
||||
bool ConcaveShape::getIsSmoothMeshCollisionEnabled() const {
|
||||
return m_isSmoothMeshCollisionEnabled;
|
||||
}
|
||||
|
||||
// Enable/disable the smooth mesh collision algorithm
|
||||
/// Smooth mesh collision is used to avoid collisions against some int32_ternal edges
|
||||
/// of the triangle mesh. If it is enabled, collsions with the mesh will be smoother
|
||||
/// but collisions computation is a bit more expensive.
|
||||
void ConcaveShape::setIsSmoothMeshCollisionEnabled(bool isEnabled) {
|
||||
m_isSmoothMeshCollisionEnabled = isEnabled;
|
||||
void ConcaveShape::setIsSmoothMeshCollisionEnabled(bool _isEnabled) {
|
||||
m_isSmoothMeshCollisionEnabled = _isEnabled;
|
||||
}
|
||||
|
||||
// Return the raycast test type (front, back, front-back)
|
||||
TriangleRaycastSide ConcaveShape::getRaycastTestType() const {
|
||||
return m_raycastTestType;
|
||||
}
|
||||
|
||||
// Set the raycast test type (front, back, front-back)
|
||||
/**
|
||||
* @param testType Raycast test type for the triangle (front, back, front-back)
|
||||
*/
|
||||
void ConcaveShape::setRaycastTestType(TriangleRaycastSide testType) {
|
||||
m_raycastTestType = testType;
|
||||
void ConcaveShape::setRaycastTestType(TriangleRaycastSide _testType) {
|
||||
m_raycastTestType = _testType;
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -25,25 +28,27 @@ namespace ephysics {
|
||||
* body that is used during the narrow-phase collision detection.
|
||||
*/
|
||||
class ConcaveShape : public CollisionShape {
|
||||
public :
|
||||
/// Constructor
|
||||
ConcaveShape(CollisionShapeType _type);
|
||||
/// DELETE copy-constructor
|
||||
ConcaveShape(const ConcaveShape& _shape) = delete;
|
||||
/// DELETE assignment operator
|
||||
ConcaveShape& operator=(const ConcaveShape& _shape) = delete;
|
||||
protected :
|
||||
bool m_isSmoothMeshCollisionEnabled; //!< True if the smooth mesh collision algorithm is enabled
|
||||
float m_triangleMargin; //!< Margin use for collision detection for each triangle
|
||||
TriangleRaycastSide m_raycastTestType; //!< Raycast test type for the triangle (front, back, front-back)
|
||||
/// Private copy-constructor
|
||||
ConcaveShape(const ConcaveShape& _shape) = delete;
|
||||
/// Private assignment operator
|
||||
ConcaveShape& operator=(const ConcaveShape& _shape) = delete;
|
||||
virtual bool testPointInside(const vec3& _localPoint, ProxyShape* _proxyShape) const override;
|
||||
public :
|
||||
/// Constructor
|
||||
ConcaveShape(CollisionShapeType _type);
|
||||
/// Destructor
|
||||
virtual ~ConcaveShape();
|
||||
bool testPointInside(const vec3& _localPoint, ProxyShape* _proxyShape) const override;
|
||||
public:
|
||||
/// Return the triangle margin
|
||||
float getTriangleMargin() const;
|
||||
/// Return the raycast test type (front, back, front-back)
|
||||
TriangleRaycastSide getRaycastTestType() const;
|
||||
// Set the raycast test type (front, back, front-back)
|
||||
/**
|
||||
* @brief Set the raycast test type (front, back, front-back)
|
||||
* @param testType Raycast test type for the triangle (front, back, front-back)
|
||||
*/
|
||||
void setRaycastTestType(TriangleRaycastSide _testType);
|
||||
/// Return true if the collision shape is convex, false if it is concave
|
||||
virtual bool isConvex() const override;
|
||||
@ -51,7 +56,12 @@ namespace ephysics {
|
||||
virtual void testAllTriangles(TriangleCallback& _callback, const AABB& _localAABB) const=0;
|
||||
/// Return true if the smooth mesh collision is enabled
|
||||
bool getIsSmoothMeshCollisionEnabled() const;
|
||||
/// Enable/disable the smooth mesh collision algorithm
|
||||
/**
|
||||
* @brief Enable/disable the smooth mesh collision algorithm
|
||||
*
|
||||
* Smooth mesh collision is used to avoid collisions against some int32_ternal edges of the triangle mesh.
|
||||
* If it is enabled, collsions with the mesh will be smoother but collisions computation is a bit more expensive.
|
||||
*/
|
||||
void setIsSmoothMeshCollisionEnabled(bool _isEnabled);
|
||||
};
|
||||
|
||||
|
@ -1,66 +1,47 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
// Libraries
|
||||
#include <ephysics/configuration.hpp>
|
||||
#include <ephysics/collision/shapes/ConeShape.hpp>
|
||||
#include <ephysics/collision/ProxyShape.hpp>
|
||||
|
||||
using namespace ephysics;
|
||||
|
||||
// Constructor
|
||||
/**
|
||||
* @param radius Radius of the cone (in meters)
|
||||
* @param height Height of the cone (in meters)
|
||||
* @param margin Collision margin (in meters) around the collision shape
|
||||
*/
|
||||
ConeShape::ConeShape(float radius, float height, float margin):
|
||||
ConvexShape(CONE, margin),
|
||||
m_radius(radius),
|
||||
m_halfHeight(height * 0.5f) {
|
||||
ConeShape::ConeShape(float _radius, float _height, float _margin):
|
||||
ConvexShape(CONE, _margin),
|
||||
m_radius(_radius),
|
||||
m_halfHeight(_height * 0.5f) {
|
||||
assert(m_radius > 0.0f);
|
||||
assert(m_halfHeight > 0.0f);
|
||||
|
||||
// Compute the sine of the semi-angle at the apex point
|
||||
m_sinTheta = m_radius / (sqrt(m_radius * m_radius + height * height));
|
||||
m_sinTheta = m_radius / (sqrt(m_radius * m_radius + _height * _height));
|
||||
}
|
||||
|
||||
// Return a local support point in a given direction without the object margin
|
||||
vec3 ConeShape::getLocalSupportPointWithoutMargin(const vec3& direction,
|
||||
void** cachedCollisionData) const {
|
||||
|
||||
const vec3& v = direction;
|
||||
vec3 ConeShape::getLocalSupportPointWithoutMargin(const vec3& _direction, void** _cachedCollisionData) const {
|
||||
const vec3& v = _direction;
|
||||
float sinThetaTimesLengthV = m_sinTheta * v.length();
|
||||
vec3 supportPoint;
|
||||
|
||||
if (v.y() > sinThetaTimesLengthV) {
|
||||
supportPoint = vec3(0.0, m_halfHeight, 0.0);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
float projectedLength = sqrt(v.x() * v.x() + v.z() * v.z());
|
||||
if (projectedLength > FLT_EPSILON) {
|
||||
float d = m_radius / projectedLength;
|
||||
supportPoint = vec3(v.x() * d, -m_halfHeight, v.z() * d);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
supportPoint = vec3(0.0, -m_halfHeight, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
return supportPoint;
|
||||
}
|
||||
|
||||
// Raycast method with feedback information
|
||||
// This implementation is based on the technique described by David Eberly in the article
|
||||
// "Intersection of a Line and a Cone" that can be found at
|
||||
// http://www.geometrictools.com/Documentation/IntersectionLineCone.pdf
|
||||
bool ConeShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const {
|
||||
|
||||
const vec3 r = ray.point2 - ray.point1;
|
||||
|
||||
bool ConeShape::raycast(const Ray& _ray, RaycastInfo& _raycastInfo, ProxyShape* _proxyShape) const {
|
||||
const vec3 r = _ray.point2 - _ray.point1;
|
||||
const float epsilon = float(0.00001);
|
||||
vec3 V(0, m_halfHeight, 0);
|
||||
vec3 centerBase(0, -m_halfHeight, 0);
|
||||
@ -68,57 +49,47 @@ bool ConeShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* pr
|
||||
float heightSquare = float(4.0) * m_halfHeight * m_halfHeight;
|
||||
float cosThetaSquare = heightSquare / (heightSquare + m_radius * m_radius);
|
||||
float factor = 1.0f - cosThetaSquare;
|
||||
vec3 delta = ray.point1 - V;
|
||||
float c0 = -cosThetaSquare * delta.x() * delta.x() + factor * delta.y() * delta.y() -
|
||||
cosThetaSquare * delta.z() * delta.z();
|
||||
vec3 delta = _ray.point1 - V;
|
||||
float c0 = -cosThetaSquare * delta.x() * delta.x() + factor * delta.y() * delta.y() - cosThetaSquare * delta.z() * delta.z();
|
||||
float c1 = -cosThetaSquare * delta.x() * r.x() + factor * delta.y() * r.y() - cosThetaSquare * delta.z() * r.z();
|
||||
float c2 = -cosThetaSquare * r.x() * r.x() + factor * r.y() * r.y() - cosThetaSquare * r.z() * r.z();
|
||||
float tHit[] = {float(-1.0), float(-1.0), float(-1.0)};
|
||||
vec3 localHitPoint[3];
|
||||
vec3 localNormal[3];
|
||||
|
||||
// If c2 is different from zero
|
||||
if (etk::abs(c2) > FLT_EPSILON) {
|
||||
float gamma = c1 * c1 - c0 * c2;
|
||||
|
||||
// If there is no real roots in the quadratic equation
|
||||
if (gamma < 0.0f) {
|
||||
return false;
|
||||
}
|
||||
else if (gamma > 0.0f) { // The equation has two real roots
|
||||
|
||||
} else if (gamma > 0.0f) { // The equation has two real roots
|
||||
// Compute two int32_tersections
|
||||
float sqrRoot = etk::sqrt(gamma);
|
||||
tHit[0] = (-c1 - sqrRoot) / c2;
|
||||
tHit[1] = (-c1 + sqrRoot) / c2;
|
||||
}
|
||||
else { // If the equation has a single real root
|
||||
|
||||
} else { // If the equation has a single real root
|
||||
// Compute the int32_tersection
|
||||
tHit[0] = -c1 / c2;
|
||||
}
|
||||
}
|
||||
else { // If c2 == 0
|
||||
|
||||
// If c2 = 0 and c1 != 0
|
||||
} else {
|
||||
// If c2 == 0
|
||||
if (etk::abs(c1) > FLT_EPSILON) {
|
||||
// If c2 = 0 and c1 != 0
|
||||
tHit[0] = -c0 / (float(2.0) * c1);
|
||||
}
|
||||
else { // If c2 = c1 = 0
|
||||
|
||||
} else {
|
||||
// If c2 = c1 = 0
|
||||
// If c0 is different from zero, no solution and if c0 = 0, we have a
|
||||
// degenerate case, the whole ray is contained in the cone side
|
||||
// but we return no hit in this case
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If the origin of the ray is inside the cone, we return no hit
|
||||
if (testPointInside(ray.point1, NULL)) return false;
|
||||
|
||||
localHitPoint[0] = ray.point1 + tHit[0] * r;
|
||||
localHitPoint[1] = ray.point1 + tHit[1] * r;
|
||||
|
||||
if (testPointInside(_ray.point1, NULL)) {
|
||||
return false;
|
||||
}
|
||||
localHitPoint[0] = _ray.point1 + tHit[0] * r;
|
||||
localHitPoint[1] = _ray.point1 + tHit[1] * r;
|
||||
// Only keep hit points in one side of the double cone (the cone we are int32_terested in)
|
||||
if (axis.dot(localHitPoint[0] - V) < 0.0f) {
|
||||
tHit[0] = float(-1.0);
|
||||
@ -126,7 +97,6 @@ bool ConeShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* pr
|
||||
if (axis.dot(localHitPoint[1] - V) < 0.0f) {
|
||||
tHit[1] = float(-1.0);
|
||||
}
|
||||
|
||||
// Only keep hit points that are within the correct height of the cone
|
||||
if (localHitPoint[0].y() < float(-m_halfHeight)) {
|
||||
tHit[0] = float(-1.0);
|
||||
@ -134,43 +104,40 @@ bool ConeShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* pr
|
||||
if (localHitPoint[1].y() < float(-m_halfHeight)) {
|
||||
tHit[1] = float(-1.0);
|
||||
}
|
||||
|
||||
// If the ray is in direction of the base plane of the cone
|
||||
if (r.y() > epsilon) {
|
||||
|
||||
// Compute the int32_tersection with the base plane of the cone
|
||||
tHit[2] = (-ray.point1.y() - m_halfHeight) / (r.y());
|
||||
|
||||
tHit[2] = (-_ray.point1.y() - m_halfHeight) / (r.y());
|
||||
// Only keep this int32_tersection if it is inside the cone radius
|
||||
localHitPoint[2] = ray.point1 + tHit[2] * r;
|
||||
|
||||
localHitPoint[2] = _ray.point1 + tHit[2] * r;
|
||||
if ((localHitPoint[2] - centerBase).length2() > m_radius * m_radius) {
|
||||
tHit[2] = float(-1.0);
|
||||
}
|
||||
|
||||
// Compute the normal direction
|
||||
localNormal[2] = axis;
|
||||
}
|
||||
|
||||
// Find the smallest positive t value
|
||||
int32_t hitIndex = -1;
|
||||
float t = FLT_MAX;
|
||||
for (int32_t i=0; i<3; i++) {
|
||||
if (tHit[i] < 0.0f) continue;
|
||||
if (tHit[i] < 0.0f) {
|
||||
continue;
|
||||
}
|
||||
if (tHit[i] < t) {
|
||||
hitIndex = i;
|
||||
t = tHit[hitIndex];
|
||||
}
|
||||
}
|
||||
|
||||
if (hitIndex < 0) return false;
|
||||
if (t > ray.maxFraction) return false;
|
||||
|
||||
if (hitIndex < 0) {
|
||||
return false;
|
||||
}
|
||||
if (t > _ray.maxFraction) {
|
||||
return false;
|
||||
}
|
||||
// Compute the normal direction for hit against side of the cone
|
||||
if (hitIndex != 2) {
|
||||
float h = float(2.0) * m_halfHeight;
|
||||
float value1 = (localHitPoint[hitIndex].x() * localHitPoint[hitIndex].x() +
|
||||
localHitPoint[hitIndex].z() * localHitPoint[hitIndex].z());
|
||||
float value1 = (localHitPoint[hitIndex].x() * localHitPoint[hitIndex].x() + localHitPoint[hitIndex].z() * localHitPoint[hitIndex].z());
|
||||
float rOverH = m_radius / h;
|
||||
float value2 = 1.0f + rOverH * rOverH;
|
||||
float factor = 1.0f / etk::sqrt(value1 * value2);
|
||||
@ -180,82 +147,56 @@ bool ConeShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* pr
|
||||
localNormal[hitIndex].setY(etk::sqrt(x * x + z * z) * rOverH);
|
||||
localNormal[hitIndex].setZ(z);
|
||||
}
|
||||
|
||||
raycastInfo.body = proxyShape->getBody();
|
||||
raycastInfo.proxyShape = proxyShape;
|
||||
raycastInfo.hitFraction = t;
|
||||
raycastInfo.worldPoint = localHitPoint[hitIndex];
|
||||
raycastInfo.worldNormal = localNormal[hitIndex];
|
||||
|
||||
_raycastInfo.body = _proxyShape->getBody();
|
||||
_raycastInfo.proxyShape = _proxyShape;
|
||||
_raycastInfo.hitFraction = t;
|
||||
_raycastInfo.worldPoint = localHitPoint[hitIndex];
|
||||
_raycastInfo.worldNormal = localNormal[hitIndex];
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return the radius
|
||||
/**
|
||||
* @return Radius of the cone (in meters)
|
||||
*/
|
||||
float ConeShape::getRadius() const {
|
||||
return m_radius;
|
||||
}
|
||||
|
||||
// Return the height
|
||||
/**
|
||||
* @return Height of the cone (in meters)
|
||||
*/
|
||||
float ConeShape::getHeight() const {
|
||||
return float(2.0) * m_halfHeight;
|
||||
}
|
||||
|
||||
// Set the scaling vector of the collision shape
|
||||
void ConeShape::setLocalScaling(const vec3& scaling) {
|
||||
|
||||
m_halfHeight = (m_halfHeight / m_scaling.y()) * scaling.y();
|
||||
m_radius = (m_radius / m_scaling.x()) * scaling.x();
|
||||
|
||||
CollisionShape::setLocalScaling(scaling);
|
||||
void ConeShape::setLocalScaling(const vec3& _scaling) {
|
||||
m_halfHeight = (m_halfHeight / m_scaling.y()) * _scaling.y();
|
||||
m_radius = (m_radius / m_scaling.x()) * _scaling.x();
|
||||
CollisionShape::setLocalScaling(_scaling);
|
||||
}
|
||||
|
||||
// Return the number of bytes used by the collision shape
|
||||
size_t ConeShape::getSizeInBytes() const {
|
||||
return sizeof(ConeShape);
|
||||
}
|
||||
|
||||
// Return the local bounds of the shape in x, y and z directions
|
||||
/**
|
||||
* @param min The minimum bounds of the shape in local-space coordinates
|
||||
* @param max The maximum bounds of the shape in local-space coordinates
|
||||
*/
|
||||
void ConeShape::getLocalBounds(vec3& min, vec3& max) const {
|
||||
|
||||
void ConeShape::getLocalBounds(vec3& _min, vec3& _max) const {
|
||||
// Maximum bounds
|
||||
max.setX(m_radius + m_margin);
|
||||
max.setY(m_halfHeight + m_margin);
|
||||
max.setZ(max.x());
|
||||
|
||||
_max.setX(m_radius + m_margin);
|
||||
_max.setY(m_halfHeight + m_margin);
|
||||
_max.setZ(_max.x());
|
||||
// Minimum bounds
|
||||
min.setX(-max.x());
|
||||
min.setY(-max.y());
|
||||
min.setZ(min.x());
|
||||
_min.setX(-_max.x());
|
||||
_min.setY(-_max.y());
|
||||
_min.setZ(_min.x());
|
||||
}
|
||||
|
||||
// Return the local inertia tensor of the collision shape
|
||||
/**
|
||||
* @param[out] tensor The 3x3 inertia tensor matrix of the shape in local-space
|
||||
* coordinates
|
||||
* @param mass Mass to use to compute the inertia tensor of the collision shape
|
||||
*/
|
||||
void ConeShape::computeLocalInertiaTensor(etk::Matrix3x3& tensor, float mass) const {
|
||||
void ConeShape::computeLocalInertiaTensor(etk::Matrix3x3& _tensor, float _mass) const {
|
||||
float rSquare = m_radius * m_radius;
|
||||
float diagXZ = float(0.15) * mass * (rSquare + m_halfHeight);
|
||||
tensor.setValue(diagXZ, 0.0, 0.0,
|
||||
0.0, float(0.3) * mass * rSquare,
|
||||
0.0, 0.0, 0.0, diagXZ);
|
||||
float diagXZ = float(0.15) * _mass * (rSquare + m_halfHeight);
|
||||
_tensor.setValue(diagXZ, 0.0, 0.0,
|
||||
0.0, float(0.3) * _mass * rSquare,
|
||||
0.0, 0.0, 0.0, diagXZ);
|
||||
}
|
||||
|
||||
// Return true if a point is inside the collision shape
|
||||
bool ConeShape::testPointInside(const vec3& localPoint, ProxyShape* proxyShape) const {
|
||||
const float radiusHeight = m_radius * (-localPoint.y() + m_halfHeight) /
|
||||
(m_halfHeight * float(2.0));
|
||||
return (localPoint.y() < m_halfHeight && localPoint.y() > -m_halfHeight) &&
|
||||
(localPoint.x() * localPoint.x() + localPoint.z() * localPoint.z() < radiusHeight *radiusHeight);
|
||||
bool ConeShape::testPointInside(const vec3& _localPoint, ProxyShape* _proxyShape) const {
|
||||
const float radiusHeight = m_radius
|
||||
* (-_localPoint.y() + m_halfHeight)
|
||||
/ (m_halfHeight * float(2.0));
|
||||
return ( _localPoint.y() < m_halfHeight
|
||||
&& _localPoint.y() > -m_halfHeight)
|
||||
&& (_localPoint.x() * _localPoint.x() + _localPoint.z() * _localPoint.z() < radiusHeight *radiusHeight);
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -25,24 +28,36 @@ namespace ephysics {
|
||||
* default margin distance by not using the "margin" parameter in the constructor.
|
||||
*/
|
||||
class ConeShape : public ConvexShape {
|
||||
public :
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param _radius Radius of the cone (in meters)
|
||||
* @param _height Height of the cone (in meters)
|
||||
* @param _margin Collision margin (in meters) around the collision shape
|
||||
*/
|
||||
ConeShape(float _radius, float _height, float _margin = OBJECT_MARGIN);
|
||||
/// DELETE copy-constructor
|
||||
ConeShape(const ConeShape& _shape) = delete;
|
||||
/// DELETE assignment operator
|
||||
ConeShape& operator=(const ConeShape& _shape) = delete;
|
||||
protected :
|
||||
float m_radius; //!< Radius of the base
|
||||
float m_halfHeight; //!< Half height of the cone
|
||||
float m_sinTheta; //!< sine of the semi angle at the apex point
|
||||
/// Private copy-constructor
|
||||
ConeShape(const ConeShape& _shape) = delete;
|
||||
/// Private assignment operator
|
||||
ConeShape& operator=(const ConeShape& _shape) = delete;
|
||||
virtual vec3 getLocalSupportPointWithoutMargin(const vec3& _direction, void** _cachedCollisionData) const override;
|
||||
bool testPointInside(const vec3& _localPoint, ProxyShape* _proxyShape) const override;
|
||||
bool raycast(const Ray& _ray, RaycastInfo& _raycastInfo, ProxyShape* _proxyShape) const override;
|
||||
size_t getSizeInBytes() const override;
|
||||
public :
|
||||
/// Constructor
|
||||
ConeShape(float _radius, float _height, float _margin = OBJECT_MARGIN);
|
||||
/// Return the radius
|
||||
public:
|
||||
/**
|
||||
* @brief Return the radius
|
||||
* @return Radius of the cone (in meters)
|
||||
*/
|
||||
float getRadius() const;
|
||||
/// Return the height
|
||||
/**
|
||||
* @brief Return the height
|
||||
* @return Height of the cone (in meters)
|
||||
*/
|
||||
float getHeight() const;
|
||||
|
||||
void setLocalScaling(const vec3& _scaling) override;
|
||||
|
@ -1,31 +1,41 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <ephysics/configuration.hpp>
|
||||
#include <ephysics/collision/shapes/ConvexMeshShape.hpp>
|
||||
|
||||
using namespace ephysics;
|
||||
|
||||
ConvexMeshShape::ConvexMeshShape(const float* arrayVertices, uint32_t nbVertices, int32_t stride, float margin)
|
||||
: ConvexShape(CONVEX_MESH, margin), m_numberVertices(nbVertices), m_minBounds(0, 0, 0),
|
||||
m_maxBounds(0, 0, 0), m_isEdgesInformationUsed(false) {
|
||||
assert(nbVertices > 0);
|
||||
assert(stride > 0);
|
||||
const unsigned char* vertexPointer = (const unsigned char*) arrayVertices;
|
||||
ConvexMeshShape::ConvexMeshShape(const float* _arrayVertices,
|
||||
uint32_t _nbVertices,
|
||||
int32_t _stride,
|
||||
float _margin):
|
||||
ConvexShape(CONVEX_MESH, _margin),
|
||||
m_numberVertices(_nbVertices),
|
||||
m_minBounds(0, 0, 0),
|
||||
m_maxBounds(0, 0, 0),
|
||||
m_isEdgesInformationUsed(false) {
|
||||
assert(_nbVertices > 0);
|
||||
assert(_stride > 0);
|
||||
const unsigned char* vertexPointer = (const unsigned char*) _arrayVertices;
|
||||
// Copy all the vertices int32_to the int32_ternal array
|
||||
for (uint32_t i=0; i<m_numberVertices; i++) {
|
||||
for (uint32_t iii=0; iii<m_numberVertices; iii++) {
|
||||
const float* newPoint = (const float*) vertexPointer;
|
||||
m_vertices.pushBack(vec3(newPoint[0], newPoint[1], newPoint[2]));
|
||||
vertexPointer += stride;
|
||||
vertexPointer += _stride;
|
||||
}
|
||||
// Recalculate the bounds of the mesh
|
||||
recalculateBounds();
|
||||
}
|
||||
|
||||
ConvexMeshShape::ConvexMeshShape(TriangleVertexArray* _triangleVertexArray, bool _isEdgesInformationUsed, float _margin):
|
||||
ConvexMeshShape::ConvexMeshShape(TriangleVertexArray* _triangleVertexArray,
|
||||
bool _isEdgesInformationUsed,
|
||||
float _margin):
|
||||
ConvexShape(CONVEX_MESH, _margin),
|
||||
m_minBounds(0, 0, 0),
|
||||
m_maxBounds(0, 0, 0),
|
||||
@ -52,9 +62,6 @@ ConvexMeshShape::ConvexMeshShape(TriangleVertexArray* _triangleVertexArray, bool
|
||||
recalculateBounds();
|
||||
}
|
||||
|
||||
// Constructor.
|
||||
/// If you use this constructor, you will need to set the vertices manually one by one using
|
||||
/// the addVertex() method.
|
||||
ConvexMeshShape::ConvexMeshShape(float _margin):
|
||||
ConvexShape(CONVEX_MESH, _margin),
|
||||
m_numberVertices(0),
|
||||
@ -64,11 +71,12 @@ ConvexMeshShape::ConvexMeshShape(float _margin):
|
||||
|
||||
}
|
||||
|
||||
vec3 ConvexMeshShape::getLocalSupportPointWithoutMargin(const vec3& _direction, void** _cachedCollisionData) const {
|
||||
vec3 ConvexMeshShape::getLocalSupportPointWithoutMargin(const vec3& _direction,
|
||||
void** _cachedCollisionData) const {
|
||||
assert(m_numberVertices == m_vertices.size());
|
||||
assert(_cachedCollisionData != nullptr);
|
||||
assert(_cachedCollisionData != null);
|
||||
// Allocate memory for the cached collision data if not allocated yet
|
||||
if ((*_cachedCollisionData) == nullptr) {
|
||||
if ((*_cachedCollisionData) == null) {
|
||||
*_cachedCollisionData = (int32_t*) malloc(sizeof(int32_t));
|
||||
*((int32_t*)(*_cachedCollisionData)) = 0;
|
||||
}
|
||||
@ -156,12 +164,12 @@ void ConvexMeshShape::recalculateBounds() {
|
||||
m_minBounds -= vec3(m_margin, m_margin, m_margin);
|
||||
}
|
||||
|
||||
bool ConvexMeshShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const {
|
||||
return proxyShape->m_body->m_world.m_collisionDetection.m_narrowPhaseGJKAlgorithm.raycast(ray, proxyShape, raycastInfo);
|
||||
bool ConvexMeshShape::raycast(const Ray& _ray, RaycastInfo& _raycastInfo, ProxyShape* _proxyShape) const {
|
||||
return _proxyShape->m_body->m_world.m_collisionDetection.m_narrowPhaseGJKAlgorithm.raycast(_ray, _proxyShape, _raycastInfo);
|
||||
}
|
||||
|
||||
void ConvexMeshShape::setLocalScaling(const vec3& scaling) {
|
||||
ConvexShape::setLocalScaling(scaling);
|
||||
void ConvexMeshShape::setLocalScaling(const vec3& _scaling) {
|
||||
ConvexShape::setLocalScaling(_scaling);
|
||||
recalculateBounds();
|
||||
}
|
||||
|
||||
@ -169,73 +177,72 @@ size_t ConvexMeshShape::getSizeInBytes() const {
|
||||
return sizeof(ConvexMeshShape);
|
||||
}
|
||||
|
||||
void ConvexMeshShape::getLocalBounds(vec3& min, vec3& max) const {
|
||||
min = m_minBounds;
|
||||
max = m_maxBounds;
|
||||
void ConvexMeshShape::getLocalBounds(vec3& _min, vec3& _max) const {
|
||||
_min = m_minBounds;
|
||||
_max = m_maxBounds;
|
||||
}
|
||||
|
||||
void ConvexMeshShape::computeLocalInertiaTensor(etk::Matrix3x3& tensor, float mass) const {
|
||||
float factor = (1.0f / float(3.0)) * mass;
|
||||
void ConvexMeshShape::computeLocalInertiaTensor(etk::Matrix3x3& _tensor, float _mass) const {
|
||||
float factor = (1.0f / float(3.0)) * _mass;
|
||||
vec3 realExtent = 0.5f * (m_maxBounds - m_minBounds);
|
||||
assert(realExtent.x() > 0 && realExtent.y() > 0 && realExtent.z() > 0);
|
||||
float xSquare = realExtent.x() * realExtent.x();
|
||||
float ySquare = realExtent.y() * realExtent.y();
|
||||
float zSquare = realExtent.z() * realExtent.z();
|
||||
tensor.setValue(factor * (ySquare + zSquare), 0.0, 0.0,
|
||||
0.0, factor * (xSquare + zSquare), 0.0,
|
||||
0.0, 0.0, factor * (xSquare + ySquare));
|
||||
_tensor.setValue(factor * (ySquare + zSquare), 0.0, 0.0,
|
||||
0.0, factor * (xSquare + zSquare), 0.0,
|
||||
0.0, 0.0, factor * (xSquare + ySquare));
|
||||
}
|
||||
|
||||
void ConvexMeshShape::addVertex(const vec3& vertex) {
|
||||
void ConvexMeshShape::addVertex(const vec3& _vertex) {
|
||||
// Add the vertex in to vertices array
|
||||
m_vertices.pushBack(vertex);
|
||||
m_vertices.pushBack(_vertex);
|
||||
m_numberVertices++;
|
||||
// Update the bounds of the mesh
|
||||
if (vertex.x() * m_scaling.x() > m_maxBounds.x()) {
|
||||
m_maxBounds.setX(vertex.x() * m_scaling.x());
|
||||
if (_vertex.x() * m_scaling.x() > m_maxBounds.x()) {
|
||||
m_maxBounds.setX(_vertex.x() * m_scaling.x());
|
||||
}
|
||||
if (vertex.x() * m_scaling.x() < m_minBounds.x()) {
|
||||
m_minBounds.setX(vertex.x() * m_scaling.x());
|
||||
if (_vertex.x() * m_scaling.x() < m_minBounds.x()) {
|
||||
m_minBounds.setX(_vertex.x() * m_scaling.x());
|
||||
}
|
||||
if (vertex.y() * m_scaling.y() > m_maxBounds.y()) {
|
||||
m_maxBounds.setY(vertex.y() * m_scaling.y());
|
||||
if (_vertex.y() * m_scaling.y() > m_maxBounds.y()) {
|
||||
m_maxBounds.setY(_vertex.y() * m_scaling.y());
|
||||
}
|
||||
if (vertex.y() * m_scaling.y() < m_minBounds.y()) {
|
||||
m_minBounds.setY(vertex.y() * m_scaling.y());
|
||||
if (_vertex.y() * m_scaling.y() < m_minBounds.y()) {
|
||||
m_minBounds.setY(_vertex.y() * m_scaling.y());
|
||||
}
|
||||
if (vertex.z() * m_scaling.z() > m_maxBounds.z()) {
|
||||
m_maxBounds.setZ(vertex.z() * m_scaling.z());
|
||||
if (_vertex.z() * m_scaling.z() > m_maxBounds.z()) {
|
||||
m_maxBounds.setZ(_vertex.z() * m_scaling.z());
|
||||
}
|
||||
if (vertex.z() * m_scaling.z() < m_minBounds.z()) {
|
||||
m_minBounds.setZ(vertex.z() * m_scaling.z());
|
||||
if (_vertex.z() * m_scaling.z() < m_minBounds.z()) {
|
||||
m_minBounds.setZ(_vertex.z() * m_scaling.z());
|
||||
}
|
||||
}
|
||||
|
||||
void ConvexMeshShape::addEdge(uint32_t v1, uint32_t v2) {
|
||||
void ConvexMeshShape::addEdge(uint32_t _v1, uint32_t _v2) {
|
||||
// If the entry for vertex v1 does not exist in the adjacency list
|
||||
if (m_edgesAdjacencyList.count(v1) == 0) {
|
||||
m_edgesAdjacencyList.add(v1, etk::Set<uint32_t>());
|
||||
if (m_edgesAdjacencyList.count(_v1) == 0) {
|
||||
m_edgesAdjacencyList.add(_v1, etk::Set<uint32_t>());
|
||||
}
|
||||
// If the entry for vertex v2 does not exist in the adjacency list
|
||||
if (m_edgesAdjacencyList.count(v2) == 0) {
|
||||
m_edgesAdjacencyList.add(v2, etk::Set<uint32_t>());
|
||||
if (m_edgesAdjacencyList.count(_v2) == 0) {
|
||||
m_edgesAdjacencyList.add(_v2, etk::Set<uint32_t>());
|
||||
}
|
||||
// Add the edge in the adjacency list
|
||||
m_edgesAdjacencyList[v1].add(v2);
|
||||
m_edgesAdjacencyList[v2].add(v1);
|
||||
m_edgesAdjacencyList[_v1].add(_v2);
|
||||
m_edgesAdjacencyList[_v2].add(_v1);
|
||||
}
|
||||
|
||||
bool ConvexMeshShape::isEdgesInformationUsed() const {
|
||||
return m_isEdgesInformationUsed;
|
||||
}
|
||||
|
||||
void ConvexMeshShape::setIsEdgesInformationUsed(bool isEdgesUsed) {
|
||||
m_isEdgesInformationUsed = isEdgesUsed;
|
||||
void ConvexMeshShape::setIsEdgesInformationUsed(bool _isEdgesUsed) {
|
||||
m_isEdgesInformationUsed = _isEdgesUsed;
|
||||
}
|
||||
|
||||
bool ConvexMeshShape::testPointInside(const vec3& localPoint,
|
||||
ProxyShape* proxyShape) const {
|
||||
bool ConvexMeshShape::testPointInside(const vec3& _localPoint,
|
||||
ProxyShape* _proxyShape) const {
|
||||
// Use the GJK algorithm to test if the point is inside the convex mesh
|
||||
return proxyShape->m_body->m_world.m_collisionDetection.
|
||||
m_narrowPhaseGJKAlgorithm.testPointInside(localPoint, proxyShape);
|
||||
return _proxyShape->m_body->m_world.m_collisionDetection.m_narrowPhaseGJKAlgorithm.testPointInside(_localPoint, _proxyShape);
|
||||
}
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -51,7 +54,7 @@ namespace ephysics {
|
||||
size_t getSizeInBytes() const override;
|
||||
public :
|
||||
/**
|
||||
* @brief Constructor to initialize with an array of 3D vertices.
|
||||
* @brief Constructor to initialize with an array of 3D vertices.
|
||||
* This method creates an int32_ternal copy of the input vertices.
|
||||
* @param[in] _arrayVertices Array with the vertices of the convex mesh
|
||||
* @param[in] _nbVertices Number of vertices in the convex mesh
|
||||
@ -72,8 +75,12 @@ namespace ephysics {
|
||||
ConvexMeshShape(TriangleVertexArray* _triangleVertexArray,
|
||||
bool _isEdgesInformationUsed = true,
|
||||
float _margin = OBJECT_MARGIN);
|
||||
/// Constructor.
|
||||
/**
|
||||
* @brief Constructor.
|
||||
* If you use this constructor, you will need to set the vertices manually one by one using the addVertex() method.
|
||||
*/
|
||||
ConvexMeshShape(float _margin = OBJECT_MARGIN);
|
||||
public:
|
||||
void getLocalBounds(vec3& _min, vec3& _max) const override;
|
||||
void computeLocalInertiaTensor(etk::Matrix3x3& _tensor, float _mass) const override;
|
||||
/**
|
||||
@ -83,7 +90,7 @@ namespace ephysics {
|
||||
void addVertex(const vec3& _vertex);
|
||||
/**
|
||||
* @brief Add an edge int32_to the convex mesh by specifying the two vertex indices of the edge.
|
||||
* Note that the vertex indices start at zero and need to correspond to the order of
|
||||
* @note that the vertex indices start at zero and need to correspond to the order of
|
||||
* the vertices in the vertices array in the constructor or the order of the calls
|
||||
* of the addVertex() methods that you use to add vertices int32_to the convex mesh.
|
||||
* @param[in] _v1 Index of the first vertex of the edge to add
|
||||
|
@ -1,9 +1,11 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <ephysics/collision/shapes/ConvexShape.hpp>
|
||||
|
||||
ephysics::ConvexShape::ConvexShape(ephysics::CollisionShapeType _type, float _margin):
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -11,23 +14,24 @@ namespace ephysics {
|
||||
* @brief It represents a convex collision shape associated with a
|
||||
* body that is used during the narrow-phase collision detection.
|
||||
*/
|
||||
class ConvexShape : public CollisionShape {
|
||||
protected :
|
||||
class ConvexShape: public CollisionShape {
|
||||
protected:
|
||||
float m_margin; //!< Margin used for the GJK collision detection algorithm
|
||||
/// Private copy-constructor
|
||||
ConvexShape(const ConvexShape& shape) = delete;
|
||||
ConvexShape(const ConvexShape& _shape) = delete;
|
||||
/// Private assignment operator
|
||||
ConvexShape& operator=(const ConvexShape& shape) = delete;
|
||||
ConvexShape& operator=(const ConvexShape& _shape) = delete;
|
||||
// Return a local support point in a given direction with the object margin
|
||||
virtual vec3 getLocalSupportPointWithMargin(const vec3& _direction, void** _cachedCollisionData) const;
|
||||
/// Return a local support point in a given direction without the object margin
|
||||
virtual vec3 getLocalSupportPointWithoutMargin(const vec3& _direction, void** _cachedCollisionData) const=0;
|
||||
bool testPointInside(const vec3& _worldPoint, ProxyShape* _proxyShape) const override = 0;
|
||||
public :
|
||||
public:
|
||||
/// Constructor
|
||||
ConvexShape(CollisionShapeType type, float margin);
|
||||
ConvexShape(CollisionShapeType _type, float _margin);
|
||||
/// Destructor
|
||||
virtual ~ConvexShape();
|
||||
public:
|
||||
/**
|
||||
* @brief Get the current object margin
|
||||
* @return The margin (in meters) around the collision shape
|
||||
|
@ -1,30 +1,27 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <ephysics/collision/shapes/CylinderShape.hpp>
|
||||
#include <ephysics/collision/ProxyShape.hpp>
|
||||
#include <ephysics/configuration.hpp>
|
||||
|
||||
using namespace ephysics;
|
||||
|
||||
/**
|
||||
* @param radius Radius of the cylinder (in meters)
|
||||
* @param height Height of the cylinder (in meters)
|
||||
* @param margin Collision margin (in meters) around the collision shape
|
||||
*/
|
||||
CylinderShape::CylinderShape(float radius, float height, float margin)
|
||||
: ConvexShape(CYLINDER, margin), mRadius(radius),
|
||||
m_halfHeight(height/float(2.0)) {
|
||||
assert(radius > 0.0f);
|
||||
assert(height > 0.0f);
|
||||
CylinderShape::CylinderShape(float _radius,
|
||||
float _height,
|
||||
float _margin):
|
||||
ConvexShape(CYLINDER, _margin), m_radius(_radius), m_halfHeight(_height/float(2.0)) {
|
||||
assert(_radius > 0.0f);
|
||||
assert(_height > 0.0f);
|
||||
}
|
||||
|
||||
|
||||
// Return a local support point in a given direction without the object margin
|
||||
vec3 CylinderShape::getLocalSupportPointWithoutMargin(const vec3& _direction, void** _cachedCollisionData) const {
|
||||
vec3 CylinderShape::getLocalSupportPointWithoutMargin(const vec3& _direction,
|
||||
void** _cachedCollisionData) const {
|
||||
vec3 supportPoint(0.0, 0.0, 0.0);
|
||||
float uDotv = _direction.y();
|
||||
vec3 w(_direction.x(), 0.0, _direction.z());
|
||||
@ -35,7 +32,7 @@ vec3 CylinderShape::getLocalSupportPointWithoutMargin(const vec3& _direction, vo
|
||||
} else {
|
||||
supportPoint.setY(m_halfHeight);
|
||||
}
|
||||
supportPoint += (mRadius / lengthW) * w;
|
||||
supportPoint += (m_radius / lengthW) * w;
|
||||
} else {
|
||||
if (uDotv < 0.0) {
|
||||
supportPoint.setY(-m_halfHeight);
|
||||
@ -46,234 +43,196 @@ vec3 CylinderShape::getLocalSupportPointWithoutMargin(const vec3& _direction, vo
|
||||
return supportPoint;
|
||||
}
|
||||
|
||||
// Raycast method with feedback information
|
||||
/// Algorithm based on the one described at page 194 in Real-ime Collision Detection by
|
||||
/// Morgan Kaufmann.
|
||||
bool CylinderShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const {
|
||||
|
||||
const vec3 n = ray.point2 - ray.point1;
|
||||
|
||||
bool CylinderShape::raycast(const Ray& _ray, RaycastInfo& _raycastInfo, ProxyShape* _proxyShape) const {
|
||||
const vec3 n = _ray.point2 - _ray.point1;
|
||||
const float epsilon = float(0.01);
|
||||
vec3 p(float(0), -m_halfHeight, float(0));
|
||||
vec3 q(float(0), m_halfHeight, float(0));
|
||||
vec3 d = q - p;
|
||||
vec3 m = ray.point1 - p;
|
||||
vec3 m = _ray.point1 - p;
|
||||
float t;
|
||||
|
||||
float mDotD = m.dot(d);
|
||||
float nDotD = n.dot(d);
|
||||
float dDotD = d.dot(d);
|
||||
|
||||
// Test if the segment is outside the cylinder
|
||||
if (mDotD < 0.0f && mDotD + nDotD < float(0.0)) return false;
|
||||
if (mDotD > dDotD && mDotD + nDotD > dDotD) return false;
|
||||
|
||||
if (mDotD < 0.0f && mDotD + nDotD < float(0.0)) {
|
||||
return false;
|
||||
}
|
||||
if (mDotD > dDotD && mDotD + nDotD > dDotD) {
|
||||
return false;
|
||||
}
|
||||
float nDotN = n.dot(n);
|
||||
float mDotN = m.dot(n);
|
||||
|
||||
float a = dDotD * nDotN - nDotD * nDotD;
|
||||
float k = m.dot(m) - mRadius * mRadius;
|
||||
float k = m.dot(m) - m_radius * m_radius;
|
||||
float c = dDotD * k - mDotD * mDotD;
|
||||
|
||||
// If the ray is parallel to the cylinder axis
|
||||
if (etk::abs(a) < epsilon) {
|
||||
|
||||
// If the origin is outside the surface of the cylinder, we return no hit
|
||||
if (c > 0.0f) return false;
|
||||
|
||||
// Here we know that the segment int32_tersect an endcap of the cylinder
|
||||
|
||||
// If the ray int32_tersects with the "p" endcap of the cylinder
|
||||
if (mDotD < 0.0f) {
|
||||
|
||||
t = -mDotN / nDotN;
|
||||
|
||||
// If the int32_tersection is behind the origin of the ray or beyond the maximum
|
||||
// raycasting distance, we return no hit
|
||||
if (t < 0.0f || t > ray.maxFraction) return false;
|
||||
|
||||
// Compute the hit information
|
||||
vec3 localHitPoint = ray.point1 + t * n;
|
||||
raycastInfo.body = proxyShape->getBody();
|
||||
raycastInfo.proxyShape = proxyShape;
|
||||
raycastInfo.hitFraction = t;
|
||||
raycastInfo.worldPoint = localHitPoint;
|
||||
vec3 normalDirection(0, float(-1), 0);
|
||||
raycastInfo.worldNormal = normalDirection;
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (mDotD > dDotD) { // If the ray int32_tersects with the "q" endcap of the cylinder
|
||||
|
||||
t = (nDotD - mDotN) / nDotN;
|
||||
|
||||
// If the int32_tersection is behind the origin of the ray or beyond the maximum
|
||||
// raycasting distance, we return no hit
|
||||
if (t < 0.0f || t > ray.maxFraction) return false;
|
||||
|
||||
// Compute the hit information
|
||||
vec3 localHitPoint = ray.point1 + t * n;
|
||||
raycastInfo.body = proxyShape->getBody();
|
||||
raycastInfo.proxyShape = proxyShape;
|
||||
raycastInfo.hitFraction = t;
|
||||
raycastInfo.worldPoint = localHitPoint;
|
||||
vec3 normalDirection(0, 1.0f, 0);
|
||||
raycastInfo.worldNormal = normalDirection;
|
||||
|
||||
return true;
|
||||
}
|
||||
else { // If the origin is inside the cylinder, we return no hit
|
||||
if (c > 0.0f) {
|
||||
return false;
|
||||
}
|
||||
// Here we know that the segment int32_tersect an endcap of the cylinder
|
||||
// If the ray int32_tersects with the "p" endcap of the cylinder
|
||||
if (mDotD < 0.0f) {
|
||||
t = -mDotN / nDotN;
|
||||
// If the int32_tersection is behind the origin of the ray or beyond the maximum
|
||||
// raycasting distance, we return no hit
|
||||
if (t < 0.0f || t > _ray.maxFraction) {
|
||||
return false;
|
||||
}
|
||||
// Compute the hit information
|
||||
vec3 localHitPoint = _ray.point1 + t * n;
|
||||
_raycastInfo.body = _proxyShape->getBody();
|
||||
_raycastInfo.proxyShape = _proxyShape;
|
||||
_raycastInfo.hitFraction = t;
|
||||
_raycastInfo.worldPoint = localHitPoint;
|
||||
vec3 normalDirection(0, float(-1), 0);
|
||||
_raycastInfo.worldNormal = normalDirection;
|
||||
return true;
|
||||
}
|
||||
// If the ray int32_tersects with the "q" endcap of the cylinder
|
||||
if (mDotD > dDotD) {
|
||||
t = (nDotD - mDotN) / nDotN;
|
||||
// If the int32_tersection is behind the origin of the ray or beyond the maximum
|
||||
// raycasting distance, we return no hit
|
||||
if (t < 0.0f || t > _ray.maxFraction) {
|
||||
return false;
|
||||
}
|
||||
// Compute the hit information
|
||||
vec3 localHitPoint = _ray.point1 + t * n;
|
||||
_raycastInfo.body = _proxyShape->getBody();
|
||||
_raycastInfo.proxyShape = _proxyShape;
|
||||
_raycastInfo.hitFraction = t;
|
||||
_raycastInfo.worldPoint = localHitPoint;
|
||||
vec3 normalDirection(0, 1.0f, 0);
|
||||
_raycastInfo.worldNormal = normalDirection;
|
||||
return true;
|
||||
}
|
||||
// If the origin is inside the cylinder, we return no hit
|
||||
return false;
|
||||
}
|
||||
float b = dDotD * mDotN - nDotD * mDotD;
|
||||
float discriminant = b * b - a * c;
|
||||
|
||||
// If the discriminant is negative, no real roots and therfore, no hit
|
||||
if (discriminant < 0.0f) return false;
|
||||
|
||||
if (discriminant < 0.0f) {
|
||||
return false;
|
||||
}
|
||||
// Compute the smallest root (first int32_tersection along the ray)
|
||||
float t0 = t = (-b - etk::sqrt(discriminant)) / a;
|
||||
|
||||
// If the int32_tersection is outside the cylinder on "p" endcap side
|
||||
float value = mDotD + t * nDotD;
|
||||
if (value < 0.0f) {
|
||||
|
||||
// If the ray is pointing away from the "p" endcap, we return no hit
|
||||
if (nDotD <= 0.0f) return false;
|
||||
|
||||
if (nDotD <= 0.0f) {
|
||||
return false;
|
||||
}
|
||||
// Compute the int32_tersection against the "p" endcap (int32_tersection agains whole plane)
|
||||
t = -mDotD / nDotD;
|
||||
|
||||
// Keep the int32_tersection if the it is inside the cylinder radius
|
||||
if (k + t * (float(2.0) * mDotN + t) > 0.0f) return false;
|
||||
|
||||
if (k + t * (float(2.0) * mDotN + t) > 0.0f) {
|
||||
return false;
|
||||
}
|
||||
// If the int32_tersection is behind the origin of the ray or beyond the maximum
|
||||
// raycasting distance, we return no hit
|
||||
if (t < 0.0f || t > ray.maxFraction) return false;
|
||||
|
||||
if (t < 0.0f || t > _ray.maxFraction) {
|
||||
return false;
|
||||
}
|
||||
// Compute the hit information
|
||||
vec3 localHitPoint = ray.point1 + t * n;
|
||||
raycastInfo.body = proxyShape->getBody();
|
||||
raycastInfo.proxyShape = proxyShape;
|
||||
raycastInfo.hitFraction = t;
|
||||
raycastInfo.worldPoint = localHitPoint;
|
||||
vec3 localHitPoint = _ray.point1 + t * n;
|
||||
_raycastInfo.body = _proxyShape->getBody();
|
||||
_raycastInfo.proxyShape = _proxyShape;
|
||||
_raycastInfo.hitFraction = t;
|
||||
_raycastInfo.worldPoint = localHitPoint;
|
||||
vec3 normalDirection(0, float(-1.0), 0);
|
||||
raycastInfo.worldNormal = normalDirection;
|
||||
|
||||
_raycastInfo.worldNormal = normalDirection;
|
||||
return true;
|
||||
}
|
||||
else if (value > dDotD) { // If the int32_tersection is outside the cylinder on the "q" side
|
||||
|
||||
// If the int32_tersection is outside the cylinder on the "q" side
|
||||
if (value > dDotD) {
|
||||
// If the ray is pointing away from the "q" endcap, we return no hit
|
||||
if (nDotD >= 0.0f) return false;
|
||||
|
||||
if (nDotD >= 0.0f) {
|
||||
return false;
|
||||
}
|
||||
// Compute the int32_tersection against the "q" endcap (int32_tersection against whole plane)
|
||||
t = (dDotD - mDotD) / nDotD;
|
||||
|
||||
// Keep the int32_tersection if it is inside the cylinder radius
|
||||
if (k + dDotD - float(2.0) * mDotD + t * (float(2.0) * (mDotN - nDotD) + t) >
|
||||
0.0f) return false;
|
||||
|
||||
if (k + dDotD - float(2.0) * mDotD + t * (float(2.0) * (mDotN - nDotD) + t) > 0.0f) {
|
||||
return false;
|
||||
}
|
||||
// If the int32_tersection is behind the origin of the ray or beyond the maximum
|
||||
// raycasting distance, we return no hit
|
||||
if (t < 0.0f || t > ray.maxFraction) return false;
|
||||
|
||||
if (t < 0.0f || t > _ray.maxFraction) {
|
||||
return false;
|
||||
}
|
||||
// Compute the hit information
|
||||
vec3 localHitPoint = ray.point1 + t * n;
|
||||
raycastInfo.body = proxyShape->getBody();
|
||||
raycastInfo.proxyShape = proxyShape;
|
||||
raycastInfo.hitFraction = t;
|
||||
raycastInfo.worldPoint = localHitPoint;
|
||||
vec3 localHitPoint = _ray.point1 + t * n;
|
||||
_raycastInfo.body = _proxyShape->getBody();
|
||||
_raycastInfo.proxyShape = _proxyShape;
|
||||
_raycastInfo.hitFraction = t;
|
||||
_raycastInfo.worldPoint = localHitPoint;
|
||||
vec3 normalDirection(0, 1.0f, 0);
|
||||
raycastInfo.worldNormal = normalDirection;
|
||||
|
||||
_raycastInfo.worldNormal = normalDirection;
|
||||
return true;
|
||||
}
|
||||
|
||||
t = t0;
|
||||
|
||||
// If the int32_tersection is behind the origin of the ray or beyond the maximum
|
||||
// raycasting distance, we return no hit
|
||||
if (t < 0.0f || t > ray.maxFraction) return false;
|
||||
|
||||
if (t < 0.0f || t > _ray.maxFraction) {
|
||||
return false;
|
||||
}
|
||||
// Compute the hit information
|
||||
vec3 localHitPoint = ray.point1 + t * n;
|
||||
raycastInfo.body = proxyShape->getBody();
|
||||
raycastInfo.proxyShape = proxyShape;
|
||||
raycastInfo.hitFraction = t;
|
||||
raycastInfo.worldPoint = localHitPoint;
|
||||
vec3 localHitPoint = _ray.point1 + t * n;
|
||||
_raycastInfo.body = _proxyShape->getBody();
|
||||
_raycastInfo.proxyShape = _proxyShape;
|
||||
_raycastInfo.hitFraction = t;
|
||||
_raycastInfo.worldPoint = localHitPoint;
|
||||
vec3 v = localHitPoint - p;
|
||||
vec3 w = (v.dot(d) / d.length2()) * d;
|
||||
vec3 normalDirection = (localHitPoint - (p + w));
|
||||
raycastInfo.worldNormal = normalDirection;
|
||||
|
||||
_raycastInfo.worldNormal = normalDirection;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return the radius
|
||||
/**
|
||||
* @return Radius of the cylinder (in meters)
|
||||
*/
|
||||
float CylinderShape::getRadius() const {
|
||||
return mRadius;
|
||||
return m_radius;
|
||||
}
|
||||
|
||||
// Return the height
|
||||
/**
|
||||
* @return Height of the cylinder (in meters)
|
||||
*/
|
||||
float CylinderShape::getHeight() const {
|
||||
return m_halfHeight + m_halfHeight;
|
||||
}
|
||||
|
||||
// Set the scaling vector of the collision shape
|
||||
void CylinderShape::setLocalScaling(const vec3& scaling) {
|
||||
|
||||
m_halfHeight = (m_halfHeight / m_scaling.y()) * scaling.y();
|
||||
mRadius = (mRadius / m_scaling.x()) * scaling.x();
|
||||
|
||||
CollisionShape::setLocalScaling(scaling);
|
||||
void CylinderShape::setLocalScaling(const vec3& _scaling) {
|
||||
m_halfHeight = (m_halfHeight / m_scaling.y()) * _scaling.y();
|
||||
m_radius = (m_radius / m_scaling.x()) * _scaling.x();
|
||||
CollisionShape::setLocalScaling(_scaling);
|
||||
}
|
||||
|
||||
// Return the number of bytes used by the collision shape
|
||||
size_t CylinderShape::getSizeInBytes() const {
|
||||
return sizeof(CylinderShape);
|
||||
}
|
||||
|
||||
// Return the local bounds of the shape in x, y and z directions
|
||||
/**
|
||||
* @param min The minimum bounds of the shape in local-space coordinates
|
||||
* @param max The maximum bounds of the shape in local-space coordinates
|
||||
*/
|
||||
void CylinderShape::getLocalBounds(vec3& min, vec3& max) const {
|
||||
void CylinderShape::getLocalBounds(vec3& _min, vec3& _max) const {
|
||||
// Maximum bounds
|
||||
max.setX(mRadius + m_margin);
|
||||
max.setY(m_halfHeight + m_margin);
|
||||
max.setZ(max.x());
|
||||
_max.setX(m_radius + m_margin);
|
||||
_max.setY(m_halfHeight + m_margin);
|
||||
_max.setZ(_max.x());
|
||||
// Minimum bounds
|
||||
min.setX(-max.x());
|
||||
min.setY(-max.y());
|
||||
min.setZ(min.x());
|
||||
_min.setX(-_max.x());
|
||||
_min.setY(-_max.y());
|
||||
_min.setZ(_min.x());
|
||||
}
|
||||
|
||||
// Return the local inertia tensor of the cylinder
|
||||
/**
|
||||
* @param[out] tensor The 3x3 inertia tensor matrix of the shape in local-space
|
||||
* coordinates
|
||||
* @param mass Mass to use to compute the inertia tensor of the collision shape
|
||||
*/
|
||||
void CylinderShape::computeLocalInertiaTensor(etk::Matrix3x3& tensor, float mass) const {
|
||||
void CylinderShape::computeLocalInertiaTensor(etk::Matrix3x3& _tensor, float _mass) const {
|
||||
float height = float(2.0) * m_halfHeight;
|
||||
float diag = (1.0f / float(12.0)) * mass * (3 * mRadius * mRadius + height * height);
|
||||
tensor.setValue(diag, 0.0, 0.0, 0.0,
|
||||
0.5f * mass * mRadius * mRadius, 0.0,
|
||||
0.0, 0.0, diag);
|
||||
float diag = (1.0f / float(12.0)) * _mass * (3 * m_radius * m_radius + height * height);
|
||||
_tensor.setValue(diag, 0.0, 0.0, 0.0,
|
||||
0.5f * _mass * m_radius * m_radius, 0.0,
|
||||
0.0, 0.0, diag);
|
||||
}
|
||||
|
||||
// Return true if a point is inside the collision shape
|
||||
bool CylinderShape::testPointInside(const vec3& localPoint, ProxyShape* proxyShape) const{
|
||||
return ( (localPoint.x() * localPoint.x() + localPoint.z() * localPoint.z()) < mRadius * mRadius
|
||||
&& localPoint.y() < m_halfHeight
|
||||
&& localPoint.y() > -m_halfHeight);
|
||||
bool CylinderShape::testPointInside(const vec3& _localPoint, ProxyShape* _proxyShape) const{
|
||||
return ( (_localPoint.x() * _localPoint.x() + _localPoint.z() * _localPoint.z()) < m_radius * m_radius
|
||||
&& _localPoint.y() < m_halfHeight
|
||||
&& _localPoint.y() > -m_halfHeight);
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -10,42 +13,53 @@
|
||||
#include <ephysics/mathematics/mathematics.hpp>
|
||||
|
||||
namespace ephysics {
|
||||
/**
|
||||
* @brief It represents a cylinder collision shape around the Y axis
|
||||
* and centered at the origin. The cylinder is defined by its height
|
||||
* and the radius of its base. The "transform" of the corresponding
|
||||
* rigid body gives an orientation and a position to the cylinder.
|
||||
* This collision shape uses an extra margin distance around it for collision
|
||||
* detection purpose. The default margin is 4cm (if your units are meters,
|
||||
* which is recommended). In case, you want to simulate small objects
|
||||
* (smaller than the margin distance), you might want to reduce the margin by
|
||||
* specifying your own margin distance using the "margin" parameter in the
|
||||
* constructor of the cylinder shape. Otherwise, it is recommended to use the
|
||||
* default margin distance by not using the "margin" parameter in the constructor.
|
||||
*/
|
||||
class CylinderShape : public ConvexShape {
|
||||
protected :
|
||||
float mRadius; //!< Radius of the base
|
||||
float m_halfHeight; //!< Half height of the cylinder
|
||||
/// Private copy-constructor
|
||||
CylinderShape(const CylinderShape&) = delete;
|
||||
/// Private assignment operator
|
||||
CylinderShape& operator=(const CylinderShape&) = delete;
|
||||
vec3 getLocalSupportPointWithoutMargin(const vec3& _direction, void** _cachedCollisionData) const override;
|
||||
bool testPointInside(const vec3& _localPoint, ProxyShape* _proxyShape) const override;
|
||||
bool raycast(const Ray& _ray, RaycastInfo& _raycastInfo, ProxyShape* _proxyShape) const override;
|
||||
size_t getSizeInBytes() const override;
|
||||
public :
|
||||
/// Constructor
|
||||
CylinderShape(float _radius, float _height, float _margin = OBJECT_MARGIN);
|
||||
/// Return the radius
|
||||
float getRadius() const;
|
||||
/// Return the height
|
||||
float getHeight() const;
|
||||
void setLocalScaling(const vec3& _scaling) override;
|
||||
void getLocalBounds(vec3& _min, vec3& _max) const override;
|
||||
void computeLocalInertiaTensor(etk::Matrix3x3& _tensor, float _mass) const override;
|
||||
};
|
||||
/**
|
||||
* @brief It represents a cylinder collision shape around the Y axis
|
||||
* and centered at the origin. The cylinder is defined by its height
|
||||
* and the radius of its base. The "transform" of the corresponding
|
||||
* rigid body gives an orientation and a position to the cylinder.
|
||||
* This collision shape uses an extra margin distance around it for collision
|
||||
* detection purpose. The default margin is 4cm (if your units are meters,
|
||||
* which is recommended). In case, you want to simulate small objects
|
||||
* (smaller than the margin distance), you might want to reduce the margin by
|
||||
* specifying your own margin distance using the "margin" parameter in the
|
||||
* constructor of the cylinder shape. Otherwise, it is recommended to use the
|
||||
* default margin distance by not using the "margin" parameter in the constructor.
|
||||
*/
|
||||
class CylinderShape: public ConvexShape {
|
||||
protected:
|
||||
float m_radius; //!< Radius of the base
|
||||
float m_halfHeight; //!< Half height of the cylinder
|
||||
/// DELETED copy-constructor
|
||||
CylinderShape(const CylinderShape&) = delete;
|
||||
/// DELETED assignment operator
|
||||
CylinderShape& operator=(const CylinderShape&) = delete;
|
||||
vec3 getLocalSupportPointWithoutMargin(const vec3& _direction, void** _cachedCollisionData) const override;
|
||||
bool testPointInside(const vec3& _localPoint, ProxyShape* _proxyShape) const override;
|
||||
bool raycast(const Ray& _ray, RaycastInfo& _raycastInfo, ProxyShape* _proxyShape) const override;
|
||||
size_t getSizeInBytes() const override;
|
||||
public:
|
||||
/**
|
||||
* @brief Contructor
|
||||
* @param radius Radius of the cylinder (in meters)
|
||||
* @param height Height of the cylinder (in meters)
|
||||
* @param margin Collision margin (in meters) around the collision shape
|
||||
*/
|
||||
CylinderShape(float _radius, float _height, float _margin = OBJECT_MARGIN);
|
||||
/**
|
||||
* @breif Get the Shape radius
|
||||
* @return Radius of the cylinder (in meters)
|
||||
*/
|
||||
float getRadius() const;
|
||||
/**
|
||||
* @breif Get the Shape height
|
||||
* @return Height of the cylinder (in meters)
|
||||
*/
|
||||
float getHeight() const;
|
||||
void setLocalScaling(const vec3& _scaling) override;
|
||||
void getLocalBounds(vec3& _min, vec3& _max) const override;
|
||||
void computeLocalInertiaTensor(etk::Matrix3x3& _tensor, float _mass) const override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,235 +1,190 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
// Libraries
|
||||
#include <ephysics/collision/shapes/HeightFieldShape.hpp>
|
||||
|
||||
// TODO: REMOVE this...
|
||||
using namespace ephysics;
|
||||
|
||||
// Constructor
|
||||
/**
|
||||
* @param nbGridColumns Number of columns in the grid of the height field
|
||||
* @param nbGridRows Number of rows in the grid of the height field
|
||||
* @param minHeight Minimum height value of the height field
|
||||
* @param maxHeight Maximum height value of the height field
|
||||
* @param heightFieldData Pointer to the first height value data (note that values are shared and not copied)
|
||||
* @param dataType Data type for the height values (int32_t, float, double)
|
||||
* @param upAxis Integer representing the up axis direction (0 for x, 1 for y and 2 for z)
|
||||
* @param int32_tegerHeightScale Scaling factor used to scale the height values (only when height values type is int32_teger)
|
||||
*/
|
||||
HeightFieldShape::HeightFieldShape(int32_t nbGridColumns, int32_t nbGridRows, float minHeight, float maxHeight,
|
||||
const void* heightFieldData, HeightDataType dataType, int32_t upAxis,
|
||||
float int32_tegerHeightScale)
|
||||
: ConcaveShape(HEIGHTFIELD), m_numberColumns(nbGridColumns), m_numberRows(nbGridRows),
|
||||
m_width(nbGridColumns - 1), m_length(nbGridRows - 1), m_minHeight(minHeight),
|
||||
m_maxHeight(maxHeight), m_upAxis(upAxis), m_integerHeightScale(int32_tegerHeightScale),
|
||||
m_heightDataType(dataType) {
|
||||
|
||||
assert(nbGridColumns >= 2);
|
||||
assert(nbGridRows >= 2);
|
||||
HeightFieldShape::HeightFieldShape(int32_t _nbGridColumns,
|
||||
int32_t _nbGridRows,
|
||||
float _minHeight,
|
||||
float _maxHeight,
|
||||
const void* _heightFieldData,
|
||||
HeightDataType _dataType,
|
||||
int32_t _upAxis,
|
||||
float _integerHeightScale):
|
||||
ConcaveShape(HEIGHTFIELD),
|
||||
m_numberColumns(_nbGridColumns),
|
||||
m_numberRows(_nbGridRows),
|
||||
m_width(_nbGridColumns - 1),
|
||||
m_length(_nbGridRows - 1),
|
||||
m_minHeight(_minHeight),
|
||||
m_maxHeight(_maxHeight),
|
||||
m_upAxis(_upAxis),
|
||||
m_integerHeightScale(_integerHeightScale),
|
||||
m_heightDataType(_dataType) {
|
||||
assert(_nbGridColumns >= 2);
|
||||
assert(_nbGridRows >= 2);
|
||||
assert(m_width >= 1);
|
||||
assert(m_length >= 1);
|
||||
assert(minHeight <= maxHeight);
|
||||
assert(upAxis == 0 || upAxis == 1 || upAxis == 2);
|
||||
|
||||
m_heightFieldData = heightFieldData;
|
||||
|
||||
assert(_minHeight <= _maxHeight);
|
||||
assert(_upAxis == 0 || _upAxis == 1 || _upAxis == 2);
|
||||
m_heightFieldData = _heightFieldData;
|
||||
float halfHeight = (m_maxHeight - m_minHeight) * 0.5f;
|
||||
assert(halfHeight >= 0);
|
||||
|
||||
// Compute the local AABB of the height field
|
||||
if (m_upAxis == 0) {
|
||||
m_AABB.setMin(vec3(-halfHeight, -m_width * 0.5f, -m_length * float(0.5)));
|
||||
m_AABB.setMax(vec3(halfHeight, m_width * 0.5f, m_length* float(0.5)));
|
||||
}
|
||||
else if (m_upAxis == 1) {
|
||||
} else if (m_upAxis == 1) {
|
||||
m_AABB.setMin(vec3(-m_width * 0.5f, -halfHeight, -m_length * float(0.5)));
|
||||
m_AABB.setMax(vec3(m_width * 0.5f, halfHeight, m_length * float(0.5)));
|
||||
}
|
||||
else if (m_upAxis == 2) {
|
||||
} else if (m_upAxis == 2) {
|
||||
m_AABB.setMin(vec3(-m_width * 0.5f, -m_length * float(0.5), -halfHeight));
|
||||
m_AABB.setMax(vec3(m_width * 0.5f, m_length * float(0.5), halfHeight));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Return the local bounds of the shape in x, y and z directions.
|
||||
// This method is used to compute the AABB of the box
|
||||
/**
|
||||
* @param min The minimum bounds of the shape in local-space coordinates
|
||||
* @param max The maximum bounds of the shape in local-space coordinates
|
||||
*/
|
||||
void HeightFieldShape::getLocalBounds(vec3& min, vec3& max) const {
|
||||
min = m_AABB.getMin() * m_scaling;
|
||||
max = m_AABB.getMax() * m_scaling;
|
||||
void HeightFieldShape::getLocalBounds(vec3& _min, vec3& _max) const {
|
||||
_min = m_AABB.getMin() * m_scaling;
|
||||
_max = m_AABB.getMax() * m_scaling;
|
||||
}
|
||||
|
||||
// Test collision with the triangles of the height field shape. The idea is to use the AABB
|
||||
// of the body when need to test and see against which triangles of the height-field we need
|
||||
// to test for collision. We compute the sub-grid points that are inside the other body's AABB
|
||||
// and then for each rectangle in the sub-grid we generate two triangles that we use to test collision.
|
||||
void HeightFieldShape::testAllTriangles(TriangleCallback& callback, const AABB& localAABB) const {
|
||||
|
||||
// Compute the non-scaled AABB
|
||||
vec3 inverseScaling(1.0f / m_scaling.x(), 1.0f / m_scaling.y(), float(1.0) / m_scaling.z());
|
||||
AABB aabb(localAABB.getMin() * inverseScaling, localAABB.getMax() * inverseScaling);
|
||||
|
||||
// Compute the int32_teger grid coordinates inside the area we need to test for collision
|
||||
int32_t minGridCoords[3];
|
||||
int32_t maxGridCoords[3];
|
||||
computeMinMaxGridCoordinates(minGridCoords, maxGridCoords, aabb);
|
||||
|
||||
// Compute the starting and ending coords of the sub-grid according to the up axis
|
||||
int32_t iMin = 0;
|
||||
int32_t iMax = 0;
|
||||
int32_t jMin = 0;
|
||||
int32_t jMax = 0;
|
||||
switch(m_upAxis) {
|
||||
case 0 : iMin = clamp(minGridCoords[1], 0, m_numberColumns - 1);
|
||||
iMax = clamp(maxGridCoords[1], 0, m_numberColumns - 1);
|
||||
jMin = clamp(minGridCoords[2], 0, m_numberRows - 1);
|
||||
jMax = clamp(maxGridCoords[2], 0, m_numberRows - 1);
|
||||
break;
|
||||
case 1 : iMin = clamp(minGridCoords[0], 0, m_numberColumns - 1);
|
||||
iMax = clamp(maxGridCoords[0], 0, m_numberColumns - 1);
|
||||
jMin = clamp(minGridCoords[2], 0, m_numberRows - 1);
|
||||
jMax = clamp(maxGridCoords[2], 0, m_numberRows - 1);
|
||||
break;
|
||||
case 2 : iMin = clamp(minGridCoords[0], 0, m_numberColumns - 1);
|
||||
iMax = clamp(maxGridCoords[0], 0, m_numberColumns - 1);
|
||||
jMin = clamp(minGridCoords[1], 0, m_numberRows - 1);
|
||||
jMax = clamp(maxGridCoords[1], 0, m_numberRows - 1);
|
||||
break;
|
||||
}
|
||||
|
||||
assert(iMin >= 0 && iMin < m_numberColumns);
|
||||
assert(iMax >= 0 && iMax < m_numberColumns);
|
||||
assert(jMin >= 0 && jMin < m_numberRows);
|
||||
assert(jMax >= 0 && jMax < m_numberRows);
|
||||
|
||||
// For each sub-grid points (except the last ones one each dimension)
|
||||
for (int32_t i = iMin; i < iMax; i++) {
|
||||
for (int32_t j = jMin; j < jMax; j++) {
|
||||
|
||||
// Compute the four point of the current quad
|
||||
vec3 p1 = getVertexAt(i, j);
|
||||
vec3 p2 = getVertexAt(i, j + 1);
|
||||
vec3 p3 = getVertexAt(i + 1, j);
|
||||
vec3 p4 = getVertexAt(i + 1, j + 1);
|
||||
|
||||
// Generate the first triangle for the current grid rectangle
|
||||
vec3 trianglePoints[3] = {p1, p2, p3};
|
||||
|
||||
// Test collision against the first triangle
|
||||
callback.testTriangle(trianglePoints);
|
||||
|
||||
// Generate the second triangle for the current grid rectangle
|
||||
trianglePoints[0] = p3;
|
||||
trianglePoints[1] = p2;
|
||||
trianglePoints[2] = p4;
|
||||
|
||||
// Test collision against the second triangle
|
||||
callback.testTriangle(trianglePoints);
|
||||
}
|
||||
}
|
||||
void HeightFieldShape::testAllTriangles(TriangleCallback& _callback, const AABB& _localAABB) const {
|
||||
// Compute the non-scaled AABB
|
||||
vec3 inverseScaling(1.0f / m_scaling.x(), 1.0f / m_scaling.y(), float(1.0) / m_scaling.z());
|
||||
AABB aabb(_localAABB.getMin() * inverseScaling, _localAABB.getMax() * inverseScaling);
|
||||
// Compute the int32_teger grid coordinates inside the area we need to test for collision
|
||||
int32_t minGridCoords[3];
|
||||
int32_t maxGridCoords[3];
|
||||
computeMinMaxGridCoordinates(minGridCoords, maxGridCoords, aabb);
|
||||
// Compute the starting and ending coords of the sub-grid according to the up axis
|
||||
int32_t iMin = 0;
|
||||
int32_t iMax = 0;
|
||||
int32_t jMin = 0;
|
||||
int32_t jMax = 0;
|
||||
switch(m_upAxis) {
|
||||
case 0 :
|
||||
iMin = clamp(minGridCoords[1], 0, m_numberColumns - 1);
|
||||
iMax = clamp(maxGridCoords[1], 0, m_numberColumns - 1);
|
||||
jMin = clamp(minGridCoords[2], 0, m_numberRows - 1);
|
||||
jMax = clamp(maxGridCoords[2], 0, m_numberRows - 1);
|
||||
break;
|
||||
case 1 :
|
||||
iMin = clamp(minGridCoords[0], 0, m_numberColumns - 1);
|
||||
iMax = clamp(maxGridCoords[0], 0, m_numberColumns - 1);
|
||||
jMin = clamp(minGridCoords[2], 0, m_numberRows - 1);
|
||||
jMax = clamp(maxGridCoords[2], 0, m_numberRows - 1);
|
||||
break;
|
||||
case 2 :
|
||||
iMin = clamp(minGridCoords[0], 0, m_numberColumns - 1);
|
||||
iMax = clamp(maxGridCoords[0], 0, m_numberColumns - 1);
|
||||
jMin = clamp(minGridCoords[1], 0, m_numberRows - 1);
|
||||
jMax = clamp(maxGridCoords[1], 0, m_numberRows - 1);
|
||||
break;
|
||||
}
|
||||
assert(iMin >= 0 && iMin < m_numberColumns);
|
||||
assert(iMax >= 0 && iMax < m_numberColumns);
|
||||
assert(jMin >= 0 && jMin < m_numberRows);
|
||||
assert(jMax >= 0 && jMax < m_numberRows);
|
||||
// For each sub-grid points (except the last ones one each dimension)
|
||||
for (int32_t i = iMin; i < iMax; i++) {
|
||||
for (int32_t j = jMin; j < jMax; j++) {
|
||||
// Compute the four point of the current quad
|
||||
vec3 p1 = getVertexAt(i, j);
|
||||
vec3 p2 = getVertexAt(i, j + 1);
|
||||
vec3 p3 = getVertexAt(i + 1, j);
|
||||
vec3 p4 = getVertexAt(i + 1, j + 1);
|
||||
// Generate the first triangle for the current grid rectangle
|
||||
vec3 trianglePoints[3] = {p1, p2, p3};
|
||||
// Test collision against the first triangle
|
||||
_callback.testTriangle(trianglePoints);
|
||||
// Generate the second triangle for the current grid rectangle
|
||||
trianglePoints[0] = p3;
|
||||
trianglePoints[1] = p2;
|
||||
trianglePoints[2] = p4;
|
||||
// Test collision against the second triangle
|
||||
_callback.testTriangle(trianglePoints);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the min/max grid coords corresponding to the int32_tersection of the AABB of the height field and
|
||||
// the AABB to collide
|
||||
void HeightFieldShape::computeMinMaxGridCoordinates(int32_t* minCoords, int32_t* maxCoords, const AABB& aabbToCollide) const {
|
||||
|
||||
void HeightFieldShape::computeMinMaxGridCoordinates(int32_t* _minCoords, int32_t* _maxCoords, const AABB& _aabbToCollide) const {
|
||||
// Clamp the min/max coords of the AABB to collide inside the height field AABB
|
||||
vec3 minPoint = etk::max(aabbToCollide.getMin(), m_AABB.getMin());
|
||||
vec3 minPoint = etk::max(_aabbToCollide.getMin(), m_AABB.getMin());
|
||||
minPoint = etk::min(minPoint, m_AABB.getMax());
|
||||
|
||||
vec3 maxPoint = etk::min(aabbToCollide.getMax(), m_AABB.getMax());
|
||||
vec3 maxPoint = etk::min(_aabbToCollide.getMax(), m_AABB.getMax());
|
||||
maxPoint = etk::max(maxPoint, m_AABB.getMin());
|
||||
|
||||
// Translate the min/max points such that the we compute grid points from [0 ... mNbWidthGridPoints]
|
||||
// and from [0 ... mNbLengthGridPoints] because the AABB coordinates range are [-mWdith/2 ... m_width/2]
|
||||
// and [-m_length/2 ... m_length/2]
|
||||
const vec3 translateVec = m_AABB.getExtent() * 0.5f;
|
||||
minPoint += translateVec;
|
||||
maxPoint += translateVec;
|
||||
|
||||
// Convert the floating min/max coords of the AABB int32_to closest int32_teger
|
||||
// grid values (note that we use the closest grid coordinate that is out
|
||||
// of the AABB)
|
||||
minCoords[0] = computeIntegerGridValue(minPoint.x()) - 1;
|
||||
minCoords[1] = computeIntegerGridValue(minPoint.y()) - 1;
|
||||
minCoords[2] = computeIntegerGridValue(minPoint.z()) - 1;
|
||||
|
||||
maxCoords[0] = computeIntegerGridValue(maxPoint.x()) + 1;
|
||||
maxCoords[1] = computeIntegerGridValue(maxPoint.y()) + 1;
|
||||
maxCoords[2] = computeIntegerGridValue(maxPoint.z()) + 1;
|
||||
_minCoords[0] = computeIntegerGridValue(minPoint.x()) - 1;
|
||||
_minCoords[1] = computeIntegerGridValue(minPoint.y()) - 1;
|
||||
_minCoords[2] = computeIntegerGridValue(minPoint.z()) - 1;
|
||||
_maxCoords[0] = computeIntegerGridValue(maxPoint.x()) + 1;
|
||||
_maxCoords[1] = computeIntegerGridValue(maxPoint.y()) + 1;
|
||||
_maxCoords[2] = computeIntegerGridValue(maxPoint.z()) + 1;
|
||||
}
|
||||
|
||||
// Raycast method with feedback information
|
||||
/// Note that only the first triangle hit by the ray in the mesh will be returned, even if
|
||||
/// the ray hits many triangles.
|
||||
bool HeightFieldShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const {
|
||||
|
||||
bool HeightFieldShape::raycast(const Ray& _ray, RaycastInfo& _raycastInfo, ProxyShape* _proxyShape) const {
|
||||
// TODO : Implement raycasting without using an AABB for the ray
|
||||
// but using a dynamic AABB tree or octree instead
|
||||
|
||||
PROFILE("HeightFieldShape::raycast()");
|
||||
|
||||
TriangleOverlapCallback triangleCallback(ray, proxyShape, raycastInfo, *this);
|
||||
|
||||
TriangleOverlapCallback triangleCallback(_ray, _proxyShape, _raycastInfo, *this);
|
||||
// Compute the AABB for the ray
|
||||
const vec3 rayEnd = ray.point1 + ray.maxFraction * (ray.point2 - ray.point1);
|
||||
const AABB rayAABB(etk::min(ray.point1, rayEnd), etk::max(ray.point1, rayEnd));
|
||||
|
||||
const vec3 rayEnd = _ray.point1 + _ray.maxFraction * (_ray.point2 - _ray.point1);
|
||||
const AABB rayAABB(etk::min(_ray.point1, rayEnd), etk::max(_ray.point1, rayEnd));
|
||||
testAllTriangles(triangleCallback, rayAABB);
|
||||
|
||||
return triangleCallback.getIsHit();
|
||||
}
|
||||
|
||||
// Return the vertex (local-coordinates) of the height field at a given (x,y) position
|
||||
vec3 HeightFieldShape::getVertexAt(int32_t x, int32_t y) const {
|
||||
|
||||
vec3 HeightFieldShape::getVertexAt(int32_t _xxx, int32_t _yyy) const {
|
||||
// Get the height value
|
||||
const float height = getHeightAt(x, y);
|
||||
|
||||
const float height = getHeightAt(_xxx, _yyy);
|
||||
// Height values origin
|
||||
const float heightOrigin = -(m_maxHeight - m_minHeight) * 0.5f - m_minHeight;
|
||||
|
||||
vec3 vertex;
|
||||
switch (m_upAxis) {
|
||||
case 0: vertex = vec3(heightOrigin + height, -m_width * 0.5f + x, -m_length * float(0.5) + y);
|
||||
break;
|
||||
case 1: vertex = vec3(-m_width * 0.5f + x, heightOrigin + height, -m_length * float(0.5) + y);
|
||||
break;
|
||||
case 2: vertex = vec3(-m_width * 0.5f + x, -m_length * float(0.5) + y, heightOrigin + height);
|
||||
break;
|
||||
default: assert(false);
|
||||
case 0:
|
||||
vertex = vec3(heightOrigin + height, -m_width * 0.5f + _xxx, -m_length * float(0.5) + _yyy);
|
||||
break;
|
||||
case 1:
|
||||
vertex = vec3(-m_width * 0.5f + _xxx, heightOrigin + height, -m_length * float(0.5) + _yyy);
|
||||
break;
|
||||
case 2:
|
||||
vertex = vec3(-m_width * 0.5f + _xxx, -m_length * float(0.5) + _yyy, heightOrigin + height);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
|
||||
assert(m_AABB.contains(vertex));
|
||||
|
||||
return vertex * m_scaling;
|
||||
}
|
||||
|
||||
// Raycast test between a ray and a triangle of the heightfield
|
||||
void TriangleOverlapCallback::testTriangle(const vec3* trianglePoints) {
|
||||
|
||||
void TriangleOverlapCallback::testTriangle(const vec3* _trianglePoints) {
|
||||
// Create a triangle collision shape
|
||||
float margin = m_heightFieldShape.getTriangleMargin();
|
||||
TriangleShape triangleShape(trianglePoints[0], trianglePoints[1], trianglePoints[2], margin);
|
||||
TriangleShape triangleShape(_trianglePoints[0], _trianglePoints[1], _trianglePoints[2], margin);
|
||||
triangleShape.setRaycastTestType(m_heightFieldShape.getRaycastTestType());
|
||||
|
||||
// Ray casting test against the collision shape
|
||||
RaycastInfo raycastInfo;
|
||||
bool isTriangleHit = triangleShape.raycast(m_ray, raycastInfo, m_proxyShape);
|
||||
|
||||
// If the ray hit the collision shape
|
||||
if (isTriangleHit && raycastInfo.hitFraction <= m_smallestHitFraction) {
|
||||
|
||||
if ( isTriangleHit
|
||||
&& raycastInfo.hitFraction <= m_smallestHitFraction) {
|
||||
assert(raycastInfo.hitFraction >= 0.0f);
|
||||
|
||||
m_raycastInfo.body = raycastInfo.body;
|
||||
m_raycastInfo.proxyShape = raycastInfo.proxyShape;
|
||||
m_raycastInfo.hitFraction = raycastInfo.hitFraction;
|
||||
@ -237,66 +192,55 @@ void TriangleOverlapCallback::testTriangle(const vec3* trianglePoints) {
|
||||
m_raycastInfo.worldNormal = raycastInfo.worldNormal;
|
||||
m_raycastInfo.meshSubpart = -1;
|
||||
m_raycastInfo.triangleIndex = -1;
|
||||
|
||||
m_smallestHitFraction = raycastInfo.hitFraction;
|
||||
m_isHit = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the number of rows in the height field
|
||||
int32_t HeightFieldShape::getNbRows() const {
|
||||
return m_numberRows;
|
||||
}
|
||||
|
||||
// Return the number of columns in the height field
|
||||
int32_t HeightFieldShape::getNbColumns() const {
|
||||
return m_numberColumns;
|
||||
}
|
||||
|
||||
// Return the type of height value in the height field
|
||||
HeightFieldShape::HeightDataType HeightFieldShape::getHeightDataType() const {
|
||||
return m_heightDataType;
|
||||
}
|
||||
|
||||
// Return the number of bytes used by the collision shape
|
||||
size_t HeightFieldShape::getSizeInBytes() const {
|
||||
return sizeof(HeightFieldShape);
|
||||
}
|
||||
|
||||
// Set the local scaling vector of the collision shape
|
||||
void HeightFieldShape::setLocalScaling(const vec3& scaling) {
|
||||
CollisionShape::setLocalScaling(scaling);
|
||||
void HeightFieldShape::setLocalScaling(const vec3& _scaling) {
|
||||
CollisionShape::setLocalScaling(_scaling);
|
||||
}
|
||||
|
||||
// Return the height of a given (x,y) point in the height field
|
||||
float HeightFieldShape::getHeightAt(int32_t x, int32_t y) const {
|
||||
|
||||
float HeightFieldShape::getHeightAt(int32_t _xxx, int32_t _yyy) const {
|
||||
switch(m_heightDataType) {
|
||||
case HEIGHT_FLOAT_TYPE : return ((float*)m_heightFieldData)[y * m_numberColumns + x];
|
||||
case HEIGHT_DOUBLE_TYPE : return ((double*)m_heightFieldData)[y * m_numberColumns + x];
|
||||
case HEIGHT_INT_TYPE : return ((int32_t*)m_heightFieldData)[y * m_numberColumns + x] * m_integerHeightScale;
|
||||
default: assert(false); return 0;
|
||||
case HEIGHT_FLOAT_TYPE:
|
||||
return ((float*)m_heightFieldData)[_yyy * m_numberColumns + _xxx];
|
||||
case HEIGHT_DOUBLE_TYPE:
|
||||
return ((double*)m_heightFieldData)[_yyy * m_numberColumns + _xxx];
|
||||
case HEIGHT_INT_TYPE:
|
||||
return ((int32_t*)m_heightFieldData)[_yyy * m_numberColumns + _xxx] * m_integerHeightScale;
|
||||
default:
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the closest inside int32_teger grid value of a given floating grid value
|
||||
int32_t HeightFieldShape::computeIntegerGridValue(float value) const {
|
||||
return (value < 0.0f) ? value - 0.5f : value + float(0.5);
|
||||
int32_t HeightFieldShape::computeIntegerGridValue(float _value) const {
|
||||
return (_value < 0.0f) ? _value - 0.5f : _value + 0.5f;
|
||||
}
|
||||
|
||||
// Return the local inertia tensor
|
||||
/**
|
||||
* @param[out] tensor The 3x3 inertia tensor matrix of the shape in local-space
|
||||
* coordinates
|
||||
* @param mass Mass to use to compute the inertia tensor of the collision shape
|
||||
*/
|
||||
void HeightFieldShape::computeLocalInertiaTensor(etk::Matrix3x3& tensor, float mass) const {
|
||||
|
||||
void HeightFieldShape::computeLocalInertiaTensor(etk::Matrix3x3& _tensor, float _mass) const {
|
||||
// Default inertia tensor
|
||||
// Note that this is not very realistic for a concave triangle mesh.
|
||||
// However, in most cases, it will only be used static bodies and therefore,
|
||||
// the inertia tensor is not used.
|
||||
tensor.setValue(mass, 0, 0,
|
||||
0, mass, 0,
|
||||
0, 0, mass);
|
||||
_tensor.setValue(_mass, 0, 0,
|
||||
0, _mass, 0,
|
||||
0, 0, _mass);
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -74,9 +77,9 @@ namespace ephysics {
|
||||
HeightDataType m_heightDataType; //!< Data type of the height values
|
||||
const void* m_heightFieldData; //!< Array of data with all the height values of the height field
|
||||
AABB m_AABB; //!< Local AABB of the height field (without scaling)
|
||||
/// Private copy-constructor
|
||||
/// DELETED copy-constructor
|
||||
HeightFieldShape(const HeightFieldShape&) = delete;
|
||||
/// Private assignment operator
|
||||
/// DELETED assignment operator
|
||||
HeightFieldShape& operator=(const HeightFieldShape&) = delete;
|
||||
bool raycast(const Ray& _ray, RaycastInfo& _raycastInfo, ProxyShape* _proxyShape) const override;
|
||||
size_t getSizeInBytes() const override;
|
||||
@ -96,7 +99,17 @@ namespace ephysics {
|
||||
/// Compute the min/max grid coords corresponding to the int32_tersection of the AABB of the height field and the AABB to collide
|
||||
void computeMinMaxGridCoordinates(int32_t* _minCoords, int32_t* _maxCoords, const AABB& _aabbToCollide) const;
|
||||
public:
|
||||
/// Constructor
|
||||
/**
|
||||
* @brief Contructor
|
||||
* @param nbGridColumns Number of columns in the grid of the height field
|
||||
* @param nbGridRows Number of rows in the grid of the height field
|
||||
* @param minHeight Minimum height value of the height field
|
||||
* @param maxHeight Maximum height value of the height field
|
||||
* @param heightFieldData Pointer to the first height value data (note that values are shared and not copied)
|
||||
* @param dataType Data type for the height values (int32_t, float, double)
|
||||
* @param upAxis Integer representing the up axis direction (0 for x, 1 for y and 2 for z)
|
||||
* @param int32_tegerHeightScale Scaling factor used to scale the height values (only when height values type is int32_teger)
|
||||
*/
|
||||
HeightFieldShape(int32_t _nbGridColumns,
|
||||
int32_t _nbGridRows,
|
||||
float _minHeight,
|
||||
|
@ -1,25 +1,23 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
// Libraries
|
||||
#include <ephysics/collision/shapes/SphereShape.hpp>
|
||||
#include <ephysics/collision/ProxyShape.hpp>
|
||||
#include <ephysics/configuration.hpp>
|
||||
|
||||
// TODO: REMOVE this ...
|
||||
using namespace ephysics;
|
||||
|
||||
// Constructor
|
||||
/**
|
||||
* @param radius Radius of the sphere (in meters)
|
||||
*/
|
||||
SphereShape::SphereShape(float radius) : ConvexShape(SPHERE, radius) {
|
||||
assert(radius > 0.0f);
|
||||
SphereShape::SphereShape(float _radius):
|
||||
ConvexShape(SPHERE, _radius) {
|
||||
assert(_radius > 0.0f);
|
||||
}
|
||||
|
||||
|
||||
void SphereShape::setLocalScaling(const vec3& _scaling) {
|
||||
m_margin = (m_margin / m_scaling.x()) * _scaling.x();
|
||||
CollisionShape::setLocalScaling(_scaling);
|
||||
@ -51,49 +49,41 @@ void SphereShape::getLocalBounds(vec3& _min, vec3& _max) const {
|
||||
_min.setZ(_min.x());
|
||||
}
|
||||
|
||||
|
||||
// Raycast method with feedback information
|
||||
bool SphereShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const {
|
||||
|
||||
const vec3 m = ray.point1;
|
||||
bool SphereShape::raycast(const Ray& _ray, RaycastInfo& _raycastInfo, ProxyShape* _proxyShape) const {
|
||||
const vec3 m = _ray.point1;
|
||||
float c = m.dot(m) - m_margin * m_margin;
|
||||
|
||||
// If the origin of the ray is inside the sphere, we return no int32_tersection
|
||||
if (c < 0.0f) return false;
|
||||
|
||||
const vec3 rayDirection = ray.point2 - ray.point1;
|
||||
if (c < 0.0f) {
|
||||
return false;
|
||||
}
|
||||
const vec3 rayDirection = _ray.point2 - _ray.point1;
|
||||
float b = m.dot(rayDirection);
|
||||
|
||||
// If the origin of the ray is outside the sphere and the ray
|
||||
// is pointing away from the sphere, there is no int32_tersection
|
||||
if (b > 0.0f) return false;
|
||||
|
||||
if (b > 0.0f) {
|
||||
return false;
|
||||
}
|
||||
float raySquareLength = rayDirection.length2();
|
||||
|
||||
// Compute the discriminant of the quadratic equation
|
||||
float discriminant = b * b - raySquareLength * c;
|
||||
|
||||
// If the discriminant is negative or the ray length is very small, there is no int32_tersection
|
||||
if (discriminant < 0.0f || raySquareLength < FLT_EPSILON) return false;
|
||||
|
||||
if ( discriminant < 0.0f
|
||||
|| raySquareLength < FLT_EPSILON) {
|
||||
return false;
|
||||
}
|
||||
// Compute the solution "t" closest to the origin
|
||||
float t = -b - etk::sqrt(discriminant);
|
||||
|
||||
assert(t >= 0.0f);
|
||||
|
||||
// If the hit point is withing the segment ray fraction
|
||||
if (t < ray.maxFraction * raySquareLength) {
|
||||
|
||||
if (t < _ray.maxFraction * raySquareLength) {
|
||||
// Compute the int32_tersection information
|
||||
t /= raySquareLength;
|
||||
raycastInfo.body = proxyShape->getBody();
|
||||
raycastInfo.proxyShape = proxyShape;
|
||||
raycastInfo.hitFraction = t;
|
||||
raycastInfo.worldPoint = ray.point1 + t * rayDirection;
|
||||
raycastInfo.worldNormal = raycastInfo.worldPoint;
|
||||
|
||||
_raycastInfo.body = _proxyShape->getBody();
|
||||
_raycastInfo.proxyShape = _proxyShape;
|
||||
_raycastInfo.hitFraction = t;
|
||||
_raycastInfo.worldPoint = _ray.point1 + t * rayDirection;
|
||||
_raycastInfo.worldNormal = _raycastInfo.worldPoint;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -33,7 +36,10 @@ namespace ephysics {
|
||||
return sizeof(SphereShape);
|
||||
}
|
||||
public :
|
||||
/// Constructor
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param[in] radius Radius of the sphere (in meters)
|
||||
*/
|
||||
SphereShape(float _radius);
|
||||
/**
|
||||
* @brief Get the radius of the sphere
|
||||
|
@ -1,203 +1,163 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
// Libraries
|
||||
#include <ephysics/collision/shapes/TriangleShape.hpp>
|
||||
#include <ephysics/collision/ProxyShape.hpp>
|
||||
#include <ephysics/engine/Profiler.hpp>
|
||||
#include <ephysics/configuration.hpp>
|
||||
|
||||
// TODO: REMOVE this...
|
||||
using namespace ephysics;
|
||||
|
||||
// Constructor
|
||||
/**
|
||||
* @param point1 First point of the triangle
|
||||
* @param point2 Second point of the triangle
|
||||
* @param point3 Third point of the triangle
|
||||
* @param margin The collision margin (in meters) around the collision shape
|
||||
*/
|
||||
TriangleShape::TriangleShape(const vec3& point1, const vec3& point2, const vec3& point3, float margin)
|
||||
: ConvexShape(TRIANGLE, margin) {
|
||||
m_points[0] = point1;
|
||||
m_points[1] = point2;
|
||||
m_points[2] = point3;
|
||||
TriangleShape::TriangleShape(const vec3& _point1, const vec3& _point2, const vec3& _point3, float _margin)
|
||||
: ConvexShape(TRIANGLE, _margin) {
|
||||
m_points[0] = _point1;
|
||||
m_points[1] = _point2;
|
||||
m_points[2] = _point3;
|
||||
m_raycastTestType = FRONT;
|
||||
}
|
||||
|
||||
// Destructor
|
||||
TriangleShape::~TriangleShape() {
|
||||
|
||||
}
|
||||
|
||||
// Raycast method with feedback information
|
||||
/// This method use the line vs triangle raycasting technique described in
|
||||
/// Real-time Collision Detection by Christer Ericson.
|
||||
bool TriangleShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const {
|
||||
|
||||
bool TriangleShape::raycast(const Ray& _ray, RaycastInfo& _raycastInfo, ProxyShape* _proxyShape) const {
|
||||
PROFILE("TriangleShape::raycast()");
|
||||
|
||||
const vec3 pq = ray.point2 - ray.point1;
|
||||
const vec3 pa = m_points[0] - ray.point1;
|
||||
const vec3 pb = m_points[1] - ray.point1;
|
||||
const vec3 pc = m_points[2] - ray.point1;
|
||||
|
||||
const vec3 pq = _ray.point2 - _ray.point1;
|
||||
const vec3 pa = m_points[0] - _ray.point1;
|
||||
const vec3 pb = m_points[1] - _ray.point1;
|
||||
const vec3 pc = m_points[2] - _ray.point1;
|
||||
// Test if the line PQ is inside the eges BC, CA and AB. We use the triple
|
||||
// product for this test.
|
||||
const vec3 m = pq.cross(pc);
|
||||
float u = pb.dot(m);
|
||||
if (m_raycastTestType == FRONT) {
|
||||
if (u < 0.0f) return false;
|
||||
if (u < 0.0f) {
|
||||
return false;
|
||||
}
|
||||
} else if (m_raycastTestType == BACK) {
|
||||
if (u > 0.0f) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (m_raycastTestType == BACK) {
|
||||
if (u > 0.0f) return false;
|
||||
}
|
||||
|
||||
float v = -pa.dot(m);
|
||||
if (m_raycastTestType == FRONT) {
|
||||
if (v < 0.0f) return false;
|
||||
if (v < 0.0f) {
|
||||
return false;
|
||||
}
|
||||
} else if (m_raycastTestType == BACK) {
|
||||
if (v > 0.0f) {
|
||||
return false;
|
||||
}
|
||||
} else if (m_raycastTestType == FRONT_AND_BACK) {
|
||||
if (!sameSign(u, v)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (m_raycastTestType == BACK) {
|
||||
if (v > 0.0f) return false;
|
||||
}
|
||||
else if (m_raycastTestType == FRONT_AND_BACK) {
|
||||
if (!sameSign(u, v)) return false;
|
||||
}
|
||||
|
||||
float w = pa.dot(pq.cross(pb));
|
||||
if (m_raycastTestType == FRONT) {
|
||||
if (w < 0.0f) return false;
|
||||
if (w < 0.0f) {
|
||||
return false;
|
||||
}
|
||||
} else if (m_raycastTestType == BACK) {
|
||||
if (w > 0.0f) {
|
||||
return false;
|
||||
}
|
||||
} else if (m_raycastTestType == FRONT_AND_BACK) {
|
||||
if (!sameSign(u, w)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (m_raycastTestType == BACK) {
|
||||
if (w > 0.0f) return false;
|
||||
}
|
||||
else if (m_raycastTestType == FRONT_AND_BACK) {
|
||||
if (!sameSign(u, w)) return false;
|
||||
}
|
||||
|
||||
// If the line PQ is in the triangle plane (case where u=v=w=0)
|
||||
if (approxEqual(u, 0) && approxEqual(v, 0) && approxEqual(w, 0)) return false;
|
||||
|
||||
if ( approxEqual(u, 0)
|
||||
&& approxEqual(v, 0)
|
||||
&& approxEqual(w, 0)) {
|
||||
return false;
|
||||
}
|
||||
// Compute the barycentric coordinates (u, v, w) to determine the
|
||||
// int32_tersection point R, R = u * a + v * b + w * c
|
||||
float denom = 1.0f / (u + v + w);
|
||||
u *= denom;
|
||||
v *= denom;
|
||||
w *= denom;
|
||||
|
||||
// Compute the local hit point using the barycentric coordinates
|
||||
const vec3 localHitPoint = u * m_points[0] + v * m_points[1] + w * m_points[2];
|
||||
const float hitFraction = (localHitPoint - ray.point1).length() / pq.length();
|
||||
|
||||
if (hitFraction < 0.0f || hitFraction > ray.maxFraction) return false;
|
||||
|
||||
const float hitFraction = (localHitPoint - _ray.point1).length() / pq.length();
|
||||
if ( hitFraction < 0.0f
|
||||
|| hitFraction > _ray.maxFraction) {
|
||||
return false;
|
||||
}
|
||||
vec3 localHitNormal = (m_points[1] - m_points[0]).cross(m_points[2] - m_points[0]);
|
||||
if (localHitNormal.dot(pq) > 0.0f) localHitNormal = -localHitNormal;
|
||||
|
||||
raycastInfo.body = proxyShape->getBody();
|
||||
raycastInfo.proxyShape = proxyShape;
|
||||
raycastInfo.worldPoint = localHitPoint;
|
||||
raycastInfo.hitFraction = hitFraction;
|
||||
raycastInfo.worldNormal = localHitNormal;
|
||||
|
||||
if (localHitNormal.dot(pq) > 0.0f) {
|
||||
localHitNormal = -localHitNormal;
|
||||
}
|
||||
_raycastInfo.body = _proxyShape->getBody();
|
||||
_raycastInfo.proxyShape = _proxyShape;
|
||||
_raycastInfo.worldPoint = localHitPoint;
|
||||
_raycastInfo.hitFraction = hitFraction;
|
||||
_raycastInfo.worldNormal = localHitNormal;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Return the number of bytes used by the collision shape
|
||||
size_t TriangleShape::getSizeInBytes() const {
|
||||
return sizeof(TriangleShape);
|
||||
}
|
||||
|
||||
// Return a local support point in a given direction without the object margin
|
||||
vec3 TriangleShape::getLocalSupportPointWithoutMargin(const vec3& direction,
|
||||
void** cachedCollisionData) const {
|
||||
vec3 dotProducts(direction.dot(m_points[0]), direction.dot(m_points[1]), direction.dot(m_points[2]));
|
||||
vec3 TriangleShape::getLocalSupportPointWithoutMargin(const vec3& _direction,
|
||||
void** _cachedCollisionData) const {
|
||||
vec3 dotProducts(_direction.dot(m_points[0]), _direction.dot(m_points[1]), _direction.dot(m_points[2]));
|
||||
return m_points[dotProducts.getMaxAxis()];
|
||||
}
|
||||
|
||||
// Return the local bounds of the shape in x, y and z directions.
|
||||
// This method is used to compute the AABB of the box
|
||||
/**
|
||||
* @param min The minimum bounds of the shape in local-space coordinates
|
||||
* @param max The maximum bounds of the shape in local-space coordinates
|
||||
*/
|
||||
void TriangleShape::getLocalBounds(vec3& min, vec3& max) const {
|
||||
|
||||
void TriangleShape::getLocalBounds(vec3& _min, vec3& _max) const {
|
||||
const vec3 xAxis(m_points[0].x(), m_points[1].x(), m_points[2].x());
|
||||
const vec3 yAxis(m_points[0].y(), m_points[1].y(), m_points[2].y());
|
||||
const vec3 zAxis(m_points[0].z(), m_points[1].z(), m_points[2].z());
|
||||
min.setValue(xAxis.getMin(), yAxis.getMin(), zAxis.getMin());
|
||||
max.setValue(xAxis.getMax(), yAxis.getMax(), zAxis.getMax());
|
||||
|
||||
min -= vec3(m_margin, m_margin, m_margin);
|
||||
max += vec3(m_margin, m_margin, m_margin);
|
||||
_min.setValue(xAxis.getMin(), yAxis.getMin(), zAxis.getMin());
|
||||
_max.setValue(xAxis.getMax(), yAxis.getMax(), zAxis.getMax());
|
||||
_min -= vec3(m_margin, m_margin, m_margin);
|
||||
_max += vec3(m_margin, m_margin, m_margin);
|
||||
}
|
||||
|
||||
// Set the local scaling vector of the collision shape
|
||||
void TriangleShape::setLocalScaling(const vec3& scaling) {
|
||||
|
||||
m_points[0] = (m_points[0] / m_scaling) * scaling;
|
||||
m_points[1] = (m_points[1] / m_scaling) * scaling;
|
||||
m_points[2] = (m_points[2] / m_scaling) * scaling;
|
||||
|
||||
CollisionShape::setLocalScaling(scaling);
|
||||
void TriangleShape::setLocalScaling(const vec3& _scaling) {
|
||||
m_points[0] = (m_points[0] / m_scaling) * _scaling;
|
||||
m_points[1] = (m_points[1] / m_scaling) * _scaling;
|
||||
m_points[2] = (m_points[2] / m_scaling) * _scaling;
|
||||
CollisionShape::setLocalScaling(_scaling);
|
||||
}
|
||||
|
||||
// Return the local inertia tensor of the triangle shape
|
||||
/**
|
||||
* @param[out] tensor The 3x3 inertia tensor matrix of the shape in local-space
|
||||
* coordinates
|
||||
* @param mass Mass to use to compute the inertia tensor of the collision shape
|
||||
*/
|
||||
void TriangleShape::computeLocalInertiaTensor(etk::Matrix3x3& tensor, float mass) const {
|
||||
tensor.setZero();
|
||||
void TriangleShape::computeLocalInertiaTensor(etk::Matrix3x3& _tensor, float _mass) const {
|
||||
_tensor.setZero();
|
||||
}
|
||||
|
||||
// Update the AABB of a body using its collision shape
|
||||
/**
|
||||
* @param[out] aabb The axis-aligned bounding box (AABB) of the collision shape
|
||||
* computed in world-space coordinates
|
||||
* @param transform etk::Transform3D used to compute the AABB of the collision shape
|
||||
*/
|
||||
void TriangleShape::computeAABB(AABB& aabb, const etk::Transform3D& transform) const {
|
||||
|
||||
const vec3 worldPoint1 = transform * m_points[0];
|
||||
const vec3 worldPoint2 = transform * m_points[1];
|
||||
const vec3 worldPoint3 = transform * m_points[2];
|
||||
|
||||
void TriangleShape::computeAABB(AABB& _aabb, const etk::Transform3D& _transform) const {
|
||||
const vec3 worldPoint1 = _transform * m_points[0];
|
||||
const vec3 worldPoint2 = _transform * m_points[1];
|
||||
const vec3 worldPoint3 = _transform * m_points[2];
|
||||
const vec3 xAxis(worldPoint1.x(), worldPoint2.x(), worldPoint3.x());
|
||||
const vec3 yAxis(worldPoint1.y(), worldPoint2.y(), worldPoint3.y());
|
||||
const vec3 zAxis(worldPoint1.z(), worldPoint2.z(), worldPoint3.z());
|
||||
aabb.setMin(vec3(xAxis.getMin(), yAxis.getMin(), zAxis.getMin()));
|
||||
aabb.setMax(vec3(xAxis.getMax(), yAxis.getMax(), zAxis.getMax()));
|
||||
_aabb.setMin(vec3(xAxis.getMin(), yAxis.getMin(), zAxis.getMin()));
|
||||
_aabb.setMax(vec3(xAxis.getMax(), yAxis.getMax(), zAxis.getMax()));
|
||||
}
|
||||
|
||||
// Return true if a point is inside the collision shape
|
||||
bool TriangleShape::testPointInside(const vec3& localPoint, ProxyShape* proxyShape) const {
|
||||
bool TriangleShape::testPointInside(const vec3& _localPoint, ProxyShape* _proxyShape) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return the raycast test type (front, back, front-back)
|
||||
TriangleRaycastSide TriangleShape::getRaycastTestType() const {
|
||||
return m_raycastTestType;
|
||||
}
|
||||
|
||||
// Set the raycast test type (front, back, front-back)
|
||||
/**
|
||||
* @param testType Raycast test type for the triangle (front, back, front-back)
|
||||
*/
|
||||
void TriangleShape::setRaycastTestType(TriangleRaycastSide testType) {
|
||||
m_raycastTestType = testType;
|
||||
|
||||
void TriangleShape::setRaycastTestType(TriangleRaycastSide _testType) {
|
||||
m_raycastTestType = _testType;
|
||||
}
|
||||
|
||||
vec3 TriangleShape::getVertex(int32_t _index) const {
|
||||
assert( _index >= 0
|
||||
&& _index < 3);
|
||||
return m_points[_index];
|
||||
}
|
||||
|
||||
// Return the coordinates of a given vertex of the triangle
|
||||
/**
|
||||
* @param index Index (0 to 2) of a vertex of the triangle
|
||||
*/
|
||||
vec3 TriangleShape::getVertex(int32_t index) const {
|
||||
assert(index >= 0 && index < 3);
|
||||
return m_points[index];
|
||||
}
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -22,34 +25,46 @@ namespace ephysics {
|
||||
* This class represents a triangle collision shape that is centered
|
||||
* at the origin and defined three points.
|
||||
*/
|
||||
class TriangleShape : public ConvexShape {
|
||||
class TriangleShape: public ConvexShape {
|
||||
protected:
|
||||
vec3 m_points[3]; //!< Three points of the triangle
|
||||
TriangleRaycastSide m_raycastTestType; //!< Raycast test type for the triangle (front, back, front-back)
|
||||
/// Private copy-constructor
|
||||
TriangleShape(const TriangleShape& shape);
|
||||
TriangleShape(const TriangleShape& _shape);
|
||||
/// Private assignment operator
|
||||
TriangleShape& operator=(const TriangleShape& shape);
|
||||
TriangleShape& operator=(const TriangleShape& _shape);
|
||||
vec3 getLocalSupportPointWithoutMargin(const vec3& _direction, void** _cachedCollisionData) const override;
|
||||
bool testPointInside(const vec3& _localPoint, ProxyShape* _proxyShape) const override;
|
||||
bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const override;
|
||||
bool raycast(const Ray& _ray, RaycastInfo& _raycastInfo, ProxyShape* _proxyShape) const override;
|
||||
size_t getSizeInBytes() const override;
|
||||
public:
|
||||
/// Constructor
|
||||
TriangleShape(const vec3& point1, const vec3& point2, const vec3& point3,
|
||||
float margin = OBJECT_MARGIN);
|
||||
/// Destructor
|
||||
virtual ~TriangleShape();
|
||||
void getLocalBounds(vec3& min, vec3& max) const override;
|
||||
void setLocalScaling(const vec3& scaling) override;
|
||||
void computeLocalInertiaTensor(etk::Matrix3x3& tensor, float mass) const override;
|
||||
void computeAABB(AABB& aabb, const etk::Transform3D& transform) const override;
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param _point1 First point of the triangle
|
||||
* @param _point2 Second point of the triangle
|
||||
* @param _point3 Third point of the triangle
|
||||
* @param _margin The collision margin (in meters) around the collision shape
|
||||
*/
|
||||
TriangleShape(const vec3& _point1,
|
||||
const vec3& _point2,
|
||||
const vec3& _point3,
|
||||
float _margin = OBJECT_MARGIN);
|
||||
void getLocalBounds(vec3& _min, vec3& _max) const override;
|
||||
void setLocalScaling(const vec3& _scaling) override;
|
||||
void computeLocalInertiaTensor(etk::Matrix3x3& _tensor, float _mass) const override;
|
||||
void computeAABB(AABB& aabb, const etk::Transform3D& _transform) const override;
|
||||
/// Return the raycast test type (front, back, front-back)
|
||||
TriangleRaycastSide getRaycastTestType() const;
|
||||
// Set the raycast test type (front, back, front-back)
|
||||
void setRaycastTestType(TriangleRaycastSide testType);
|
||||
/// Return the coordinates of a given vertex of the triangle
|
||||
vec3 getVertex(int32_t index) const;
|
||||
/**
|
||||
* @brief Set the raycast test type (front, back, front-back)
|
||||
* @param[in] _testType Raycast test type for the triangle (front, back, front-back)
|
||||
*/
|
||||
void setRaycastTestType(TriangleRaycastSide _testType);
|
||||
/**
|
||||
* @brief Return the coordinates of a given vertex of the triangle
|
||||
* @param[in] _index Index (0 to 2) of a vertex of the triangle
|
||||
*/
|
||||
vec3 getVertex(int32_t _index) const;
|
||||
friend class ConcaveMeshRaycastCallback;
|
||||
friend class TriangleOverlapCallback;
|
||||
};
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
@ -1,9 +1,11 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
// Libraries
|
||||
#include <ephysics/constraint/BallAndSocketJoint.hpp>
|
||||
#include <ephysics/engine/ConstraintSolver.hpp>
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
@ -1,10 +1,11 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
// Libraries
|
||||
#include <ephysics/constraint/ContactPoint.hpp>
|
||||
#include <ephysics/collision/ProxyShape.hpp>
|
||||
|
||||
@ -12,24 +13,25 @@ using namespace ephysics;
|
||||
using namespace std;
|
||||
|
||||
// Constructor
|
||||
ContactPoint::ContactPoint(const ContactPointInfo& contactInfo)
|
||||
: m_body1(contactInfo.shape1->getBody()), m_body2(contactInfo.shape2->getBody()),
|
||||
m_normal(contactInfo.normal),
|
||||
m_penetrationDepth(contactInfo.penetrationDepth),
|
||||
m_localPointOnBody1(contactInfo.localPoint1),
|
||||
m_localPointOnBody2(contactInfo.localPoint2),
|
||||
m_worldPointOnBody1(contactInfo.shape1->getBody()->getTransform() *
|
||||
contactInfo.shape1->getLocalToBodyTransform() *
|
||||
contactInfo.localPoint1),
|
||||
m_worldPointOnBody2(contactInfo.shape2->getBody()->getTransform() *
|
||||
contactInfo.shape2->getLocalToBodyTransform() *
|
||||
contactInfo.localPoint2),
|
||||
m_isRestingContact(false) {
|
||||
ContactPoint::ContactPoint(const ContactPointInfo& _contactInfo):
|
||||
m_body1(_contactInfo.shape1->getBody()),
|
||||
m_body2(_contactInfo.shape2->getBody()),
|
||||
m_normal(_contactInfo.normal),
|
||||
m_penetrationDepth(_contactInfo.penetrationDepth),
|
||||
m_localPointOnBody1(_contactInfo.localPoint1),
|
||||
m_localPointOnBody2(_contactInfo.localPoint2),
|
||||
m_worldPointOnBody1(_contactInfo.shape1->getBody()->getTransform() *
|
||||
_contactInfo.shape1->getLocalToBodyTransform() *
|
||||
_contactInfo.localPoint1),
|
||||
m_worldPointOnBody2(_contactInfo.shape2->getBody()->getTransform() *
|
||||
_contactInfo.shape2->getLocalToBodyTransform() *
|
||||
_contactInfo.localPoint2),
|
||||
m_isRestingContact(false) {
|
||||
|
||||
m_frictionVectors[0] = vec3(0, 0, 0);
|
||||
m_frictionVectors[1] = vec3(0, 0, 0);
|
||||
|
||||
assert(m_penetrationDepth > 0.0);
|
||||
assert(m_penetrationDepth >= 0.0);
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -48,10 +51,10 @@ namespace ephysics {
|
||||
|
||||
}
|
||||
ContactPointInfo():
|
||||
shape1(nullptr),
|
||||
shape2(nullptr),
|
||||
collisionShape1(nullptr),
|
||||
collisionShape2(nullptr) {
|
||||
shape1(null),
|
||||
shape2(null),
|
||||
collisionShape1(null),
|
||||
collisionShape2(null) {
|
||||
// TODO: add it for etk::Vector
|
||||
}
|
||||
};
|
||||
|
@ -1,9 +1,11 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <ephysics/constraint/FixedJoint.hpp>
|
||||
#include <ephysics/engine/ConstraintSolver.hpp>
|
||||
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
@ -1,10 +1,11 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
// Libraries
|
||||
#include <ephysics/constraint/HingeJoint.hpp>
|
||||
#include <ephysics/engine/ConstraintSolver.hpp>
|
||||
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#include <ephysics/constraint/Joint.hpp>
|
||||
|
||||
@ -12,8 +15,8 @@ Joint::Joint(const JointInfo& jointInfo)
|
||||
m_positionCorrectionTechnique(jointInfo.positionCorrectionTechnique),
|
||||
m_isCollisionEnabled(jointInfo.isCollisionEnabled), m_isAlreadyInIsland(false) {
|
||||
|
||||
assert(m_body1 != nullptr);
|
||||
assert(m_body2 != nullptr);
|
||||
assert(m_body1 != null);
|
||||
assert(m_body2 != null);
|
||||
}
|
||||
|
||||
Joint::~Joint() {
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -47,8 +50,8 @@ namespace ephysics {
|
||||
bool isCollisionEnabled; //!< True if the two bodies of the joint are allowed to collide with each other
|
||||
/// Constructor
|
||||
JointInfo(JointType _constraintType):
|
||||
body1(nullptr),
|
||||
body2(nullptr),
|
||||
body1(null),
|
||||
body2(null),
|
||||
type(_constraintType),
|
||||
positionCorrectionTechnique(NON_LINEAR_GAUSS_SEIDEL),
|
||||
isCollisionEnabled(true) {
|
||||
|
@ -1,10 +1,11 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
// Libraries
|
||||
#include <ephysics/constraint/SliderJoint.hpp>
|
||||
|
||||
using namespace ephysics;
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
@ -1,9 +1,11 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <ephysics/engine/CollisionWorld.hpp>
|
||||
#include <ephysics/debug.hpp>
|
||||
|
||||
@ -13,220 +15,140 @@ using namespace std;
|
||||
CollisionWorld::CollisionWorld() :
|
||||
m_collisionDetection(this),
|
||||
m_currentBodyID(0),
|
||||
m_eventListener(nullptr) {
|
||||
m_eventListener(null) {
|
||||
|
||||
}
|
||||
|
||||
CollisionWorld::~CollisionWorld() {
|
||||
// Destroy all the collision bodies that have not been removed
|
||||
etk::Set<CollisionBody*>::Iterator itBodies;
|
||||
for (itBodies = m_bodies.begin(); itBodies != m_bodies.end(); ) {
|
||||
etk::Set<CollisionBody*>::Iterator itToRemove = itBodies;
|
||||
++itBodies;
|
||||
destroyCollisionBody(*itToRemove);
|
||||
while(m_bodies.size() != 0) {
|
||||
destroyCollisionBody(m_bodies[0]);
|
||||
}
|
||||
assert(m_bodies.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a collision body and add it to the world
|
||||
* @param transform etk::Transform3Dation mapping the local-space of the body to world-space
|
||||
* @return A pointer to the body that has been created in the world
|
||||
*/
|
||||
CollisionBody* CollisionWorld::createCollisionBody(const etk::Transform3D& transform) {
|
||||
|
||||
CollisionBody* CollisionWorld::createCollisionBody(const etk::Transform3D& _transform) {
|
||||
// Get the next available body ID
|
||||
bodyindex bodyID = computeNextAvailableBodyID();
|
||||
// Largest index cannot be used (it is used for invalid index)
|
||||
EPHY_ASSERT(bodyID < std::numeric_limits<ephysics::bodyindex>::max(), "index too big");
|
||||
EPHY_ASSERT(bodyID < UINT64_MAX, "index too big");
|
||||
// Create the collision body
|
||||
CollisionBody* collisionBody = new CollisionBody(transform, *this, bodyID);
|
||||
EPHY_ASSERT(collisionBody != nullptr, "empty Body collision");
|
||||
CollisionBody* collisionBody = ETK_NEW(CollisionBody, _transform, *this, bodyID);
|
||||
EPHY_ASSERT(collisionBody != null, "empty Body collision");
|
||||
// Add the collision body to the world
|
||||
m_bodies.add(collisionBody);
|
||||
// Return the pointer to the rigid body
|
||||
return collisionBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Destroy a collision body
|
||||
* @param collisionBody Pointer to the body to destroy
|
||||
*/
|
||||
void CollisionWorld::destroyCollisionBody(CollisionBody* collisionBody) {
|
||||
|
||||
void CollisionWorld::destroyCollisionBody(CollisionBody* _collisionBody) {
|
||||
// Remove all the collision shapes of the body
|
||||
collisionBody->removeAllCollisionShapes();
|
||||
|
||||
_collisionBody->removeAllCollisionShapes();
|
||||
// Add the body ID to the list of free IDs
|
||||
m_freeBodiesIDs.pushBack(collisionBody->getID());
|
||||
|
||||
m_freeBodiesIDs.pushBack(_collisionBody->getID());
|
||||
// Remove the collision body from the list of bodies
|
||||
m_bodies.erase(m_bodies.find(collisionBody));
|
||||
|
||||
delete collisionBody;
|
||||
collisionBody = nullptr;
|
||||
m_bodies.erase(m_bodies.find(_collisionBody));
|
||||
ETK_DELETE(CollisionBody, _collisionBody);
|
||||
_collisionBody = null;
|
||||
}
|
||||
|
||||
// Return the next available body ID
|
||||
bodyindex CollisionWorld::computeNextAvailableBodyID() {
|
||||
|
||||
// Compute the body ID
|
||||
bodyindex bodyID;
|
||||
if (!m_freeBodiesIDs.empty()) {
|
||||
bodyID = m_freeBodiesIDs.back();
|
||||
m_freeBodiesIDs.popBack();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
bodyID = m_currentBodyID;
|
||||
m_currentBodyID++;
|
||||
}
|
||||
|
||||
return bodyID;
|
||||
}
|
||||
|
||||
// Reset all the contact manifolds linked list of each body
|
||||
void CollisionWorld::resetContactManifoldListsOfBodies() {
|
||||
|
||||
// For each rigid body of the world
|
||||
for (etk::Set<CollisionBody*>::Iterator it = m_bodies.begin(); it != m_bodies.end(); ++it) {
|
||||
|
||||
// Reset the contact manifold list of the body
|
||||
(*it)->resetContactManifoldsList();
|
||||
}
|
||||
}
|
||||
|
||||
// Test if the AABBs of two bodies overlap
|
||||
/**
|
||||
* @param body1 Pointer to the first body to test
|
||||
* @param body2 Pointer to the second body to test
|
||||
* @return True if the AABBs of the two bodies overlap and false otherwise
|
||||
*/
|
||||
bool CollisionWorld::testAABBOverlap(const CollisionBody* body1,
|
||||
const CollisionBody* body2) const {
|
||||
|
||||
bool CollisionWorld::testAABBOverlap(const CollisionBody* _body1, const CollisionBody* _body2) const {
|
||||
// If one of the body is not active, we return no overlap
|
||||
if (!body1->isActive() || !body2->isActive()) return false;
|
||||
|
||||
if ( !_body1->isActive()
|
||||
|| !_body2->isActive()) {
|
||||
return false;
|
||||
}
|
||||
// Compute the AABBs of both bodies
|
||||
AABB body1AABB = body1->getAABB();
|
||||
AABB body2AABB = body2->getAABB();
|
||||
|
||||
AABB body1AABB = _body1->getAABB();
|
||||
AABB body2AABB = _body2->getAABB();
|
||||
// Return true if the two AABBs overlap
|
||||
return body1AABB.testCollision(body2AABB);
|
||||
}
|
||||
|
||||
// Test and report collisions between a given shape and all the others
|
||||
// shapes of the world.
|
||||
/**
|
||||
* @param shape Pointer to the proxy shape to test
|
||||
* @param callback Pointer to the object with the callback method
|
||||
*/
|
||||
void CollisionWorld::testCollision(const ProxyShape* shape,
|
||||
CollisionCallback* callback) {
|
||||
|
||||
void CollisionWorld::testCollision(const ProxyShape* _shape, CollisionCallback* _callback) {
|
||||
// Reset all the contact manifolds lists of each body
|
||||
resetContactManifoldListsOfBodies();
|
||||
|
||||
// Create the sets of shapes
|
||||
etk::Set<uint32_t> shapes;
|
||||
shapes.add(shape->m_broadPhaseID);
|
||||
shapes.add(_shape->m_broadPhaseID);
|
||||
etk::Set<uint32_t> emptySet;
|
||||
|
||||
// Perform the collision detection and report contacts
|
||||
m_collisionDetection.testCollisionBetweenShapes(callback, shapes, emptySet);
|
||||
m_collisionDetection.testCollisionBetweenShapes(_callback, shapes, emptySet);
|
||||
}
|
||||
|
||||
// Test and report collisions between two given shapes
|
||||
/**
|
||||
* @param shape1 Pointer to the first proxy shape to test
|
||||
* @param shape2 Pointer to the second proxy shape to test
|
||||
* @param callback Pointer to the object with the callback method
|
||||
*/
|
||||
void CollisionWorld::testCollision(const ProxyShape* shape1,
|
||||
const ProxyShape* shape2,
|
||||
CollisionCallback* callback) {
|
||||
|
||||
void CollisionWorld::testCollision(const ProxyShape* _shape1, const ProxyShape* _shape2, CollisionCallback* _callback) {
|
||||
// Reset all the contact manifolds lists of each body
|
||||
resetContactManifoldListsOfBodies();
|
||||
|
||||
// Create the sets of shapes
|
||||
etk::Set<uint32_t> shapes1;
|
||||
shapes1.add(shape1->m_broadPhaseID);
|
||||
shapes1.add(_shape1->m_broadPhaseID);
|
||||
etk::Set<uint32_t> shapes2;
|
||||
shapes2.add(shape2->m_broadPhaseID);
|
||||
|
||||
shapes2.add(_shape2->m_broadPhaseID);
|
||||
// Perform the collision detection and report contacts
|
||||
m_collisionDetection.testCollisionBetweenShapes(callback, shapes1, shapes2);
|
||||
m_collisionDetection.testCollisionBetweenShapes(_callback, shapes1, shapes2);
|
||||
}
|
||||
|
||||
// Test and report collisions between a body and all the others bodies of the
|
||||
// world
|
||||
/**
|
||||
* @param body Pointer to the first body to test
|
||||
* @param callback Pointer to the object with the callback method
|
||||
*/
|
||||
void CollisionWorld::testCollision(const CollisionBody* body,
|
||||
CollisionCallback* callback) {
|
||||
|
||||
void CollisionWorld::testCollision(const CollisionBody* _body, CollisionCallback* _callback) {
|
||||
// Reset all the contact manifolds lists of each body
|
||||
resetContactManifoldListsOfBodies();
|
||||
|
||||
// Create the sets of shapes
|
||||
etk::Set<uint32_t> shapes1;
|
||||
|
||||
// For each shape of the body
|
||||
for (const ProxyShape* shape=body->getProxyShapesList(); shape != nullptr;
|
||||
shape = shape->getNext()) {
|
||||
for (const ProxyShape* shape = _body->getProxyShapesList();
|
||||
shape != null;
|
||||
shape = shape->getNext()) {
|
||||
shapes1.add(shape->m_broadPhaseID);
|
||||
}
|
||||
|
||||
etk::Set<uint32_t> emptySet;
|
||||
|
||||
// Perform the collision detection and report contacts
|
||||
m_collisionDetection.testCollisionBetweenShapes(callback, shapes1, emptySet);
|
||||
m_collisionDetection.testCollisionBetweenShapes(_callback, shapes1, emptySet);
|
||||
}
|
||||
|
||||
// Test and report collisions between two bodies
|
||||
/**
|
||||
* @param body1 Pointer to the first body to test
|
||||
* @param body2 Pointer to the second body to test
|
||||
* @param callback Pointer to the object with the callback method
|
||||
*/
|
||||
void CollisionWorld::testCollision(const CollisionBody* body1,
|
||||
const CollisionBody* body2,
|
||||
CollisionCallback* callback) {
|
||||
|
||||
void CollisionWorld::testCollision(const CollisionBody* _body1, const CollisionBody* _body2, CollisionCallback* _callback) {
|
||||
// Reset all the contact manifolds lists of each body
|
||||
resetContactManifoldListsOfBodies();
|
||||
|
||||
// Create the sets of shapes
|
||||
etk::Set<uint32_t> shapes1;
|
||||
for (const ProxyShape* shape=body1->getProxyShapesList(); shape != nullptr;
|
||||
shape = shape->getNext()) {
|
||||
for (const ProxyShape* shape = _body1->getProxyShapesList();
|
||||
shape != null;
|
||||
shape = shape->getNext()) {
|
||||
shapes1.add(shape->m_broadPhaseID);
|
||||
}
|
||||
|
||||
etk::Set<uint32_t> shapes2;
|
||||
for (const ProxyShape* shape=body2->getProxyShapesList(); shape != nullptr;
|
||||
shape = shape->getNext()) {
|
||||
for (const ProxyShape* shape = _body2->getProxyShapesList();
|
||||
shape != null;
|
||||
shape = shape->getNext()) {
|
||||
shapes2.add(shape->m_broadPhaseID);
|
||||
}
|
||||
|
||||
// Perform the collision detection and report contacts
|
||||
m_collisionDetection.testCollisionBetweenShapes(callback, shapes1, shapes2);
|
||||
m_collisionDetection.testCollisionBetweenShapes(_callback, shapes1, shapes2);
|
||||
}
|
||||
|
||||
// Test and report collisions between all shapes of the world
|
||||
/**
|
||||
* @param callback Pointer to the object with the callback method
|
||||
*/
|
||||
void CollisionWorld::testCollision(CollisionCallback* callback) {
|
||||
|
||||
void CollisionWorld::testCollision(CollisionCallback* _callback) {
|
||||
// Reset all the contact manifolds lists of each body
|
||||
resetContactManifoldListsOfBodies();
|
||||
|
||||
etk::Set<uint32_t> emptySet;
|
||||
|
||||
// Perform the collision detection and report contacts
|
||||
m_collisionDetection.testCollisionBetweenShapes(callback, emptySet, emptySet);
|
||||
m_collisionDetection.testCollisionBetweenShapes(_callback, emptySet, emptySet);
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -57,9 +60,16 @@ namespace ephysics {
|
||||
etk::Set<CollisionBody*>::Iterator getBodiesEndIterator() {
|
||||
return m_bodies.end();
|
||||
}
|
||||
/// Create a collision body
|
||||
/**
|
||||
* @brief Create a collision body and add it to the world
|
||||
* @param transform etk::Transform3Dation mapping the local-space of the body to world-space
|
||||
* @return A pointer to the body that has been created in the world
|
||||
*/
|
||||
CollisionBody* createCollisionBody(const etk::Transform3D& transform);
|
||||
/// Destroy a collision body
|
||||
/**
|
||||
* @brief Destroy a collision body
|
||||
* @param collisionBody Pointer to the body to destroy
|
||||
*/
|
||||
void destroyCollisionBody(CollisionBody* collisionBody);
|
||||
/**
|
||||
* @brief Set the collision dispatch configuration
|
||||
@ -82,7 +92,12 @@ namespace ephysics {
|
||||
unsigned short _raycastWithCategoryMaskBits = 0xFFFF) const {
|
||||
m_collisionDetection.raycast(_raycastCallback, _ray, _raycastWithCategoryMaskBits);
|
||||
}
|
||||
/// Test if the AABBs of two bodies overlap
|
||||
/**
|
||||
* @brief Test if the AABBs of two bodies overlap
|
||||
* @param _body1 Pointer to the first body to test
|
||||
* @param _body2 Pointer to the second body to test
|
||||
* @return True if the AABBs of the two bodies overlap and false otherwise
|
||||
*/
|
||||
bool testAABBOverlap(const CollisionBody* _body1,
|
||||
const CollisionBody* _body2) const;
|
||||
/**
|
||||
@ -94,23 +109,42 @@ namespace ephysics {
|
||||
const ProxyShape* _shape2) const {
|
||||
return m_collisionDetection.testAABBOverlap(_shape1, _shape2);
|
||||
}
|
||||
/// Test and report collisions between a given shape and all the others
|
||||
/// shapes of the world
|
||||
/**
|
||||
* @brief Test and report collisions between a given shape and all the others shapes of the world.
|
||||
* @param _shape Pointer to the proxy shape to test
|
||||
* @param _callback Pointer to the object with the callback method
|
||||
*/
|
||||
virtual void testCollision(const ProxyShape* _shape,
|
||||
CollisionCallback* _callback);
|
||||
/// Test and report collisions between two given shapes
|
||||
/**
|
||||
* @briefTest and report collisions between two given shapes
|
||||
* @param _shape1 Pointer to the first proxy shape to test
|
||||
* @param _shape2 Pointer to the second proxy shape to test
|
||||
* @param _callback Pointer to the object with the callback method
|
||||
*/
|
||||
virtual void testCollision(const ProxyShape* _shape1,
|
||||
const ProxyShape* _shape2,
|
||||
CollisionCallback* _callback);
|
||||
/// Test and report collisions between a body and all the others bodies of the
|
||||
/// world
|
||||
/**
|
||||
* @brief Test and report collisions between a body and all the others bodies of the world.
|
||||
* @param _body Pointer to the first body to test
|
||||
* @param _callback Pointer to the object with the callback method
|
||||
*/
|
||||
virtual void testCollision(const CollisionBody* _body,
|
||||
CollisionCallback* _callback);
|
||||
/// Test and report collisions between two bodies
|
||||
/**
|
||||
* @brief Test and report collisions between two bodies
|
||||
* @param _body1 Pointer to the first body to test
|
||||
* @param _body2 Pointer to the second body to test
|
||||
* @param _callback Pointer to the object with the callback method
|
||||
*/
|
||||
virtual void testCollision(const CollisionBody* _body1,
|
||||
const CollisionBody* _body2,
|
||||
CollisionCallback* _callback);
|
||||
/// Test and report collisions between all shapes of the world
|
||||
/**
|
||||
* @brief Test and report collisions between all shapes of the world
|
||||
* @param _callback Pointer to the object with the callback method
|
||||
*/
|
||||
virtual void testCollision(CollisionCallback* _callback);
|
||||
friend class CollisionDetection;
|
||||
friend class CollisionBody;
|
||||
|
@ -1,9 +1,11 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <ephysics/engine/ConstraintSolver.hpp>
|
||||
#include <ephysics/engine/Profiler.hpp>
|
||||
|
||||
@ -18,7 +20,7 @@ ConstraintSolver::ConstraintSolver(const etk::Map<RigidBody*, uint32_t>& _mapBod
|
||||
|
||||
void ConstraintSolver::initializeForIsland(float _dt, Island* _island) {
|
||||
PROFILE("ConstraintSolver::initializeForIsland()");
|
||||
assert(_island != nullptr);
|
||||
assert(_island != null);
|
||||
assert(_island->getNbBodies() > 0);
|
||||
assert(_island->getNbJoints() > 0);
|
||||
// Set the current time step
|
||||
@ -40,7 +42,7 @@ void ConstraintSolver::initializeForIsland(float _dt, Island* _island) {
|
||||
|
||||
void ConstraintSolver::solveVelocityConstraints(Island* _island) {
|
||||
PROFILE("ConstraintSolver::solveVelocityConstraints()");
|
||||
assert(_island != nullptr);
|
||||
assert(_island != null);
|
||||
assert(_island->getNbJoints() > 0);
|
||||
// For each joint of the island
|
||||
Joint** joints = _island->getJoints();
|
||||
@ -51,7 +53,7 @@ void ConstraintSolver::solveVelocityConstraints(Island* _island) {
|
||||
|
||||
void ConstraintSolver::solvePositionConstraints(Island* _island) {
|
||||
PROFILE("ConstraintSolver::solvePositionConstraints()");
|
||||
assert(_island != nullptr);
|
||||
assert(_island != null);
|
||||
assert(_island->getNbJoints() > 0);
|
||||
Joint** joints = _island->getJoints();
|
||||
for (uint32_t iii=0; iii < _island->getNbJoints(); ++iii) {
|
||||
@ -61,16 +63,16 @@ void ConstraintSolver::solvePositionConstraints(Island* _island) {
|
||||
|
||||
void ConstraintSolver::setConstrainedVelocitiesArrays(vec3* _constrainedLinearVelocities,
|
||||
vec3* _constrainedAngularVelocities) {
|
||||
assert(_constrainedLinearVelocities != nullptr);
|
||||
assert(_constrainedAngularVelocities != nullptr);
|
||||
assert(_constrainedLinearVelocities != null);
|
||||
assert(_constrainedAngularVelocities != null);
|
||||
m_constraintSolverData.linearVelocities = _constrainedLinearVelocities;
|
||||
m_constraintSolverData.angularVelocities = _constrainedAngularVelocities;
|
||||
}
|
||||
|
||||
void ConstraintSolver::setConstrainedPositionsArrays(vec3* _constrainedPositions,
|
||||
etk::Quaternion* _constrainedOrientations) {
|
||||
assert(_constrainedPositions != nullptr);
|
||||
assert(_constrainedOrientations != nullptr);
|
||||
assert(_constrainedPositions != null);
|
||||
assert(_constrainedOrientations != null);
|
||||
m_constraintSolverData.positions = _constrainedPositions;
|
||||
m_constraintSolverData.orientations = _constrainedOrientations;
|
||||
}
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -27,10 +30,10 @@ namespace ephysics {
|
||||
bool isWarmStartingActive; //!< True if warm starting of the solver is active
|
||||
/// Constructor
|
||||
ConstraintSolverData(const etk::Map<RigidBody*, uint32_t>& refMapBodyToConstrainedVelocityIndex):
|
||||
linearVelocities(nullptr),
|
||||
angularVelocities(nullptr),
|
||||
positions(nullptr),
|
||||
orientations(nullptr),
|
||||
linearVelocities(null),
|
||||
angularVelocities(null),
|
||||
positions(null),
|
||||
orientations(null),
|
||||
mapBodyToConstrainedVelocityIndex(refMapBodyToConstrainedVelocityIndex) {
|
||||
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -115,7 +118,6 @@ namespace ephysics {
|
||||
bool isRestingContact; //!< True if the contact was existing last time step
|
||||
ContactPoint* externalContact; //!< Pointer to the external contact
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Contact solver int32_ternal data structure to store all the information relative to a contact manifold.
|
||||
*/
|
||||
@ -163,76 +165,147 @@ namespace ephysics {
|
||||
vec3* m_splitLinearVelocities; //!< Split linear velocities for the position contact solver (split impulse)
|
||||
vec3* m_splitAngularVelocities; //!< Split angular velocities for the position contact solver (split impulse)
|
||||
float m_timeStep; //!< Current time step
|
||||
ContactManifoldSolver* m_contactConstraints; //!< Contact constraints
|
||||
uint32_t m_numberContactManifolds; //!< Number of contact constraints
|
||||
etk::Vector<ContactManifoldSolver> m_contactConstraints; //!< Contact constraints
|
||||
vec3* m_linearVelocities; //!< Array of linear velocities
|
||||
vec3* m_angularVelocities; //!< Array of angular velocities
|
||||
const etk::Map<RigidBody*, uint32_t>& m_mapBodyToConstrainedVelocityIndex; //!< Reference to the map of rigid body to their index in the constrained velocities array
|
||||
bool m_isWarmStartingActive; //!< True if the warm starting of the solver is active
|
||||
bool m_isSplitImpulseActive; //!< True if the split impulse position correction is active
|
||||
bool m_isSolveFrictionAtContactManifoldCenterActive; //!< True if we solve 3 friction constraints at the contact manifold center only instead of 2 friction constraints at each contact point
|
||||
/// Initialize the contact constraints before solving the system
|
||||
/**
|
||||
* @brief Initialize the contact constraints before solving the system
|
||||
*/
|
||||
void initializeContactConstraints();
|
||||
/// Apply an impulse to the two bodies of a constraint
|
||||
void applyImpulse(const Impulse& impulse, const ContactManifoldSolver& manifold);
|
||||
/// Apply an impulse to the two bodies of a constraint
|
||||
void applySplitImpulse(const Impulse& impulse,
|
||||
const ContactManifoldSolver& manifold);
|
||||
/// Compute the collision restitution factor from the restitution factor of each body
|
||||
float computeMixedRestitutionFactor(RigidBody *body1,
|
||||
RigidBody *body2) const;
|
||||
/// Compute the mixed friction coefficient from the friction coefficient of each body
|
||||
float computeMixedFrictionCoefficient(RigidBody* body1,
|
||||
RigidBody* body2) const;
|
||||
/// Compute th mixed rolling resistance factor between two bodies
|
||||
float computeMixedRollingResistance(RigidBody* body1, RigidBody* body2) const;
|
||||
/// Compute the two unit orthogonal vectors "t1" and "t2" that span the tangential friction
|
||||
/// plane for a contact point. The two vectors have to be
|
||||
/// such that : t1 x t2 = contactNormal.
|
||||
void computeFrictionVectors(const vec3& deltaVelocity,
|
||||
ContactPointSolver &contactPoint) const;
|
||||
/// Compute the two unit orthogonal vectors "t1" and "t2" that span the tangential friction
|
||||
/// plane for a contact manifold. The two vectors have to be
|
||||
/// such that : t1 x t2 = contactNormal.
|
||||
void computeFrictionVectors(const vec3& deltaVelocity,
|
||||
ContactManifoldSolver& contactPoint) const;
|
||||
/// Compute a penetration constraint impulse
|
||||
const Impulse computePenetrationImpulse(float deltaLambda,
|
||||
const ContactPointSolver& contactPoint) const;
|
||||
/// Compute the first friction constraint impulse
|
||||
const Impulse computeFriction1Impulse(float deltaLambda,
|
||||
const ContactPointSolver& contactPoint) const;
|
||||
/// Compute the second friction constraint impulse
|
||||
const Impulse computeFriction2Impulse(float deltaLambda,
|
||||
const ContactPointSolver& contactPoint) const;
|
||||
/**
|
||||
* @brief Apply an impulse to the two bodies of a constraint
|
||||
* @param[in] _impulse Impulse to apply
|
||||
* @param[in] _manifold Constraint to apply the impulse
|
||||
*/
|
||||
void applyImpulse(const Impulse& _impulse, const ContactManifoldSolver& _manifold);
|
||||
/**
|
||||
* @brief Apply an impulse to the two bodies of a constraint
|
||||
* @param[in] _impulse Impulse to apply
|
||||
* @param[in] _manifold Constraint to apply the impulse
|
||||
*/
|
||||
void applySplitImpulse(const Impulse& _impulse, const ContactManifoldSolver& _manifold);
|
||||
/**
|
||||
* @brief Compute the collision restitution factor from the restitution factor of each body
|
||||
* @param[in] _body1 First body to compute
|
||||
* @param[in] _body2 Second body to compute
|
||||
* @return Collision restitution factor
|
||||
*/
|
||||
float computeMixedRestitutionFactor(RigidBody* _body1, RigidBody* _body2) const;
|
||||
/**
|
||||
* @brief Compute the mixed friction coefficient from the friction coefficient of each body
|
||||
* @param[in] _body1 First body to compute
|
||||
* @param[in] _body2 Second body to compute
|
||||
* @return Mixed friction coefficient
|
||||
*/
|
||||
float computeMixedFrictionCoefficient(RigidBody* _body1, RigidBody* _body2) const;
|
||||
/**
|
||||
* @brief Compute the mixed rolling resistance factor between two bodies
|
||||
* @param[in] _body1 First body to compute
|
||||
* @param[in] _body2 Second body to compute
|
||||
* @return Mixed rolling resistance
|
||||
*/
|
||||
float computeMixedRollingResistance(RigidBody* _body1, RigidBody* _body2) const;
|
||||
/**
|
||||
* @brief Compute the two unit orthogonal vectors "t1" and "t2" that span the tangential friction
|
||||
* plane for a contact point. The two vectors have to be such that : t1 x t2 = contactNormal.
|
||||
* @param[in] _deltaVelocity Velocity ratio (with the delta time step)
|
||||
* @param[in,out] _contactPoint Contact point property
|
||||
*/
|
||||
void computeFrictionVectors(const vec3& _deltaVelocity, ContactPointSolver& _contactPoint) const;
|
||||
/**
|
||||
* @brief Compute the two unit orthogonal vectors "t1" and "t2" that span the tangential friction
|
||||
* plane for a contact manifold. The two vectors have to be such that : t1 x t2 = contactNormal.
|
||||
* @param[in] _deltaVelocity Velocity ratio (with the delta time step)
|
||||
* @param[in,out] _contactPoint Contact point property
|
||||
*/
|
||||
void computeFrictionVectors(const vec3& _deltaVelocity, ContactManifoldSolver& _contactPoint) const;
|
||||
/**
|
||||
* @brief Compute a penetration constraint impulse
|
||||
* @param[in] _deltaLambda Ratio to apply at the calculation.
|
||||
* @param[in,out] _contactPoint Contact point property
|
||||
* @return Impulse of the penetration result
|
||||
*/
|
||||
const Impulse computePenetrationImpulse(float _deltaLambda, const ContactPointSolver& _contactPoint) const;
|
||||
/**
|
||||
* @brief Compute the first friction constraint impulse
|
||||
* @param[in] _deltaLambda Ratio to apply at the calculation.
|
||||
* @param[in] _contactPoint Contact point property
|
||||
* @return Impulse of the friction result
|
||||
*/
|
||||
const Impulse computeFriction1Impulse(float _deltaLambda, const ContactPointSolver& _contactPoint) const;
|
||||
/**
|
||||
* @brief Compute the second friction constraint impulse
|
||||
* @param[in] _deltaLambda Ratio to apply at the calculation.
|
||||
* @param[in] _contactPoint Contact point property
|
||||
* @return Impulse of the friction result
|
||||
*/
|
||||
const Impulse computeFriction2Impulse(float _deltaLambda, const ContactPointSolver& _contactPoint) const;
|
||||
public:
|
||||
/// Constructor
|
||||
ContactSolver(const etk::Map<RigidBody*, uint32_t>& mapBodyToVelocityIndex);
|
||||
/// Destructor
|
||||
virtual ~ContactSolver();
|
||||
/// Initialize the constraint solver for a given island
|
||||
void initializeForIsland(float dt, Island* island);
|
||||
/// Set the split velocities arrays
|
||||
void setSplitVelocitiesArrays(vec3* splitLinearVelocities,
|
||||
vec3* splitAngularVelocities);
|
||||
/// Set the constrained velocities arrays
|
||||
void setConstrainedVelocitiesArrays(vec3* constrainedLinearVelocities,
|
||||
vec3* constrainedAngularVelocities);
|
||||
/// Warm start the solver.
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param[in] _mapBodyToVelocityIndex
|
||||
*/
|
||||
ContactSolver(const etk::Map<RigidBody*, uint32_t>& _mapBodyToVelocityIndex);
|
||||
/**
|
||||
* @brief Virtualize the destructor
|
||||
*/
|
||||
virtual ~ContactSolver() = default;
|
||||
/**
|
||||
* @brief Initialize the constraint solver for a given island
|
||||
* @param[in] _dt Delta step time
|
||||
* @param[in] _island Island list property
|
||||
*/
|
||||
void initializeForIsland(float _dt, Island* _island);
|
||||
/**
|
||||
* @brief Set the split velocities arrays
|
||||
* @param[in] _splitLinearVelocities Split linear velocities Table pointer (not free)
|
||||
* @param[in] _splitAngularVelocities Split angular velocities Table pointer (not free)
|
||||
*/
|
||||
void setSplitVelocitiesArrays(vec3* _splitLinearVelocities, vec3* _splitAngularVelocities);
|
||||
/**
|
||||
* @brief Set the constrained velocities arrays
|
||||
* @param[in] _constrainedLinearVelocities Constrained Linear velocities Table pointer (not free)
|
||||
* @param[in] _constrainedAngularVelocities Constrained angular velocities Table pointer (not free)
|
||||
*/
|
||||
void setConstrainedVelocitiesArrays(vec3* _constrainedLinearVelocities, vec3* _constrainedAngularVelocities);
|
||||
/**
|
||||
* @brief Warm start the solver.
|
||||
* For each constraint, we apply the previous impulse (from the previous step)
|
||||
* at the beginning. With this technique, we will converge faster towards the solution of the linear system
|
||||
*/
|
||||
void warmStart();
|
||||
/// Store the computed impulses to use them to
|
||||
/// warm start the solver at the next iteration
|
||||
/**
|
||||
* @brief Store the computed impulses to use them to warm start the solver at the next iteration
|
||||
*/
|
||||
void storeImpulses();
|
||||
/// Solve the contacts
|
||||
/**
|
||||
* @brief Solve the contacts
|
||||
*/
|
||||
void solve();
|
||||
/// Return true if the split impulses position correction technique is used for contacts
|
||||
/**
|
||||
* @brief Get the split impulses position correction technique is used for contacts
|
||||
* @return true the split status is Enable
|
||||
* @return true the split status is Disable
|
||||
*/
|
||||
bool isSplitImpulseActive() const;
|
||||
/// Activate or Deactivate the split impulses for contacts
|
||||
void setIsSplitImpulseActive(bool isActive);
|
||||
/// Activate or deactivate the solving of friction constraints at the center of
|
||||
/**
|
||||
* @brief Activate or Deactivate the split impulses for contacts
|
||||
* @param[in] _isActive status to set.
|
||||
*/
|
||||
void setIsSplitImpulseActive(bool _isActive);
|
||||
/**
|
||||
* @brief Activate or deactivate the solving of friction constraints at the center of
|
||||
/// the contact manifold instead of solving them at each contact point
|
||||
void setIsSolveFrictionAtContactManifoldCenterActive(bool isActive);
|
||||
/// Clean up the constraint solver
|
||||
* @param[in] _isActive Enable or not the center inertie
|
||||
*/
|
||||
void setIsSolveFrictionAtContactManifoldCenterActive(bool _isActive);
|
||||
/**
|
||||
* @brief Clean up the constraint solver
|
||||
*/
|
||||
void cleanup();
|
||||
};
|
||||
|
||||
|
@ -1,9 +1,11 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
|
||||
#include <ephysics/engine/DynamicsWorld.hpp>
|
||||
#include <ephysics/constraint/BallAndSocketJoint.hpp>
|
||||
#include <ephysics/constraint/SliderJoint.hpp>
|
||||
@ -20,13 +22,6 @@ ephysics::DynamicsWorld::DynamicsWorld(const vec3& _gravity):
|
||||
m_isSleepingEnabled(SPLEEPING_ENABLED),
|
||||
m_gravity(_gravity),
|
||||
m_isGravityEnabled(true),
|
||||
m_constrainedLinearVelocities(nullptr),
|
||||
m_constrainedAngularVelocities(nullptr),
|
||||
m_splitLinearVelocities(nullptr),
|
||||
m_splitAngularVelocities(nullptr),
|
||||
m_constrainedPositions(nullptr),
|
||||
m_constrainedOrientations(nullptr),
|
||||
m_islands(),
|
||||
m_numberBodiesCapacity(0),
|
||||
m_sleepLinearVelocity(DEFAULT_SLEEP_LINEAR_VELOCITY),
|
||||
m_sleepAngularVelocity(DEFAULT_SLEEP_ANGULAR_VELOCITY),
|
||||
@ -52,18 +47,18 @@ ephysics::DynamicsWorld::~DynamicsWorld() {
|
||||
// Release the memory allocated for the islands
|
||||
for (auto &it: m_islands) {
|
||||
// Call the island destructor
|
||||
delete it;
|
||||
it = nullptr;
|
||||
ETK_DELETE(Island, it);
|
||||
it = null;
|
||||
}
|
||||
m_islands.clear();
|
||||
// Release the memory allocated for the bodies velocity arrays
|
||||
if (m_numberBodiesCapacity > 0) {
|
||||
delete[] m_splitLinearVelocities;
|
||||
delete[] m_splitAngularVelocities;
|
||||
delete[] m_constrainedLinearVelocities;
|
||||
delete[] m_constrainedAngularVelocities;
|
||||
delete[] m_constrainedPositions;
|
||||
delete[] m_constrainedOrientations;
|
||||
m_splitLinearVelocities.clear();
|
||||
m_splitAngularVelocities.clear();
|
||||
m_constrainedLinearVelocities.clear();
|
||||
m_constrainedAngularVelocities.clear();
|
||||
m_constrainedPositions.clear();
|
||||
m_constrainedOrientations.clear();
|
||||
}
|
||||
assert(m_joints.size() == 0);
|
||||
assert(m_rigidBodies.size() == 0);
|
||||
@ -85,7 +80,7 @@ void ephysics::DynamicsWorld::update(float timeStep) {
|
||||
PROFILE("ephysics::DynamicsWorld::update()");
|
||||
m_timeStep = timeStep;
|
||||
// Notify the event listener about the beginning of an int32_ternal tick
|
||||
if (m_eventListener != nullptr) {
|
||||
if (m_eventListener != null) {
|
||||
m_eventListener->beginInternalTick();
|
||||
}
|
||||
// Reset all the contact manifolds lists of each body
|
||||
@ -112,7 +107,7 @@ void ephysics::DynamicsWorld::update(float timeStep) {
|
||||
updateSleepingBodies();
|
||||
}
|
||||
// Notify the event listener about the end of an int32_ternal tick
|
||||
if (m_eventListener != nullptr) {
|
||||
if (m_eventListener != null) {
|
||||
m_eventListener->endInternalTick();
|
||||
}
|
||||
// Reset the external force and torque applied to the bodies
|
||||
@ -178,23 +173,22 @@ void ephysics::DynamicsWorld::initVelocityArrays() {
|
||||
uint32_t nbBodies = m_rigidBodies.size();
|
||||
if (m_numberBodiesCapacity != nbBodies && nbBodies > 0) {
|
||||
if (m_numberBodiesCapacity > 0) {
|
||||
delete[] m_splitLinearVelocities;
|
||||
delete[] m_splitAngularVelocities;
|
||||
m_splitLinearVelocities.clear();
|
||||
m_splitAngularVelocities.clear();
|
||||
}
|
||||
m_numberBodiesCapacity = nbBodies;
|
||||
// TODO : Use better memory allocation here
|
||||
m_splitLinearVelocities = new vec3[m_numberBodiesCapacity];
|
||||
m_splitAngularVelocities = new vec3[m_numberBodiesCapacity];
|
||||
m_constrainedLinearVelocities = new vec3[m_numberBodiesCapacity];
|
||||
m_constrainedAngularVelocities = new vec3[m_numberBodiesCapacity];
|
||||
m_constrainedPositions = new vec3[m_numberBodiesCapacity];
|
||||
m_constrainedOrientations = new etk::Quaternion[m_numberBodiesCapacity];
|
||||
assert(m_splitLinearVelocities != nullptr);
|
||||
assert(m_splitAngularVelocities != nullptr);
|
||||
assert(m_constrainedLinearVelocities != nullptr);
|
||||
assert(m_constrainedAngularVelocities != nullptr);
|
||||
assert(m_constrainedPositions != nullptr);
|
||||
assert(m_constrainedOrientations != nullptr);
|
||||
m_splitLinearVelocities.clear();
|
||||
m_splitAngularVelocities.clear();
|
||||
m_constrainedLinearVelocities.clear();
|
||||
m_constrainedAngularVelocities.clear();
|
||||
m_constrainedPositions.clear();
|
||||
m_constrainedOrientations.clear();
|
||||
m_splitLinearVelocities.resize(m_numberBodiesCapacity, vec3(0,0,0));
|
||||
m_splitAngularVelocities.resize(m_numberBodiesCapacity, vec3(0,0,0));
|
||||
m_constrainedLinearVelocities.resize(m_numberBodiesCapacity, vec3(0,0,0));
|
||||
m_constrainedAngularVelocities.resize(m_numberBodiesCapacity, vec3(0,0,0));
|
||||
m_constrainedPositions.resize(m_numberBodiesCapacity, vec3(0,0,0));
|
||||
m_constrainedOrientations.resize(m_numberBodiesCapacity, etk::Quaternion::identity());
|
||||
}
|
||||
// Reset the velocities arrays
|
||||
for (uint32_t i=0; i<m_numberBodiesCapacity; i++) {
|
||||
@ -262,13 +256,13 @@ void ephysics::DynamicsWorld::integrateRigidBodiesVelocities() {
|
||||
void ephysics::DynamicsWorld::solveContactsAndConstraints() {
|
||||
PROFILE("ephysics::DynamicsWorld::solveContactsAndConstraints()");
|
||||
// Set the velocities arrays
|
||||
m_contactSolver.setSplitVelocitiesArrays(m_splitLinearVelocities, m_splitAngularVelocities);
|
||||
m_contactSolver.setConstrainedVelocitiesArrays(m_constrainedLinearVelocities,
|
||||
m_constrainedAngularVelocities);
|
||||
m_constraintSolver.setConstrainedVelocitiesArrays(m_constrainedLinearVelocities,
|
||||
m_constrainedAngularVelocities);
|
||||
m_constraintSolver.setConstrainedPositionsArrays(m_constrainedPositions,
|
||||
m_constrainedOrientations);
|
||||
m_contactSolver.setSplitVelocitiesArrays(&m_splitLinearVelocities[0], &m_splitAngularVelocities[0]);
|
||||
m_contactSolver.setConstrainedVelocitiesArrays(&m_constrainedLinearVelocities[0],
|
||||
&m_constrainedAngularVelocities[0]);
|
||||
m_constraintSolver.setConstrainedVelocitiesArrays(&m_constrainedLinearVelocities[0],
|
||||
&m_constrainedAngularVelocities[0]);
|
||||
m_constraintSolver.setConstrainedPositionsArrays(&m_constrainedPositions[0],
|
||||
&m_constrainedOrientations[0]);
|
||||
// ---------- Solve velocity constraints for joints and contacts ---------- //
|
||||
// For each island of the world
|
||||
for (uint32_t islandIndex = 0; islandIndex < m_islands.size(); islandIndex++) {
|
||||
@ -329,10 +323,10 @@ ephysics::RigidBody* ephysics::DynamicsWorld::createRigidBody(const etk::Transfo
|
||||
// Compute the body ID
|
||||
ephysics::bodyindex bodyID = computeNextAvailableBodyID();
|
||||
// Largest index cannot be used (it is used for invalid index)
|
||||
assert(bodyID < std::numeric_limits<ephysics::bodyindex>::max());
|
||||
assert(bodyID < UINT64_MAX);
|
||||
// Create the rigid body
|
||||
ephysics::RigidBody* rigidBody = new RigidBody(_transform, *this, bodyID);
|
||||
assert(rigidBody != nullptr);
|
||||
ephysics::RigidBody* rigidBody = ETK_NEW(RigidBody, _transform, *this, bodyID);
|
||||
assert(rigidBody != null);
|
||||
// Add the rigid body to the physics world
|
||||
m_bodies.add(rigidBody);
|
||||
m_rigidBodies.add(rigidBody);
|
||||
@ -347,7 +341,7 @@ void ephysics::DynamicsWorld::destroyRigidBody(RigidBody* _rigidBody) {
|
||||
m_freeBodiesIDs.pushBack(_rigidBody->getID());
|
||||
// Destroy all the joints in which the rigid body to be destroyed is involved
|
||||
for (ephysics::JointListElement* element = _rigidBody->m_jointsList;
|
||||
element != nullptr;
|
||||
element != null;
|
||||
element = element->next) {
|
||||
destroyJoint(element->joint);
|
||||
}
|
||||
@ -357,33 +351,33 @@ void ephysics::DynamicsWorld::destroyRigidBody(RigidBody* _rigidBody) {
|
||||
m_bodies.erase(m_bodies.find(_rigidBody));
|
||||
m_rigidBodies.erase(m_rigidBodies.find(_rigidBody));
|
||||
// Call the destructor of the rigid body
|
||||
delete _rigidBody;
|
||||
_rigidBody = nullptr;
|
||||
ETK_DELETE(RigidBody, _rigidBody);
|
||||
_rigidBody = null;
|
||||
}
|
||||
|
||||
ephysics::Joint* ephysics::DynamicsWorld::createJoint(const ephysics::JointInfo& _jointInfo) {
|
||||
Joint* newJoint = nullptr;
|
||||
Joint* newJoint = null;
|
||||
// Allocate memory to create the new joint
|
||||
switch(_jointInfo.type) {
|
||||
// Ball-and-Socket joint
|
||||
case BALLSOCKETJOINT:
|
||||
newJoint = new BallAndSocketJoint(static_cast<const ephysics::BallAndSocketJointInfo&>(_jointInfo));
|
||||
newJoint = ETK_NEW(BallAndSocketJoint, static_cast<const ephysics::BallAndSocketJointInfo&>(_jointInfo));
|
||||
break;
|
||||
// Slider joint
|
||||
case SLIDERJOINT:
|
||||
newJoint = new SliderJoint(static_cast<const ephysics::SliderJointInfo&>(_jointInfo));
|
||||
newJoint = ETK_NEW(SliderJoint, static_cast<const ephysics::SliderJointInfo&>(_jointInfo));
|
||||
break;
|
||||
// Hinge joint
|
||||
case HINGEJOINT:
|
||||
newJoint = new HingeJoint(static_cast<const ephysics::HingeJointInfo&>(_jointInfo));
|
||||
newJoint = ETK_NEW(HingeJoint, static_cast<const ephysics::HingeJointInfo&>(_jointInfo));
|
||||
break;
|
||||
// Fixed joint
|
||||
case FIXEDJOINT:
|
||||
newJoint = new FixedJoint(static_cast<const ephysics::FixedJointInfo&>(_jointInfo));
|
||||
newJoint = ETK_NEW(FixedJoint, static_cast<const ephysics::FixedJointInfo&>(_jointInfo));
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
return nullptr;
|
||||
return null;
|
||||
}
|
||||
// If the collision between the two bodies of the constraint is disabled
|
||||
if (!_jointInfo.isCollisionEnabled) {
|
||||
@ -399,8 +393,8 @@ ephysics::Joint* ephysics::DynamicsWorld::createJoint(const ephysics::JointInfo&
|
||||
}
|
||||
|
||||
void ephysics::DynamicsWorld::destroyJoint(Joint* _joint) {
|
||||
if (_joint == nullptr) {
|
||||
EPHY_WARNING("Request destroy nullptr joint");
|
||||
if (_joint == null) {
|
||||
EPHY_WARNING("Request destroy null joint");
|
||||
return;
|
||||
}
|
||||
// If the collision between the two bodies of the constraint was disabled
|
||||
@ -418,19 +412,19 @@ void ephysics::DynamicsWorld::destroyJoint(Joint* _joint) {
|
||||
_joint->m_body2->removeJointFrom_jointsList(_joint);
|
||||
size_t nbBytes = _joint->getSizeInBytes();
|
||||
// Call the destructor of the joint
|
||||
delete _joint;
|
||||
_joint = nullptr;
|
||||
ETK_DELETE(Joint, _joint);
|
||||
_joint = null;
|
||||
}
|
||||
|
||||
void ephysics::DynamicsWorld::addJointToBody(ephysics::Joint* _joint) {
|
||||
if (_joint == nullptr) {
|
||||
EPHY_WARNING("Request add nullptr joint");
|
||||
if (_joint == null) {
|
||||
EPHY_WARNING("Request add null joint");
|
||||
return;
|
||||
}
|
||||
// Add the joint at the beginning of the linked list of joints of the first body
|
||||
_joint->m_body1->m_jointsList = new JointListElement(_joint, _joint->m_body1->m_jointsList);
|
||||
_joint->m_body1->m_jointsList = ETK_NEW(JointListElement, _joint, _joint->m_body1->m_jointsList);
|
||||
// Add the joint at the beginning of the linked list of joints of the second body
|
||||
_joint->m_body2->m_jointsList = new JointListElement(_joint, _joint->m_body2->m_jointsList);
|
||||
_joint->m_body2->m_jointsList = ETK_NEW(JointListElement, _joint, _joint->m_body2->m_jointsList);
|
||||
}
|
||||
|
||||
void ephysics::DynamicsWorld::computeIslands() {
|
||||
@ -438,8 +432,8 @@ void ephysics::DynamicsWorld::computeIslands() {
|
||||
uint32_t nbBodies = m_rigidBodies.size();
|
||||
// Clear all the islands
|
||||
for (auto &it: m_islands) {
|
||||
delete it;
|
||||
it = nullptr;
|
||||
ETK_DELETE(Island, it);
|
||||
it = null;
|
||||
}
|
||||
// Call the island destructor
|
||||
m_islands.clear();
|
||||
@ -454,7 +448,7 @@ void ephysics::DynamicsWorld::computeIslands() {
|
||||
}
|
||||
// Create a stack (using an array) for the rigid bodies to visit during the Depth First Search
|
||||
etk::Vector<ephysics::RigidBody*> stackBodiesToVisit;
|
||||
stackBodiesToVisit.resize(nbBodies, nullptr);
|
||||
stackBodiesToVisit.resize(nbBodies, null);
|
||||
// For each rigid body of the world
|
||||
for (etk::Set<ephysics::RigidBody*>::Iterator it = m_rigidBodies.begin(); it != m_rigidBodies.end(); ++it) {
|
||||
ephysics::RigidBody* body = *it;
|
||||
@ -476,7 +470,7 @@ void ephysics::DynamicsWorld::computeIslands() {
|
||||
stackIndex++;
|
||||
body->m_isAlreadyInIsland = true;
|
||||
// Create the new island
|
||||
m_islands.pushBack(new Island(nbBodies, nbContactManifolds, m_joints.size()));
|
||||
m_islands.pushBack(ETK_NEW(Island, nbBodies, nbContactManifolds, m_joints.size()));
|
||||
// While there are still some bodies to visit in the stack
|
||||
while (stackIndex > 0) {
|
||||
// Get the next body to visit from the stack
|
||||
@ -495,7 +489,7 @@ void ephysics::DynamicsWorld::computeIslands() {
|
||||
// For each contact manifold in which the current body is involded
|
||||
ephysics::ContactManifoldListElement* contactElement;
|
||||
for (contactElement = bodyToVisit->m_contactManifoldsList;
|
||||
contactElement != nullptr;
|
||||
contactElement != null;
|
||||
contactElement = contactElement->next) {
|
||||
ephysics::ContactManifold* contactManifold = contactElement->contactManifold;
|
||||
assert(contactManifold->getNbContactPoints() > 0);
|
||||
@ -522,7 +516,7 @@ void ephysics::DynamicsWorld::computeIslands() {
|
||||
// For each joint in which the current body is involved
|
||||
ephysics::JointListElement* jointElement;
|
||||
for (jointElement = bodyToVisit->m_jointsList;
|
||||
jointElement != nullptr;
|
||||
jointElement != null;
|
||||
jointElement = jointElement->next) {
|
||||
ephysics::Joint* joint = jointElement->joint;
|
||||
// Check if the current joint has already been added int32_to an island
|
||||
@ -542,13 +536,7 @@ void ephysics::DynamicsWorld::computeIslands() {
|
||||
otherBody->m_isAlreadyInIsland = true;
|
||||
}
|
||||
}
|
||||
// Reset the isAlreadyIsland variable of the static bodies so that they
|
||||
// can also be included in the other islands
|
||||
for (uint32_t i=0; i < m_islands.back()->m_numberBodies; i++) {
|
||||
if (m_islands.back()->m_bodies[i]->getType() == STATIC) {
|
||||
m_islands.back()->m_bodies[i]->m_isAlreadyInIsland = false;
|
||||
}
|
||||
}
|
||||
m_islands.back()->resetStaticBobyNotInIsland();
|
||||
}
|
||||
}
|
||||
|
||||
@ -627,7 +615,7 @@ void ephysics::DynamicsWorld::testCollision(const ephysics::CollisionBody* _body
|
||||
etk::Set<uint32_t> shapes1;
|
||||
// For each shape of the body
|
||||
for (const ProxyShape* shape = _body->getProxyShapesList();
|
||||
shape != nullptr;
|
||||
shape != null;
|
||||
shape = shape->getNext()) {
|
||||
shapes1.add(shape->m_broadPhaseID);
|
||||
}
|
||||
@ -639,12 +627,12 @@ void ephysics::DynamicsWorld::testCollision(const ephysics::CollisionBody* _body
|
||||
void ephysics::DynamicsWorld::testCollision(const ephysics::CollisionBody* _body1, const ephysics::CollisionBody* _body2, ephysics::CollisionCallback* _callback) {
|
||||
// Create the sets of shapes
|
||||
etk::Set<uint32_t> shapes1;
|
||||
for (const ProxyShape* shape=_body1->getProxyShapesList(); shape != nullptr;
|
||||
for (const ProxyShape* shape=_body1->getProxyShapesList(); shape != null;
|
||||
shape = shape->getNext()) {
|
||||
shapes1.add(shape->m_broadPhaseID);
|
||||
}
|
||||
etk::Set<uint32_t> shapes2;
|
||||
for (const ProxyShape* shape=_body2->getProxyShapesList(); shape != nullptr;
|
||||
for (const ProxyShape* shape=_body2->getProxyShapesList(); shape != null;
|
||||
shape = shape->getNext()) {
|
||||
shapes2.add(shape->m_broadPhaseID);
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -31,12 +34,12 @@ namespace ephysics {
|
||||
vec3 m_gravity; //!< Gravity vector of the world
|
||||
float m_timeStep; //!< Current frame time step (in seconds)
|
||||
bool m_isGravityEnabled; //!< True if the gravity force is on
|
||||
vec3* m_constrainedLinearVelocities; //!< Array of constrained linear velocities (state of the linear velocities after solving the constraints)
|
||||
vec3* m_constrainedAngularVelocities; //!< Array of constrained angular velocities (state of the angular velocities after solving the constraints)
|
||||
vec3* m_splitLinearVelocities; //!< Split linear velocities for the position contact solver (split impulse)
|
||||
vec3* m_splitAngularVelocities; //!< Split angular velocities for the position contact solver (split impulse)
|
||||
vec3* m_constrainedPositions; //!< Array of constrained rigid bodies position (for position error correction)
|
||||
etk::Quaternion* m_constrainedOrientations; //!< Array of constrained rigid bodies orientation (for position error correction)
|
||||
etk::Vector<vec3> m_constrainedLinearVelocities; //!< Array of constrained linear velocities (state of the linear velocities after solving the constraints)
|
||||
etk::Vector<vec3> m_constrainedAngularVelocities; //!< Array of constrained angular velocities (state of the angular velocities after solving the constraints)
|
||||
etk::Vector<vec3> m_splitLinearVelocities; //!< Split linear velocities for the position contact solver (split impulse)
|
||||
etk::Vector<vec3> m_splitAngularVelocities; //!< Split angular velocities for the position contact solver (split impulse)
|
||||
etk::Vector<vec3> m_constrainedPositions; //!< Array of constrained rigid bodies position (for position error correction)
|
||||
etk::Vector<etk::Quaternion> m_constrainedOrientations; //!< Array of constrained rigid bodies orientation (for position error correction)
|
||||
etk::Map<RigidBody*, uint32_t> m_mapBodyToConstrainedVelocityIndex; //!< Map body to their index in the constrained velocities array
|
||||
etk::Vector<Island*> m_islands; //!< Array with all the islands of awaken bodies
|
||||
uint32_t m_numberBodiesCapacity; //!< Current allocated capacity for the bodies
|
||||
@ -263,7 +266,7 @@ namespace ephysics {
|
||||
void setTimeBeforeSleep(float timeBeforeSleep);
|
||||
/**
|
||||
* @brief Set an event listener object to receive events callbacks.
|
||||
* @note If you use nullptr as an argument, the events callbacks will be disabled.
|
||||
* @note If you use null as an argument, the events callbacks will be disabled.
|
||||
* @param[in] _eventListener Pointer to the event listener object that will receive
|
||||
* event callbacks during the simulation
|
||||
*/
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
@ -1,7 +1,10 @@
|
||||
/** @file
|
||||
* @author Daniel Chappuis
|
||||
* @copyright 2010-2016 Daniel Chappuis
|
||||
* @license BSD 3 clauses (see license file)
|
||||
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
||||
* @author Daniel CHAPPUIS
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2010-2016, Daniel Chappuis
|
||||
* @copyright 2017, Edouard DUPIN
|
||||
* @license MPL v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user