Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/jolt_physics/Jolt/Physics/Collision/Shape/GetTrianglesContext.h
9917 views
1
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
2
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
3
// SPDX-License-Identifier: MIT
4
5
#pragma once
6
7
#include <Jolt/Physics/Collision/Shape/Shape.h>
8
9
JPH_NAMESPACE_BEGIN
10
11
class PhysicsMaterial;
12
13
/// Implementation of GetTrianglesStart/Next that uses a fixed list of vertices for the triangles. These are transformed into world space when getting the triangles.
14
class GetTrianglesContextVertexList
15
{
16
public:
17
/// Constructor, to be called in GetTrianglesStart
18
GetTrianglesContextVertexList(Vec3Arg inPositionCOM, QuatArg inRotation, Vec3Arg inScale, Mat44Arg inLocalTransform, const Vec3 *inTriangleVertices, size_t inNumTriangleVertices, const PhysicsMaterial *inMaterial) :
19
mLocalToWorld(Mat44::sRotationTranslation(inRotation, inPositionCOM) * Mat44::sScale(inScale) * inLocalTransform),
20
mTriangleVertices(inTriangleVertices),
21
mNumTriangleVertices(inNumTriangleVertices),
22
mMaterial(inMaterial),
23
mIsInsideOut(ScaleHelpers::IsInsideOut(inScale))
24
{
25
static_assert(sizeof(GetTrianglesContextVertexList) <= sizeof(Shape::GetTrianglesContext), "GetTrianglesContext too small");
26
JPH_ASSERT(IsAligned(this, alignof(GetTrianglesContextVertexList)));
27
JPH_ASSERT(inNumTriangleVertices % 3 == 0);
28
}
29
30
/// @see Shape::GetTrianglesNext
31
int GetTrianglesNext(int inMaxTrianglesRequested, Float3 *outTriangleVertices, const PhysicsMaterial **outMaterials)
32
{
33
JPH_ASSERT(inMaxTrianglesRequested >= Shape::cGetTrianglesMinTrianglesRequested);
34
35
int total_num_vertices = min(inMaxTrianglesRequested * 3, int(mNumTriangleVertices - mCurrentVertex));
36
37
if (mIsInsideOut)
38
{
39
// Store triangles flipped
40
for (const Vec3 *v = mTriangleVertices + mCurrentVertex, *v_end = v + total_num_vertices; v < v_end; v += 3)
41
{
42
(mLocalToWorld * v[0]).StoreFloat3(outTriangleVertices++);
43
(mLocalToWorld * v[2]).StoreFloat3(outTriangleVertices++);
44
(mLocalToWorld * v[1]).StoreFloat3(outTriangleVertices++);
45
}
46
}
47
else
48
{
49
// Store triangles
50
for (const Vec3 *v = mTriangleVertices + mCurrentVertex, *v_end = v + total_num_vertices; v < v_end; v += 3)
51
{
52
(mLocalToWorld * v[0]).StoreFloat3(outTriangleVertices++);
53
(mLocalToWorld * v[1]).StoreFloat3(outTriangleVertices++);
54
(mLocalToWorld * v[2]).StoreFloat3(outTriangleVertices++);
55
}
56
}
57
58
// Update the current vertex to point to the next vertex to get
59
mCurrentVertex += total_num_vertices;
60
int total_num_triangles = total_num_vertices / 3;
61
62
// Store materials
63
if (outMaterials != nullptr)
64
for (const PhysicsMaterial **m = outMaterials, **m_end = outMaterials + total_num_triangles; m < m_end; ++m)
65
*m = mMaterial;
66
67
return total_num_triangles;
68
}
69
70
/// Helper function that creates a vertex list of a half unit sphere (top part)
71
template <class A>
72
static void sCreateHalfUnitSphereTop(A &ioVertices, int inDetailLevel)
73
{
74
sCreateUnitSphereHelper(ioVertices, Vec3::sAxisX(), Vec3::sAxisY(), Vec3::sAxisZ(), inDetailLevel);
75
sCreateUnitSphereHelper(ioVertices, Vec3::sAxisY(), -Vec3::sAxisX(), Vec3::sAxisZ(), inDetailLevel);
76
sCreateUnitSphereHelper(ioVertices, Vec3::sAxisY(), Vec3::sAxisX(), -Vec3::sAxisZ(), inDetailLevel);
77
sCreateUnitSphereHelper(ioVertices, -Vec3::sAxisX(), Vec3::sAxisY(), -Vec3::sAxisZ(), inDetailLevel);
78
}
79
80
/// Helper function that creates a vertex list of a half unit sphere (bottom part)
81
template <class A>
82
static void sCreateHalfUnitSphereBottom(A &ioVertices, int inDetailLevel)
83
{
84
sCreateUnitSphereHelper(ioVertices, -Vec3::sAxisX(), -Vec3::sAxisY(), Vec3::sAxisZ(), inDetailLevel);
85
sCreateUnitSphereHelper(ioVertices, -Vec3::sAxisY(), Vec3::sAxisX(), Vec3::sAxisZ(), inDetailLevel);
86
sCreateUnitSphereHelper(ioVertices, Vec3::sAxisX(), -Vec3::sAxisY(), -Vec3::sAxisZ(), inDetailLevel);
87
sCreateUnitSphereHelper(ioVertices, -Vec3::sAxisY(), -Vec3::sAxisX(), -Vec3::sAxisZ(), inDetailLevel);
88
}
89
90
/// Helper function that creates an open cylinder of half height 1 and radius 1
91
template <class A>
92
static void sCreateUnitOpenCylinder(A &ioVertices, int inDetailLevel)
93
{
94
const Vec3 bottom_offset(0.0f, -2.0f, 0.0f);
95
int num_verts = 4 * (1 << inDetailLevel);
96
for (int i = 0; i < num_verts; ++i)
97
{
98
float angle1 = 2.0f * JPH_PI * (float(i) / num_verts);
99
float angle2 = 2.0f * JPH_PI * (float(i + 1) / num_verts);
100
101
Vec3 t1(Sin(angle1), 1.0f, Cos(angle1));
102
Vec3 t2(Sin(angle2), 1.0f, Cos(angle2));
103
Vec3 b1 = t1 + bottom_offset;
104
Vec3 b2 = t2 + bottom_offset;
105
106
ioVertices.push_back(t1);
107
ioVertices.push_back(b1);
108
ioVertices.push_back(t2);
109
110
ioVertices.push_back(t2);
111
ioVertices.push_back(b1);
112
ioVertices.push_back(b2);
113
}
114
}
115
116
private:
117
/// Recursive helper function for creating a sphere
118
template <class A>
119
static void sCreateUnitSphereHelper(A &ioVertices, Vec3Arg inV1, Vec3Arg inV2, Vec3Arg inV3, int inLevel)
120
{
121
Vec3 center1 = (inV1 + inV2).Normalized();
122
Vec3 center2 = (inV2 + inV3).Normalized();
123
Vec3 center3 = (inV3 + inV1).Normalized();
124
125
if (inLevel > 0)
126
{
127
int new_level = inLevel - 1;
128
sCreateUnitSphereHelper(ioVertices, inV1, center1, center3, new_level);
129
sCreateUnitSphereHelper(ioVertices, center1, center2, center3, new_level);
130
sCreateUnitSphereHelper(ioVertices, center1, inV2, center2, new_level);
131
sCreateUnitSphereHelper(ioVertices, center3, center2, inV3, new_level);
132
}
133
else
134
{
135
ioVertices.push_back(inV1);
136
ioVertices.push_back(inV2);
137
ioVertices.push_back(inV3);
138
}
139
}
140
141
Mat44 mLocalToWorld;
142
const Vec3 * mTriangleVertices;
143
size_t mNumTriangleVertices;
144
size_t mCurrentVertex = 0;
145
const PhysicsMaterial * mMaterial;
146
bool mIsInsideOut;
147
};
148
149
/// Implementation of GetTrianglesStart/Next that uses a multiple fixed lists of vertices for the triangles. These are transformed into world space when getting the triangles.
150
class GetTrianglesContextMultiVertexList
151
{
152
public:
153
/// Constructor, to be called in GetTrianglesStart
154
GetTrianglesContextMultiVertexList(bool inIsInsideOut, const PhysicsMaterial *inMaterial) :
155
mMaterial(inMaterial),
156
mIsInsideOut(inIsInsideOut)
157
{
158
static_assert(sizeof(GetTrianglesContextMultiVertexList) <= sizeof(Shape::GetTrianglesContext), "GetTrianglesContext too small");
159
JPH_ASSERT(IsAligned(this, alignof(GetTrianglesContextMultiVertexList)));
160
}
161
162
/// Add a mesh part and its transform
163
void AddPart(Mat44Arg inLocalToWorld, const Vec3 *inTriangleVertices, size_t inNumTriangleVertices)
164
{
165
JPH_ASSERT(inNumTriangleVertices % 3 == 0);
166
167
mParts.push_back({ inLocalToWorld, inTriangleVertices, inNumTriangleVertices });
168
}
169
170
/// @see Shape::GetTrianglesNext
171
int GetTrianglesNext(int inMaxTrianglesRequested, Float3 *outTriangleVertices, const PhysicsMaterial **outMaterials)
172
{
173
JPH_ASSERT(inMaxTrianglesRequested >= Shape::cGetTrianglesMinTrianglesRequested);
174
175
int total_num_vertices = 0;
176
int max_vertices_requested = inMaxTrianglesRequested * 3;
177
178
// Loop over parts
179
for (; mCurrentPart < mParts.size(); ++mCurrentPart)
180
{
181
const Part &part = mParts[mCurrentPart];
182
183
// Calculate how many vertices to take from this part
184
int part_num_vertices = min(max_vertices_requested, int(part.mNumTriangleVertices - mCurrentVertex));
185
if (part_num_vertices == 0)
186
break;
187
188
max_vertices_requested -= part_num_vertices;
189
total_num_vertices += part_num_vertices;
190
191
if (mIsInsideOut)
192
{
193
// Store triangles flipped
194
for (const Vec3 *v = part.mTriangleVertices + mCurrentVertex, *v_end = v + part_num_vertices; v < v_end; v += 3)
195
{
196
(part.mLocalToWorld * v[0]).StoreFloat3(outTriangleVertices++);
197
(part.mLocalToWorld * v[2]).StoreFloat3(outTriangleVertices++);
198
(part.mLocalToWorld * v[1]).StoreFloat3(outTriangleVertices++);
199
}
200
}
201
else
202
{
203
// Store triangles
204
for (const Vec3 *v = part.mTriangleVertices + mCurrentVertex, *v_end = v + part_num_vertices; v < v_end; v += 3)
205
{
206
(part.mLocalToWorld * v[0]).StoreFloat3(outTriangleVertices++);
207
(part.mLocalToWorld * v[1]).StoreFloat3(outTriangleVertices++);
208
(part.mLocalToWorld * v[2]).StoreFloat3(outTriangleVertices++);
209
}
210
}
211
212
// Update the current vertex to point to the next vertex to get
213
mCurrentVertex += part_num_vertices;
214
215
// Check if we completed this part
216
if (mCurrentVertex < part.mNumTriangleVertices)
217
break;
218
219
// Reset current vertex for the next part
220
mCurrentVertex = 0;
221
}
222
223
int total_num_triangles = total_num_vertices / 3;
224
225
// Store materials
226
if (outMaterials != nullptr)
227
for (const PhysicsMaterial **m = outMaterials, **m_end = outMaterials + total_num_triangles; m < m_end; ++m)
228
*m = mMaterial;
229
230
return total_num_triangles;
231
}
232
233
private:
234
struct Part
235
{
236
Mat44 mLocalToWorld;
237
const Vec3 * mTriangleVertices;
238
size_t mNumTriangleVertices;
239
};
240
241
StaticArray<Part, 3> mParts;
242
uint mCurrentPart = 0;
243
size_t mCurrentVertex = 0;
244
const PhysicsMaterial * mMaterial;
245
bool mIsInsideOut;
246
};
247
248
JPH_NAMESPACE_END
249
250