1 /********************************************************************************
2 * ReactPhysics3D physics library, http://www.reactphysics3d.com                 *
3 * Copyright (c) 2010-2020 Daniel Chappuis                                       *
4 *********************************************************************************
5 *                                                                               *
6 * This software is provided 'as-is', without any express or implied warranty.   *
7 * In no event will the authors be held liable for any damages arising from the  *
8 * use of this software.                                                         *
9 *                                                                               *
10 * Permission is granted to anyone to use this software for any purpose,         *
11 * including commercial applications, and to alter it and redistribute it        *
12 * freely, subject to the following restrictions:                                *
13 *                                                                               *
14 * 1. The origin of this software must not be misrepresented; you must not claim *
15 *    that you wrote the original software. If you use this software in a        *
16 *    product, an acknowledgment in the product documentation would be           *
17 *    appreciated but is not required.                                           *
18 *                                                                               *
19 * 2. Altered source versions must be plainly marked as such, and must not be    *
20 *    misrepresented as being the original software.                             *
21 *                                                                               *
22 * 3. This notice may not be removed or altered from any source distribution.    *
23 *                                                                               *
24 ********************************************************************************/
25 
26 #ifndef REACTPHYSICS3D_TRIANGLE_SHAPE_H
27 #define REACTPHYSICS3D_TRIANGLE_SHAPE_H
28 
29 // Libraries
30 #include <reactphysics3d/mathematics/mathematics.h>
31 #include <reactphysics3d/collision/shapes/ConvexPolyhedronShape.h>
32 
33 /// ReactPhysics3D namespace
34 namespace reactphysics3d {
35 
36 /// Raycast test side for the triangle
37 enum class TriangleRaycastSide {
38 
39     /// Raycast against front triangle
40     FRONT,
41 
42     /// Raycast against back triangle
43     BACK,
44 
45     /// Raycast against front and back triangle
46     FRONT_AND_BACK
47 };
48 
49 // Class TriangleShape
50 /**
51  * This class represents a triangle collision shape that is centered
52  * at the origin and defined three points. A user cannot instanciate
53  * an object of this class. This class is for internal use only. Instances
54  * of this class are created when the user creates an HeightFieldShape and
55  * a ConcaveMeshShape
56  */
57 class TriangleShape : public ConvexPolyhedronShape {
58 
59     protected:
60 
61         // -------------------- Attribute -------------------- //
62 
63 
64         /// Three points of the triangle
65         Vector3 mPoints[3];
66 
67         /// Normal of the triangle
68         Vector3 mNormal;
69 
70         /// Three vertices normals for smooth collision with triangle mesh
71         Vector3 mVerticesNormals[3];
72 
73         /// Raycast test type for the triangle (front, back, front-back)
74         TriangleRaycastSide mRaycastTestType;
75 
76         /// Faces information for the two faces of the triangle
77         HalfEdgeStructure::Face mFaces[2];
78 
79         /// Edges information for the six edges of the triangle
80         HalfEdgeStructure::Edge mEdges[6];
81 
82         // -------------------- Methods -------------------- //
83 
84         /// Return a local support point in a given direction without the object margin
85         virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction) const override;
86 
87         /// Get a smooth contact normal for collision for a triangle of the mesh
88         Vector3 computeSmoothLocalContactNormalForTriangle(const Vector3& localContactPoint) const;
89 
90         /// Return true if a point is inside the collider
91         virtual bool testPointInside(const Vector3& localPoint, Collider* collider) const override;
92 
93         /// Raycast method with feedback information
94         virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, Collider* collider,
95                              MemoryAllocator& allocator) const override;
96 
97         /// Return the number of bytes used by the collision shape
98         virtual size_t getSizeInBytes() const override;
99 
100         /// Generate the id of the shape (used for temporal coherence)
101         void generateId();
102 
103         // -------------------- Methods -------------------- //
104 
105         /// This method implements the technique described in Game Physics Pearl book
106         void computeSmoothMeshContact(Vector3 localContactPointTriangle, const Transform& triangleShapeToWorldTransform,
107                                       const Transform& worldToOtherShapeTransform, decimal penetrationDepth, bool isTriangleShape1,
108                                       Vector3& outNewLocalContactPointOtherShape, Vector3& outSmoothWorldContactTriangleNormal) const;
109 
110         /// Constructor
111         TriangleShape(const Vector3* vertices, const Vector3* verticesNormals,
112                       uint shapeId, MemoryAllocator& allocator);
113 
114         /// Destructor
115         virtual ~TriangleShape() override = default;
116 
117     public:
118 
119         // -------------------- Methods -------------------- //
120 
121         /// Deleted copy-constructor
122         TriangleShape(const TriangleShape& shape) = delete;
123 
124         /// Deleted assignment operator
125         TriangleShape& operator=(const TriangleShape& shape) = delete;
126 
127         /// Return the local bounds of the shape in x, y and z directions.
128         virtual void getLocalBounds(Vector3& min, Vector3& max) const override;
129 
130         /// Return the local inertia tensor of the collision shape
131         virtual Vector3 getLocalInertiaTensor(decimal mass) const override;
132 
133         /// Update the AABB of a body using its collision shape
134         virtual void computeAABB(AABB& aabb, const Transform& transform) const override;
135 
136         /// Return the raycast test type (front, back, front-back)
137         TriangleRaycastSide getRaycastTestType() const;
138 
139         // Set the raycast test type (front, back, front-back)
140         void setRaycastTestType(TriangleRaycastSide testType);
141 
142         /// Return the number of faces of the polyhedron
143         virtual uint getNbFaces() const override;
144 
145         /// Return a given face of the polyhedron
146         virtual const HalfEdgeStructure::Face& getFace(uint faceIndex) const override;
147 
148         /// Return the number of vertices of the polyhedron
149         virtual uint getNbVertices() const override;
150 
151         /// Return a given vertex of the polyhedron
152         virtual HalfEdgeStructure::Vertex getVertex(uint vertexIndex) const override;
153 
154         /// Return the position of a given vertex
155         virtual Vector3 getVertexPosition(uint vertexIndex) const override;
156 
157         /// Return the normal vector of a given face of the polyhedron
158         virtual Vector3 getFaceNormal(uint faceIndex) const override;
159 
160         /// Return the number of half-edges of the polyhedron
161         virtual uint getNbHalfEdges() const override;
162 
163         /// Return a given half-edge of the polyhedron
164         virtual const HalfEdgeStructure::Edge& getHalfEdge(uint edgeIndex) const override;
165 
166         /// Return the centroid of the polyhedron
167         virtual Vector3 getCentroid() const override;
168 
169         /// Compute and return the volume of the collision shape
170         virtual decimal getVolume() const override;
171 
172         /// This method compute the smooth mesh contact with a triangle in case one of the two collision shapes is a triangle. The idea in this case is to use a smooth vertex normal of the triangle mesh
173         static void computeSmoothTriangleMeshContact(const CollisionShape* shape1, const CollisionShape* shape2,
174                                                      Vector3& localContactPointShape1, Vector3& localContactPointShape2,
175                                                      const Transform& shape1ToWorld, const Transform& shape2ToWorld,
176                                                      decimal penetrationDepth, Vector3& outSmoothVertexNormal);
177 
178         /// Return the string representation of the shape
179         virtual std::string to_string() const override;
180 
181         // ---------- Friendship ---------- //
182 
183         friend class ConcaveMeshRaycastCallback;
184         friend class TriangleOverlapCallback;
185         friend class MiddlePhaseTriangleCallback;
186         friend class HeightFieldShape;
187         friend class CollisionDetectionSystem;
188 };
189 
190 // Return the number of bytes used by the collision shape
getSizeInBytes()191 inline size_t TriangleShape::getSizeInBytes() const {
192     return sizeof(TriangleShape);
193 }
194 
195 // Return a local support point in a given direction without the object margin
getLocalSupportPointWithoutMargin(const Vector3 & direction)196 inline Vector3 TriangleShape::getLocalSupportPointWithoutMargin(const Vector3& direction) const {
197     Vector3 dotProducts(direction.dot(mPoints[0]), direction.dot(mPoints[1]), direction.dot(mPoints[2]));
198     return mPoints[dotProducts.getMaxAxis()];
199 }
200 
201 // Return the local bounds of the shape in x, y and z directions.
202 // This method is used to compute the AABB of the box
203 /**
204  * @param min The minimum bounds of the shape in local-space coordinates
205  * @param max The maximum bounds of the shape in local-space coordinates
206  */
getLocalBounds(Vector3 & min,Vector3 & max)207 inline void TriangleShape::getLocalBounds(Vector3& min, Vector3& max) const {
208 
209     const Vector3 xAxis(mPoints[0].x, mPoints[1].x, mPoints[2].x);
210     const Vector3 yAxis(mPoints[0].y, mPoints[1].y, mPoints[2].y);
211     const Vector3 zAxis(mPoints[0].z, mPoints[1].z, mPoints[2].z);
212     min.setAllValues(xAxis.getMinValue(), yAxis.getMinValue(), zAxis.getMinValue());
213     max.setAllValues(xAxis.getMaxValue(), yAxis.getMaxValue(), zAxis.getMaxValue());
214 
215     min -= Vector3(mMargin, mMargin, mMargin);
216     max += Vector3(mMargin, mMargin, mMargin);
217 }
218 
219 // Return the local inertia tensor of the triangle shape
220 /**
221  * @param[out] tensor The 3x3 inertia tensor matrix of the shape in local-space
222  *                    coordinates
223  * @param mass Mass to use to compute the inertia tensor of the collision shape
224  */
getLocalInertiaTensor(decimal mass)225 inline Vector3 TriangleShape::getLocalInertiaTensor(decimal mass) const {
226     return Vector3(0, 0, 0);
227 }
228 
229 // Return true if a point is inside the collision shape
testPointInside(const Vector3 & localPoint,Collider * collider)230 inline bool TriangleShape::testPointInside(const Vector3& localPoint, Collider* collider) const {
231     return false;
232 }
233 
234 // Return the number of faces of the polyhedron
getNbFaces()235 inline uint TriangleShape::getNbFaces() const {
236     return 2;
237 }
238 
239 // Return a given face of the polyhedron
getFace(uint faceIndex)240 inline const HalfEdgeStructure::Face& TriangleShape::getFace(uint faceIndex) const {
241     assert(faceIndex < 2);
242     return mFaces[faceIndex];
243 }
244 
245 // Return the number of vertices of the polyhedron
getNbVertices()246 inline uint TriangleShape::getNbVertices() const {
247     return 3;
248 }
249 
250 // Return a given vertex of the polyhedron
getVertex(uint vertexIndex)251 inline HalfEdgeStructure::Vertex TriangleShape::getVertex(uint vertexIndex) const {
252     assert(vertexIndex < 3);
253 
254     HalfEdgeStructure::Vertex vertex(vertexIndex);
255     switch (vertexIndex) {
256         case 0: vertex.edgeIndex = 0; break;
257         case 1: vertex.edgeIndex = 2; break;
258         case 2: vertex.edgeIndex = 4; break;
259     }
260     return vertex;
261 }
262 
263 // Return a given half-edge of the polyhedron
getHalfEdge(uint edgeIndex)264 inline const HalfEdgeStructure::Edge& TriangleShape::getHalfEdge(uint edgeIndex) const {
265     assert(edgeIndex < getNbHalfEdges());
266     return mEdges[edgeIndex];
267 }
268 
269 // Return the position of a given vertex
getVertexPosition(uint vertexIndex)270 inline Vector3 TriangleShape::getVertexPosition(uint vertexIndex) const {
271     assert(vertexIndex < 3);
272     return mPoints[vertexIndex];
273 }
274 
275 // Return the normal vector of a given face of the polyhedron
getFaceNormal(uint faceIndex)276 inline Vector3 TriangleShape::getFaceNormal(uint faceIndex) const {
277     assert(faceIndex < 2);
278     return faceIndex == 0 ? mNormal : -mNormal;
279 }
280 
281 // Return the centroid of the box
getCentroid()282 inline Vector3 TriangleShape::getCentroid() const {
283     return (mPoints[0] + mPoints[1] + mPoints[2]) / decimal(3.0);
284 }
285 
286 // Return the number of half-edges of the polyhedron
getNbHalfEdges()287 inline uint TriangleShape::getNbHalfEdges() const {
288     return 6;
289 }
290 
291 // Return the raycast test type (front, back, front-back)
getRaycastTestType()292 inline TriangleRaycastSide TriangleShape::getRaycastTestType() const {
293     return mRaycastTestType;
294 }
295 
296 // Set the raycast test type (front, back, front-back)
297 /**
298  * @param testType Raycast test type for the triangle (front, back, front-back)
299  */
setRaycastTestType(TriangleRaycastSide testType)300 inline void TriangleShape::setRaycastTestType(TriangleRaycastSide testType) {
301     mRaycastTestType = testType;
302 }
303 
304 // Return the string representation of the shape
to_string()305 inline std::string TriangleShape::to_string() const {
306     return "TriangleShape{v1=" + mPoints[0].to_string() + ", v2=" + mPoints[1].to_string() + "," +
307             "v3=" + mPoints[2].to_string() + "}";
308 }
309 
310 // Compute and return the volume of the collision shape
getVolume()311 inline decimal TriangleShape::getVolume() const {
312     return decimal(0.0);
313 }
314 
315 }
316 
317 #endif
318 
319