Compare commits

...

21 Commits

Author SHA1 Message Date
7851f45134 [DEV] integrate GLD 2021-12-15 22:35:42 +01:00
bc8f81bb4c [DEV] uptate new lutin declaration model 2021-10-25 07:52:11 +02:00
3a73c9aa4b [DEV] Stupid commit 2021-08-23 11:10:00 +02:00
08acb860c1 [DEBUG] update new API of lutin log 2019-05-03 10:18:23 +02:00
beba85290c [DEBUG] correct segmentation fault 2019-04-01 22:07:43 +02:00
640d3fdcbe [DEV] update new etk Uri API 2018-10-23 22:19:32 +02:00
42f5d84744 [DEV] update etk null 2018-06-19 22:13:48 +02:00
59280cc06c [DEV] try find collision error 2018-06-19 21:24:54 +02:00
4525e80a60 [DEV] continue rework 2018-06-19 21:24:54 +02:00
696a979395 [DEV] continue rework 2018-06-19 21:24:54 +02:00
b1fe6eebb4 [DEV] refacto 2018-06-19 21:24:54 +02:00
b85098fcaa [STYLE] correct some coding style 2018-06-19 21:24:54 +02:00
33f24d6b17 [DEV] basic update 2018-06-19 21:24:54 +02:00
14644e4f5f [DEV] update to the system allocator ETK_NEW 2018-06-19 21:24:54 +02:00
96d6ff59d1 [DEV] remove an assert ==> create some eratic comportment, and coorect build after licence change 2018-06-19 21:24:54 +02:00
078fc33309 [LICENCE] change ZLib to MPL-2 with athoriqzation of author:
Email exchange:

On 29.09.2017 14:35 Edouard DUPIN wrote:
Hello,

I have fork your physic engine and update it to fit better with my 3d
game engine and my framework.

I do many change:
  - on assert policy (I do not like it)
  - the back-end use of the vector3D and quaternion, that I have
already an other implementation...
  - Log management
  - Other build system (lutin)
  - organisation of doxygen (all in the header)
  - remove dependency of the STL (in progress)
  - some bugs ...
  - ...

And I have a problem with the licence. You use BSD-3 that is a good
point, but this licence does not force the user to send your their
modification. Then I ask you to permit me to change the licence of the
FORK in MPL-2 that have the benefit to force developer to publish the
modification and permit to use the software in a proprietary
application without contamination.

Best regards

Edouard DUPIN

https://github.com/HeeroYui
https://github.com/atria-soft
https://github.com/musicdsp

answers from chappuis.daniel@XXXXXXX.yyy
Hello,

I am glad that you have found the ReactPhysics3D library to be useful.
You said that you have found bugs. Maybe I have already found and fixed some of them but do not hesitate to report them
here (https://github.com/DanielChappuis/reactphysics3d/issues) if not done yet.

Concerning the license. The library is not under the BSD-3 license but under the zlib license (https://opensource.org/licenses/Zlib).
With this license, it is allowed to use the software in a proprietary application without contamination. Regarding your request to
change the license to the MPL-2, you can do it with the following condition : You need to add the following text in all the source files
of ReactPhysics3D where the license will change. It must always be clear where the original code is coming from.

--------------- TEXT TO ADD TO THE LICENSE IN EACH FILE -------------------------
Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/>
This code is re-licensed with permission from ReactPhysics3D author.
---------------------------------------------------------------------------------

For example, you can see here how the flow/react library (java port of ReactPhysics3D) has been re-licensed from
ReactPhysics3D (https://github.com/flow/react/blob/develop/src/main/java/com/flowpowered/react/constraint/ContactPoint.java)

I hope it fits your needs.

Best Regards,

Daniel Chappuis
2018-06-19 21:24:54 +02:00
7689205279 [DEV] remove some unneeded log 2018-06-19 21:24:54 +02:00
619246407c [DEBUG] correct the collision Detection 2018-06-19 21:24:54 +02:00
8d77c326de [DEV] clean some unuse of container 2018-06-19 21:24:54 +02:00
cccb93fd34 [DEV] regactor the EPA triangle store 2018-06-19 21:24:54 +02:00
a353893266 [DEV] update the 2 callback herited in function lanmba availlable 2018-06-18 21:26:38 +02:00
122 changed files with 3571 additions and 3765 deletions

5
.gitignore vendored
View File

@ -1,3 +1,8 @@
__pycache__
.bck
out
target
build
# Compiled source #
###################
*.com

29
GLD_ephysics-test.json Normal file
View 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
View 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
View File

@ -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.

View File

@ -1,18 +1,19 @@
[![Travis Build Status](https://travis-ci.org/DanielChappuis/ephysics.svg?branch=master)](https://travis-ci.org/DanielChappuis/ephysics)
[![Travis Build Status](https://travis-ci.org/atria-soft/ephysics.svg?branch=master)](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).

View File

@ -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) {
}

View File

@ -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;
};
}

View File

@ -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);

View File

@ -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.

View File

@ -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);
}

View File

@ -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

View File

@ -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() {

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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];
}

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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>

View File

@ -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) {
}

View File

@ -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() {

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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;
}
}

View File

@ -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

View File

@ -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);
}

View File

@ -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.

View File

@ -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) {

View File

@ -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;
}
};

View File

@ -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>

View File

@ -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

View File

@ -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() {
}

View File

@ -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) {

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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) {
}

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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;
}

View File

@ -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>

View File

@ -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]);
}

View File

@ -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;
};
}

View File

@ -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);
}

View File

@ -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;
};
}

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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);
}

View File

@ -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;
};
}

View File

@ -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;
}

View File

@ -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);
};

View File

@ -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);
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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

View File

@ -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):

View File

@ -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

View File

@ -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);
}

View File

@ -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;
};
}

View File

@ -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);
}

View File

@ -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,

View File

@ -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;
}

View File

@ -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

View File

@ -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];
}

View File

@ -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;
};

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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);
}

View File

@ -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
}
};

View File

@ -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>

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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() {

View File

@ -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) {

View File

@ -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;

View File

@ -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

View File

@ -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);
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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();
};

View File

@ -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);
}

View File

@ -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
*/

View File

@ -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

View File

@ -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