basilisk-engine 0.1.43__py3-none-any.whl → 0.1.45__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of basilisk-engine might be problematic. Click here for more details.
- basilisk/__init__.py +26 -26
- basilisk/audio/sound.py +27 -27
- basilisk/bsk_assets/cube.obj +48 -48
- basilisk/collisions/broad/broad_aabb.py +102 -102
- basilisk/collisions/broad/broad_bvh.py +137 -137
- basilisk/collisions/collider.py +95 -95
- basilisk/collisions/collider_handler.py +225 -225
- basilisk/collisions/narrow/contact_manifold.py +95 -95
- basilisk/collisions/narrow/dataclasses.py +34 -34
- basilisk/collisions/narrow/deprecated.py +46 -46
- basilisk/collisions/narrow/epa.py +91 -91
- basilisk/collisions/narrow/gjk.py +66 -66
- basilisk/collisions/narrow/graham_scan.py +24 -24
- basilisk/collisions/narrow/helper.py +29 -29
- basilisk/collisions/narrow/line_intersections.py +106 -106
- basilisk/collisions/narrow/sutherland_hodgman.py +75 -75
- basilisk/config.py +53 -53
- basilisk/draw/draw.py +100 -100
- basilisk/draw/draw_handler.py +181 -178
- basilisk/draw/font_renderer.py +28 -28
- basilisk/engine.py +168 -169
- basilisk/generic/abstract_bvh.py +15 -15
- basilisk/generic/abstract_custom.py +133 -133
- basilisk/generic/collisions.py +70 -70
- basilisk/generic/input_validation.py +82 -82
- basilisk/generic/math.py +17 -17
- basilisk/generic/matrices.py +35 -35
- basilisk/generic/meshes.py +72 -72
- basilisk/generic/quat.py +142 -142
- basilisk/generic/quat_methods.py +7 -7
- basilisk/generic/raycast_result.py +26 -26
- basilisk/generic/vec3.py +143 -143
- basilisk/input/__init__.py +0 -0
- basilisk/input/mouse.py +62 -0
- basilisk/input/path.py +14 -0
- basilisk/input_output/IO_handler.py +91 -91
- basilisk/input_output/clock.py +49 -49
- basilisk/input_output/keys.py +43 -43
- basilisk/input_output/mouse.py +90 -90
- basilisk/input_output/path.py +14 -14
- basilisk/mesh/cube.py +33 -33
- basilisk/mesh/mesh.py +233 -233
- basilisk/mesh/mesh_from_data.py +150 -150
- basilisk/mesh/model.py +271 -271
- basilisk/mesh/narrow_aabb.py +89 -89
- basilisk/mesh/narrow_bvh.py +91 -91
- basilisk/mesh/narrow_primative.py +23 -23
- basilisk/nodes/helper.py +28 -28
- basilisk/nodes/node.py +709 -709
- basilisk/nodes/node_handler.py +97 -97
- basilisk/particles/particle_handler.py +64 -64
- basilisk/particles/particle_renderer.py +93 -93
- basilisk/physics/impulse.py +112 -112
- basilisk/physics/physics_body.py +43 -43
- basilisk/physics/physics_engine.py +35 -35
- basilisk/render/batch.py +103 -103
- basilisk/render/bloom.py +117 -117
- basilisk/render/camera.py +260 -260
- basilisk/render/chunk.py +113 -113
- basilisk/render/chunk_handler.py +167 -167
- basilisk/render/frame.py +130 -130
- basilisk/render/framebuffer.py +192 -192
- basilisk/render/image.py +120 -120
- basilisk/render/image_handler.py +120 -120
- basilisk/render/light.py +96 -96
- basilisk/render/light_handler.py +58 -58
- basilisk/render/material.py +232 -232
- basilisk/render/material_handler.py +133 -133
- basilisk/render/post_process.py +180 -180
- basilisk/render/shader.py +135 -135
- basilisk/render/shader_handler.py +109 -109
- basilisk/render/sky.py +119 -119
- basilisk/scene.py +287 -287
- basilisk/shaders/batch.frag +291 -293
- basilisk/shaders/batch.vert +117 -117
- basilisk/shaders/bloom_downsample.frag +23 -23
- basilisk/shaders/bloom_frame.frag +25 -0
- basilisk/shaders/bloom_upsample.frag +33 -33
- basilisk/shaders/crt.frag +34 -34
- basilisk/shaders/draw.frag +27 -27
- basilisk/shaders/draw.vert +25 -25
- basilisk/shaders/filter.frag +22 -22
- basilisk/shaders/frame.frag +13 -13
- basilisk/shaders/frame.vert +13 -13
- basilisk/shaders/frame_hdr.frag +27 -27
- basilisk/shaders/geometry.frag +10 -10
- basilisk/shaders/geometry.vert +41 -41
- basilisk/shaders/normal.frag +62 -62
- basilisk/shaders/normal.vert +96 -96
- basilisk/shaders/particle.frag +81 -81
- basilisk/shaders/particle.vert +86 -86
- basilisk/shaders/sky.frag +23 -23
- basilisk/shaders/sky.vert +13 -13
- {basilisk_engine-0.1.43.dist-info → basilisk_engine-0.1.45.dist-info}/METADATA +89 -89
- basilisk_engine-0.1.45.dist-info/RECORD +115 -0
- {basilisk_engine-0.1.43.dist-info → basilisk_engine-0.1.45.dist-info}/WHEEL +1 -1
- basilisk_engine-0.1.43.dist-info/RECORD +0 -111
- {basilisk_engine-0.1.43.dist-info → basilisk_engine-0.1.45.dist-info}/top_level.txt +0 -0
basilisk/mesh/model.py
CHANGED
|
@@ -1,272 +1,272 @@
|
|
|
1
|
-
import numpy as np
|
|
2
|
-
import glm
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class Model:
|
|
6
|
-
"""
|
|
7
|
-
Instance of a loaded model. Contains all objects, groups, and vertex data
|
|
8
|
-
model.vertex_data contains all vertex data
|
|
9
|
-
Objects stored in the model.objects dictionary, where keys are the object names (marked by 'o') in the .obj
|
|
10
|
-
Default object key is '0'
|
|
11
|
-
"""
|
|
12
|
-
|
|
13
|
-
def __init__(self) -> None:
|
|
14
|
-
self.objects = {0 : VertexObject()}
|
|
15
|
-
|
|
16
|
-
self.vertex_data = []
|
|
17
|
-
"""All vertex data in the obj. Use this for buffer data"""
|
|
18
|
-
self.tangent_data = []
|
|
19
|
-
"""Tangents and bitangents"""
|
|
20
|
-
self.format = None
|
|
21
|
-
self.attribs = None
|
|
22
|
-
|
|
23
|
-
self.vertex_points = []
|
|
24
|
-
"""The unique points given by the file"""
|
|
25
|
-
self.vertex_uv = []
|
|
26
|
-
"""The unique texture coordinates given by the file"""
|
|
27
|
-
self.vertex_normals = []
|
|
28
|
-
"""The unique normals given by the file"""
|
|
29
|
-
|
|
30
|
-
self.point_indices = []
|
|
31
|
-
"""Indices of to vertex_points to construct triangles. Grouped in three."""
|
|
32
|
-
self.uv_indices = []
|
|
33
|
-
"""Indices of to vertex_uv to construct triangles. Grouped in three."""
|
|
34
|
-
self.normal_indices = []
|
|
35
|
-
"""Indices of to vertex_normals to construct triangles. Grouped in three."""
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def __repr__(self) -> str:
|
|
39
|
-
return_string = '<Model | objects: {'
|
|
40
|
-
for vertex_object in self.objects.keys():
|
|
41
|
-
return_string += str(vertex_object) + ', '
|
|
42
|
-
return_string = return_string[:-2] + '}>'
|
|
43
|
-
return return_string
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
class VertexObject:
|
|
47
|
-
"""
|
|
48
|
-
Object conataining groups of vertices.
|
|
49
|
-
Groups stored in the vertex_object.groups dictionary, where keys are the group names (marked by 'g') in the .obj
|
|
50
|
-
Default group key is '0'
|
|
51
|
-
"""
|
|
52
|
-
|
|
53
|
-
def __init__(self) -> None:
|
|
54
|
-
self.groups = {0 : VertexGroup()}
|
|
55
|
-
|
|
56
|
-
def __repr__(self) -> str:
|
|
57
|
-
return_string = '<Vertex Object | groups: {'
|
|
58
|
-
for vertex_group in self.groups.keys():
|
|
59
|
-
return_string += str(vertex_group) + ', '
|
|
60
|
-
return_string = return_string[:-2] + '}>'
|
|
61
|
-
return return_string
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
class VertexGroup:
|
|
65
|
-
"""
|
|
66
|
-
Groups containing the vertex data
|
|
67
|
-
vertex_group.vertex_data will be a numpy array of vertices
|
|
68
|
-
"""
|
|
69
|
-
|
|
70
|
-
def __init__(self) -> None:
|
|
71
|
-
self.vertex_data = []
|
|
72
|
-
self.tangent_data = []
|
|
73
|
-
|
|
74
|
-
def __repr__(self) -> str:
|
|
75
|
-
return f'<Vertex Group | {self.vertex_data}>'
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
def load_model(obj_file: str, calculate_tangents=False) -> Model:
|
|
79
|
-
"""
|
|
80
|
-
Loads an obj model. Returns a model class instance
|
|
81
|
-
model.vertex_data contains all vertex data combined in a single numpy array
|
|
82
|
-
Args:
|
|
83
|
-
file:
|
|
84
|
-
Path to the .obj file to load
|
|
85
|
-
calculate_tangents:
|
|
86
|
-
Calculates the tangent and bitangent vectors for normal mapping
|
|
87
|
-
"""
|
|
88
|
-
|
|
89
|
-
model = Model()
|
|
90
|
-
current_object = 0
|
|
91
|
-
current_group = 0
|
|
92
|
-
|
|
93
|
-
vertex_format = None
|
|
94
|
-
vertex_attribs = None
|
|
95
|
-
|
|
96
|
-
with open(obj_file, 'r') as file:
|
|
97
|
-
line = file.readline()
|
|
98
|
-
while line:
|
|
99
|
-
line = line.strip()
|
|
100
|
-
|
|
101
|
-
# Add object
|
|
102
|
-
if line.startswith('o '):
|
|
103
|
-
if line[2:].strip() not in model.objects:
|
|
104
|
-
model.objects[line[2:].strip()] = VertexObject()
|
|
105
|
-
current_object = line[2:].strip()
|
|
106
|
-
|
|
107
|
-
# Add group
|
|
108
|
-
elif line.startswith('g '):
|
|
109
|
-
if line[2:].strip() not in model.objects[current_object].groups:
|
|
110
|
-
model.objects[current_object].groups[line[2:].strip()] = VertexGroup()
|
|
111
|
-
current_group = line[2:].strip()
|
|
112
|
-
|
|
113
|
-
# Add vertex point
|
|
114
|
-
elif line.startswith('v '):
|
|
115
|
-
points = list(map(float, line[2:].strip().split(' ')))
|
|
116
|
-
model.vertex_points.append(points)
|
|
117
|
-
|
|
118
|
-
# Add vertex UV
|
|
119
|
-
elif line.startswith('vt '):
|
|
120
|
-
uvs = list(map(float, line[3:].strip().split(' ')))
|
|
121
|
-
model.vertex_uv.append(uvs[:2])
|
|
122
|
-
|
|
123
|
-
# Add vertex normals
|
|
124
|
-
elif line.startswith('vn '):
|
|
125
|
-
normals = list(map(float, line[3:].strip().split(' ')))
|
|
126
|
-
model.vertex_normals.append(normals)
|
|
127
|
-
|
|
128
|
-
# Create faces
|
|
129
|
-
elif line.startswith('f '):
|
|
130
|
-
corners = line[2:].strip().split(' ')
|
|
131
|
-
# The index of the position, uv, and normal in each vertex
|
|
132
|
-
vertex_indices = [[0, 0, 0] for i in range(len(corners))]
|
|
133
|
-
for corner_index, corner in enumerate(corners):
|
|
134
|
-
corner = corner.split('/')
|
|
135
|
-
|
|
136
|
-
if not vertex_format:
|
|
137
|
-
if len(corner) == 1:
|
|
138
|
-
vertex_format = '3f'
|
|
139
|
-
vertex_attribs = ['in_position']
|
|
140
|
-
elif not corner[1]:
|
|
141
|
-
vertex_format = '3f 3f'
|
|
142
|
-
vertex_attribs = ['in_position', 'in_normal']
|
|
143
|
-
else:
|
|
144
|
-
vertex_format = '3f 2f 3f'
|
|
145
|
-
vertex_attribs = ['in_position', 'in_uv', 'in_normal']
|
|
146
|
-
|
|
147
|
-
vertex = []
|
|
148
|
-
|
|
149
|
-
# Add each attribute to the vertex
|
|
150
|
-
for attribute, index in enumerate(corner):
|
|
151
|
-
if attribute == 0 and index:
|
|
152
|
-
vertex += model.vertex_points[int(index) - 1]
|
|
153
|
-
vertex_indices[corner_index][0] = int(index) - 1
|
|
154
|
-
if attribute == 1 and index:
|
|
155
|
-
vertex += model.vertex_uv[int(index) - 1]
|
|
156
|
-
vertex_indices[corner_index][1] = int(index) - 1
|
|
157
|
-
if attribute == 2 and index:
|
|
158
|
-
vertex += model.vertex_normals[int(index) - 1]
|
|
159
|
-
vertex_indices[corner_index][2] = int(index) - 1
|
|
160
|
-
|
|
161
|
-
# Replace the vertex data
|
|
162
|
-
corners[corner_index] = vertex
|
|
163
|
-
|
|
164
|
-
# Add each triangle to the objects vertex array
|
|
165
|
-
for triangle in range(len(corners) - 2):
|
|
166
|
-
if 'in_normal' not in vertex_attribs: # If the model doesnt have normals, calculate face normals
|
|
167
|
-
p1 = glm.vec3(corners[0])
|
|
168
|
-
p2 = glm.vec3(corners[1 + triangle])
|
|
169
|
-
p3 = glm.vec3(corners[2 + triangle])
|
|
170
|
-
normal = glm.normalize(glm.cross(p2 - p1, p3 - p1))
|
|
171
|
-
normal = list(normal.xyz)
|
|
172
|
-
model.vertex_normals.append(normal)
|
|
173
|
-
model.objects[current_object].groups[current_group].vertex_data.append(corners[0] + normal)
|
|
174
|
-
model.objects[current_object].groups[current_group].vertex_data.append(corners[1 + triangle] + normal)
|
|
175
|
-
model.objects[current_object].groups[current_group].vertex_data.append(corners[2 + triangle] + normal)
|
|
176
|
-
|
|
177
|
-
# Add the triangle to the indices
|
|
178
|
-
model.point_indices.append([vertex_indices[0][0], vertex_indices[1 + triangle][0], vertex_indices[2 + triangle][0]])
|
|
179
|
-
model.normal_indices.append([len(model.vertex_normals) - 1] * 3)
|
|
180
|
-
else: # Standard reading
|
|
181
|
-
model.objects[current_object].groups[current_group].vertex_data.append(corners[0])
|
|
182
|
-
model.objects[current_object].groups[current_group].vertex_data.append(corners[1 + triangle])
|
|
183
|
-
model.objects[current_object].groups[current_group].vertex_data.append(corners[2 + triangle])
|
|
184
|
-
|
|
185
|
-
# Add the triangle to the indices
|
|
186
|
-
model.point_indices.append([vertex_indices[0][0], vertex_indices[1 + triangle][0], vertex_indices[2 + triangle][0]])
|
|
187
|
-
model.uv_indices.append([vertex_indices[0][1], vertex_indices[1 + triangle][1], vertex_indices[2 + triangle][1]])
|
|
188
|
-
model.normal_indices.append([vertex_indices[0][2], vertex_indices[1 + triangle][2], vertex_indices[2 + triangle][2]])
|
|
189
|
-
|
|
190
|
-
# Calculate the tangents and bitangents
|
|
191
|
-
if calculate_tangents and 'in_uv' in vertex_attribs:
|
|
192
|
-
v1 = corners[0]
|
|
193
|
-
v2 = corners[1 + triangle]
|
|
194
|
-
v3 = corners[2 + triangle]
|
|
195
|
-
|
|
196
|
-
x1 = v2[0] - v1[0]
|
|
197
|
-
x2 = v3[0] - v1[0]
|
|
198
|
-
y1 = v2[1] - v1[1]
|
|
199
|
-
y2 = v3[1] - v1[1]
|
|
200
|
-
z1 = v2[2] - v1[2]
|
|
201
|
-
z2 = v3[2] - v1[2]
|
|
202
|
-
|
|
203
|
-
s1 = v2[3] - v1[3]
|
|
204
|
-
s2 = v3[3] - v1[3]
|
|
205
|
-
t1 = v2[4] - v1[4]
|
|
206
|
-
t2 = v3[4] - v1[4]
|
|
207
|
-
|
|
208
|
-
if (s1 * t2 - s2 * t1): r = 1.0 / (s1 * t2 - s2 * t1)
|
|
209
|
-
else: r = 1
|
|
210
|
-
|
|
211
|
-
tangent = glm.normalize(((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r))
|
|
212
|
-
bitangent = glm.normalize(((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r))
|
|
213
|
-
|
|
214
|
-
T = np.array(tangent)
|
|
215
|
-
U = np.array(bitangent)
|
|
216
|
-
N1 = np.array(corners[0][5:8])
|
|
217
|
-
N2 = np.array(corners[1 + triangle][5:8])
|
|
218
|
-
N3 = np.array(corners[2 + triangle][5:8])
|
|
219
|
-
|
|
220
|
-
T1 = T - np.dot(N1, T) * N1
|
|
221
|
-
T2 = T - np.dot(N2, T) * N2
|
|
222
|
-
T3 = T - np.dot(N3, T) * N3
|
|
223
|
-
U1 = U - np.dot(N1, U) * N1 - np.dot(T1, U) * T1
|
|
224
|
-
U2 = U - np.dot(N2, U) * N2 - np.dot(T2, U) * T2
|
|
225
|
-
U3 = U - np.dot(N3, U) * N3 - np.dot(T3, U) * T3
|
|
226
|
-
|
|
227
|
-
data = [[*T1, *U1], [*T2, *U2], [*T3, *U3]]
|
|
228
|
-
|
|
229
|
-
model.objects[current_object].groups[current_group].tangent_data.extend(data)
|
|
230
|
-
|
|
231
|
-
line = file.readline()
|
|
232
|
-
|
|
233
|
-
vertex_groups = []
|
|
234
|
-
tangent_groups = []
|
|
235
|
-
|
|
236
|
-
# Loop through all vertex objects and groups in the model
|
|
237
|
-
for object in model.objects.values():
|
|
238
|
-
for group in object.groups.values():
|
|
239
|
-
# Ignore empty groups
|
|
240
|
-
if not len(group.vertex_data): continue
|
|
241
|
-
# Convert to a numpy array
|
|
242
|
-
group.vertex_data = np.array(group.vertex_data, dtype='f4')
|
|
243
|
-
# Add to the vertex_groups list to be stacked
|
|
244
|
-
vertex_groups.append(group.vertex_data)
|
|
245
|
-
tangent_groups.append(group.tangent_data)
|
|
246
|
-
|
|
247
|
-
# Array of all vertices from all the model's groups combined
|
|
248
|
-
vertices = np.vstack(vertex_groups, dtype='f4')
|
|
249
|
-
tangents = np.vstack(tangent_groups, dtype='f4')
|
|
250
|
-
|
|
251
|
-
# Save the model's combined vertices
|
|
252
|
-
model.vertex_data = vertices
|
|
253
|
-
model.tangent_data = tangents
|
|
254
|
-
|
|
255
|
-
# Convert the points and indices to array for convenience with C-like buffers
|
|
256
|
-
model.vertex_points = np.array(model.vertex_points, dtype="f4")
|
|
257
|
-
model.vertex_uv = np.array(model.vertex_uv, dtype="f4")
|
|
258
|
-
model.vertex_normals = np.array(model.vertex_normals, dtype="f4")
|
|
259
|
-
model.point_indices = np.array(model.point_indices, dtype="i4")
|
|
260
|
-
model.uv_indices = np.array(model.uv_indices, dtype="i4")
|
|
261
|
-
model.normal_indices = np.array(model.normal_indices, dtype="i4")
|
|
262
|
-
|
|
263
|
-
# Add normals to position only models
|
|
264
|
-
if vertex_format == '3f':
|
|
265
|
-
vertex_format = '3f 3f'
|
|
266
|
-
vertex_attribs = ['in_position', 'in_normal']
|
|
267
|
-
|
|
268
|
-
# Save the model vertex format and attribs
|
|
269
|
-
model.format = vertex_format
|
|
270
|
-
model.attribs = vertex_attribs
|
|
271
|
-
|
|
1
|
+
import numpy as np
|
|
2
|
+
import glm
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Model:
|
|
6
|
+
"""
|
|
7
|
+
Instance of a loaded model. Contains all objects, groups, and vertex data
|
|
8
|
+
model.vertex_data contains all vertex data
|
|
9
|
+
Objects stored in the model.objects dictionary, where keys are the object names (marked by 'o') in the .obj
|
|
10
|
+
Default object key is '0'
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
def __init__(self) -> None:
|
|
14
|
+
self.objects = {0 : VertexObject()}
|
|
15
|
+
|
|
16
|
+
self.vertex_data = []
|
|
17
|
+
"""All vertex data in the obj. Use this for buffer data"""
|
|
18
|
+
self.tangent_data = []
|
|
19
|
+
"""Tangents and bitangents"""
|
|
20
|
+
self.format = None
|
|
21
|
+
self.attribs = None
|
|
22
|
+
|
|
23
|
+
self.vertex_points = []
|
|
24
|
+
"""The unique points given by the file"""
|
|
25
|
+
self.vertex_uv = []
|
|
26
|
+
"""The unique texture coordinates given by the file"""
|
|
27
|
+
self.vertex_normals = []
|
|
28
|
+
"""The unique normals given by the file"""
|
|
29
|
+
|
|
30
|
+
self.point_indices = []
|
|
31
|
+
"""Indices of to vertex_points to construct triangles. Grouped in three."""
|
|
32
|
+
self.uv_indices = []
|
|
33
|
+
"""Indices of to vertex_uv to construct triangles. Grouped in three."""
|
|
34
|
+
self.normal_indices = []
|
|
35
|
+
"""Indices of to vertex_normals to construct triangles. Grouped in three."""
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def __repr__(self) -> str:
|
|
39
|
+
return_string = '<Model | objects: {'
|
|
40
|
+
for vertex_object in self.objects.keys():
|
|
41
|
+
return_string += str(vertex_object) + ', '
|
|
42
|
+
return_string = return_string[:-2] + '}>'
|
|
43
|
+
return return_string
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class VertexObject:
|
|
47
|
+
"""
|
|
48
|
+
Object conataining groups of vertices.
|
|
49
|
+
Groups stored in the vertex_object.groups dictionary, where keys are the group names (marked by 'g') in the .obj
|
|
50
|
+
Default group key is '0'
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
def __init__(self) -> None:
|
|
54
|
+
self.groups = {0 : VertexGroup()}
|
|
55
|
+
|
|
56
|
+
def __repr__(self) -> str:
|
|
57
|
+
return_string = '<Vertex Object | groups: {'
|
|
58
|
+
for vertex_group in self.groups.keys():
|
|
59
|
+
return_string += str(vertex_group) + ', '
|
|
60
|
+
return_string = return_string[:-2] + '}>'
|
|
61
|
+
return return_string
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class VertexGroup:
|
|
65
|
+
"""
|
|
66
|
+
Groups containing the vertex data
|
|
67
|
+
vertex_group.vertex_data will be a numpy array of vertices
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
def __init__(self) -> None:
|
|
71
|
+
self.vertex_data = []
|
|
72
|
+
self.tangent_data = []
|
|
73
|
+
|
|
74
|
+
def __repr__(self) -> str:
|
|
75
|
+
return f'<Vertex Group | {self.vertex_data}>'
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def load_model(obj_file: str, calculate_tangents=False) -> Model:
|
|
79
|
+
"""
|
|
80
|
+
Loads an obj model. Returns a model class instance
|
|
81
|
+
model.vertex_data contains all vertex data combined in a single numpy array
|
|
82
|
+
Args:
|
|
83
|
+
file:
|
|
84
|
+
Path to the .obj file to load
|
|
85
|
+
calculate_tangents:
|
|
86
|
+
Calculates the tangent and bitangent vectors for normal mapping
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
model = Model()
|
|
90
|
+
current_object = 0
|
|
91
|
+
current_group = 0
|
|
92
|
+
|
|
93
|
+
vertex_format = None
|
|
94
|
+
vertex_attribs = None
|
|
95
|
+
|
|
96
|
+
with open(obj_file, 'r') as file:
|
|
97
|
+
line = file.readline()
|
|
98
|
+
while line:
|
|
99
|
+
line = line.strip()
|
|
100
|
+
|
|
101
|
+
# Add object
|
|
102
|
+
if line.startswith('o '):
|
|
103
|
+
if line[2:].strip() not in model.objects:
|
|
104
|
+
model.objects[line[2:].strip()] = VertexObject()
|
|
105
|
+
current_object = line[2:].strip()
|
|
106
|
+
|
|
107
|
+
# Add group
|
|
108
|
+
elif line.startswith('g '):
|
|
109
|
+
if line[2:].strip() not in model.objects[current_object].groups:
|
|
110
|
+
model.objects[current_object].groups[line[2:].strip()] = VertexGroup()
|
|
111
|
+
current_group = line[2:].strip()
|
|
112
|
+
|
|
113
|
+
# Add vertex point
|
|
114
|
+
elif line.startswith('v '):
|
|
115
|
+
points = list(map(float, line[2:].strip().split(' ')))
|
|
116
|
+
model.vertex_points.append(points)
|
|
117
|
+
|
|
118
|
+
# Add vertex UV
|
|
119
|
+
elif line.startswith('vt '):
|
|
120
|
+
uvs = list(map(float, line[3:].strip().split(' ')))
|
|
121
|
+
model.vertex_uv.append(uvs[:2])
|
|
122
|
+
|
|
123
|
+
# Add vertex normals
|
|
124
|
+
elif line.startswith('vn '):
|
|
125
|
+
normals = list(map(float, line[3:].strip().split(' ')))
|
|
126
|
+
model.vertex_normals.append(normals)
|
|
127
|
+
|
|
128
|
+
# Create faces
|
|
129
|
+
elif line.startswith('f '):
|
|
130
|
+
corners = line[2:].strip().split(' ')
|
|
131
|
+
# The index of the position, uv, and normal in each vertex
|
|
132
|
+
vertex_indices = [[0, 0, 0] for i in range(len(corners))]
|
|
133
|
+
for corner_index, corner in enumerate(corners):
|
|
134
|
+
corner = corner.split('/')
|
|
135
|
+
|
|
136
|
+
if not vertex_format:
|
|
137
|
+
if len(corner) == 1:
|
|
138
|
+
vertex_format = '3f'
|
|
139
|
+
vertex_attribs = ['in_position']
|
|
140
|
+
elif not corner[1]:
|
|
141
|
+
vertex_format = '3f 3f'
|
|
142
|
+
vertex_attribs = ['in_position', 'in_normal']
|
|
143
|
+
else:
|
|
144
|
+
vertex_format = '3f 2f 3f'
|
|
145
|
+
vertex_attribs = ['in_position', 'in_uv', 'in_normal']
|
|
146
|
+
|
|
147
|
+
vertex = []
|
|
148
|
+
|
|
149
|
+
# Add each attribute to the vertex
|
|
150
|
+
for attribute, index in enumerate(corner):
|
|
151
|
+
if attribute == 0 and index:
|
|
152
|
+
vertex += model.vertex_points[int(index) - 1]
|
|
153
|
+
vertex_indices[corner_index][0] = int(index) - 1
|
|
154
|
+
if attribute == 1 and index:
|
|
155
|
+
vertex += model.vertex_uv[int(index) - 1]
|
|
156
|
+
vertex_indices[corner_index][1] = int(index) - 1
|
|
157
|
+
if attribute == 2 and index:
|
|
158
|
+
vertex += model.vertex_normals[int(index) - 1]
|
|
159
|
+
vertex_indices[corner_index][2] = int(index) - 1
|
|
160
|
+
|
|
161
|
+
# Replace the vertex data
|
|
162
|
+
corners[corner_index] = vertex
|
|
163
|
+
|
|
164
|
+
# Add each triangle to the objects vertex array
|
|
165
|
+
for triangle in range(len(corners) - 2):
|
|
166
|
+
if 'in_normal' not in vertex_attribs: # If the model doesnt have normals, calculate face normals
|
|
167
|
+
p1 = glm.vec3(corners[0])
|
|
168
|
+
p2 = glm.vec3(corners[1 + triangle])
|
|
169
|
+
p3 = glm.vec3(corners[2 + triangle])
|
|
170
|
+
normal = glm.normalize(glm.cross(p2 - p1, p3 - p1))
|
|
171
|
+
normal = list(normal.xyz)
|
|
172
|
+
model.vertex_normals.append(normal)
|
|
173
|
+
model.objects[current_object].groups[current_group].vertex_data.append(corners[0] + normal)
|
|
174
|
+
model.objects[current_object].groups[current_group].vertex_data.append(corners[1 + triangle] + normal)
|
|
175
|
+
model.objects[current_object].groups[current_group].vertex_data.append(corners[2 + triangle] + normal)
|
|
176
|
+
|
|
177
|
+
# Add the triangle to the indices
|
|
178
|
+
model.point_indices.append([vertex_indices[0][0], vertex_indices[1 + triangle][0], vertex_indices[2 + triangle][0]])
|
|
179
|
+
model.normal_indices.append([len(model.vertex_normals) - 1] * 3)
|
|
180
|
+
else: # Standard reading
|
|
181
|
+
model.objects[current_object].groups[current_group].vertex_data.append(corners[0])
|
|
182
|
+
model.objects[current_object].groups[current_group].vertex_data.append(corners[1 + triangle])
|
|
183
|
+
model.objects[current_object].groups[current_group].vertex_data.append(corners[2 + triangle])
|
|
184
|
+
|
|
185
|
+
# Add the triangle to the indices
|
|
186
|
+
model.point_indices.append([vertex_indices[0][0], vertex_indices[1 + triangle][0], vertex_indices[2 + triangle][0]])
|
|
187
|
+
model.uv_indices.append([vertex_indices[0][1], vertex_indices[1 + triangle][1], vertex_indices[2 + triangle][1]])
|
|
188
|
+
model.normal_indices.append([vertex_indices[0][2], vertex_indices[1 + triangle][2], vertex_indices[2 + triangle][2]])
|
|
189
|
+
|
|
190
|
+
# Calculate the tangents and bitangents
|
|
191
|
+
if calculate_tangents and 'in_uv' in vertex_attribs:
|
|
192
|
+
v1 = corners[0]
|
|
193
|
+
v2 = corners[1 + triangle]
|
|
194
|
+
v3 = corners[2 + triangle]
|
|
195
|
+
|
|
196
|
+
x1 = v2[0] - v1[0]
|
|
197
|
+
x2 = v3[0] - v1[0]
|
|
198
|
+
y1 = v2[1] - v1[1]
|
|
199
|
+
y2 = v3[1] - v1[1]
|
|
200
|
+
z1 = v2[2] - v1[2]
|
|
201
|
+
z2 = v3[2] - v1[2]
|
|
202
|
+
|
|
203
|
+
s1 = v2[3] - v1[3]
|
|
204
|
+
s2 = v3[3] - v1[3]
|
|
205
|
+
t1 = v2[4] - v1[4]
|
|
206
|
+
t2 = v3[4] - v1[4]
|
|
207
|
+
|
|
208
|
+
if (s1 * t2 - s2 * t1): r = 1.0 / (s1 * t2 - s2 * t1)
|
|
209
|
+
else: r = 1
|
|
210
|
+
|
|
211
|
+
tangent = glm.normalize(((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r))
|
|
212
|
+
bitangent = glm.normalize(((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r))
|
|
213
|
+
|
|
214
|
+
T = np.array(tangent)
|
|
215
|
+
U = np.array(bitangent)
|
|
216
|
+
N1 = np.array(corners[0][5:8])
|
|
217
|
+
N2 = np.array(corners[1 + triangle][5:8])
|
|
218
|
+
N3 = np.array(corners[2 + triangle][5:8])
|
|
219
|
+
|
|
220
|
+
T1 = T - np.dot(N1, T) * N1
|
|
221
|
+
T2 = T - np.dot(N2, T) * N2
|
|
222
|
+
T3 = T - np.dot(N3, T) * N3
|
|
223
|
+
U1 = U - np.dot(N1, U) * N1 - np.dot(T1, U) * T1
|
|
224
|
+
U2 = U - np.dot(N2, U) * N2 - np.dot(T2, U) * T2
|
|
225
|
+
U3 = U - np.dot(N3, U) * N3 - np.dot(T3, U) * T3
|
|
226
|
+
|
|
227
|
+
data = [[*T1, *U1], [*T2, *U2], [*T3, *U3]]
|
|
228
|
+
|
|
229
|
+
model.objects[current_object].groups[current_group].tangent_data.extend(data)
|
|
230
|
+
|
|
231
|
+
line = file.readline()
|
|
232
|
+
|
|
233
|
+
vertex_groups = []
|
|
234
|
+
tangent_groups = []
|
|
235
|
+
|
|
236
|
+
# Loop through all vertex objects and groups in the model
|
|
237
|
+
for object in model.objects.values():
|
|
238
|
+
for group in object.groups.values():
|
|
239
|
+
# Ignore empty groups
|
|
240
|
+
if not len(group.vertex_data): continue
|
|
241
|
+
# Convert to a numpy array
|
|
242
|
+
group.vertex_data = np.array(group.vertex_data, dtype='f4')
|
|
243
|
+
# Add to the vertex_groups list to be stacked
|
|
244
|
+
vertex_groups.append(group.vertex_data)
|
|
245
|
+
tangent_groups.append(group.tangent_data)
|
|
246
|
+
|
|
247
|
+
# Array of all vertices from all the model's groups combined
|
|
248
|
+
vertices = np.vstack(vertex_groups, dtype='f4')
|
|
249
|
+
tangents = np.vstack(tangent_groups, dtype='f4')
|
|
250
|
+
|
|
251
|
+
# Save the model's combined vertices
|
|
252
|
+
model.vertex_data = vertices
|
|
253
|
+
model.tangent_data = tangents
|
|
254
|
+
|
|
255
|
+
# Convert the points and indices to array for convenience with C-like buffers
|
|
256
|
+
model.vertex_points = np.array(model.vertex_points, dtype="f4")
|
|
257
|
+
model.vertex_uv = np.array(model.vertex_uv, dtype="f4")
|
|
258
|
+
model.vertex_normals = np.array(model.vertex_normals, dtype="f4")
|
|
259
|
+
model.point_indices = np.array(model.point_indices, dtype="i4")
|
|
260
|
+
model.uv_indices = np.array(model.uv_indices, dtype="i4")
|
|
261
|
+
model.normal_indices = np.array(model.normal_indices, dtype="i4")
|
|
262
|
+
|
|
263
|
+
# Add normals to position only models
|
|
264
|
+
if vertex_format == '3f':
|
|
265
|
+
vertex_format = '3f 3f'
|
|
266
|
+
vertex_attribs = ['in_position', 'in_normal']
|
|
267
|
+
|
|
268
|
+
# Save the model vertex format and attribs
|
|
269
|
+
model.format = vertex_format
|
|
270
|
+
model.attribs = vertex_attribs
|
|
271
|
+
|
|
272
272
|
return model
|