ncca-ngl 0.1.4__py3-none-any.whl → 0.2.1__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.
- ncca/ngl/__init__.py +11 -1
- ncca/ngl/abstract_vao.py +6 -2
- ncca/ngl/prim_data.py +603 -0
- ncca/ngl/primitives.py +38 -525
- ncca/ngl/quaternion.py +6 -2
- ncca/ngl/shader_program.py +165 -23
- ncca/ngl/text.py +9 -3
- ncca/ngl/util.py +46 -18
- ncca/ngl/vec2.py +3 -1
- ncca/ngl/vec3.py +23 -9
- ncca/ngl/vec4.py +16 -4
- {ncca_ngl-0.1.4.dist-info → ncca_ngl-0.2.1.dist-info}/METADATA +1 -1
- {ncca_ngl-0.1.4.dist-info → ncca_ngl-0.2.1.dist-info}/RECORD +14 -13
- {ncca_ngl-0.1.4.dist-info → ncca_ngl-0.2.1.dist-info}/WHEEL +1 -1
ncca/ngl/primitives.py
CHANGED
|
@@ -6,66 +6,18 @@ We need to create the data first which is stored in a map as part of the class,
|
|
|
6
6
|
which will generate a pipeline for this object and draw into the current context.
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
|
-
import enum
|
|
10
|
-
from pathlib import Path
|
|
11
9
|
from typing import Dict, Union
|
|
12
10
|
|
|
13
11
|
import numpy as np
|
|
14
12
|
import OpenGL.GL as gl
|
|
15
13
|
|
|
16
14
|
from .log import logger
|
|
15
|
+
from .prim_data import PrimData, Prims
|
|
17
16
|
from .simple_vao import VertexData
|
|
18
17
|
from .vao_factory import VAOFactory, VAOType # noqa
|
|
19
18
|
from .vec3 import Vec3
|
|
20
19
|
|
|
21
20
|
|
|
22
|
-
class Prims(enum.Enum):
|
|
23
|
-
"""Enum for the default primitives that can be loaded."""
|
|
24
|
-
|
|
25
|
-
BUDDAH = "buddah"
|
|
26
|
-
BUNNY = "bunny"
|
|
27
|
-
CUBE = "cube"
|
|
28
|
-
DODECAHEDRON = "dodecahedron"
|
|
29
|
-
DRAGON = "dragon"
|
|
30
|
-
FOOTBALL = "football"
|
|
31
|
-
ICOSAHEDRON = "icosahedron"
|
|
32
|
-
OCTAHEDRON = "octahedron"
|
|
33
|
-
TEAPOT = "teapot"
|
|
34
|
-
TETRAHEDRON = "tetrahedron"
|
|
35
|
-
TROLL = "troll"
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def _circle_table(n: int) -> np.ndarray:
|
|
39
|
-
"""
|
|
40
|
-
Generates a table of sine and cosine values for a circle divided into n segments.
|
|
41
|
-
|
|
42
|
-
Args:
|
|
43
|
-
n: The number of segments to divide the circle into.
|
|
44
|
-
|
|
45
|
-
Returns:
|
|
46
|
-
A numpy array of shape (n+1, 2) containing the cosine and sine values.
|
|
47
|
-
"""
|
|
48
|
-
# Determine the angle between samples
|
|
49
|
-
angle = 2.0 * np.pi / (n if n != 0 else 1)
|
|
50
|
-
|
|
51
|
-
# Allocate list for n samples, plus duplicate of first entry at the end
|
|
52
|
-
cs = np.zeros((n + 1, 2), dtype=np.float32)
|
|
53
|
-
|
|
54
|
-
# Compute cos and sin around the circle
|
|
55
|
-
cs[0, 0] = 1.0 # cost
|
|
56
|
-
cs[0, 1] = 0.0 # sint
|
|
57
|
-
|
|
58
|
-
for i in range(1, n):
|
|
59
|
-
cs[i, 1] = np.sin(angle * i) # sint
|
|
60
|
-
cs[i, 0] = np.cos(angle * i) # cost
|
|
61
|
-
|
|
62
|
-
# Last sample is duplicate of the first
|
|
63
|
-
cs[n, 1] = cs[0, 1] # sint
|
|
64
|
-
cs[n, 0] = cs[0, 0] # cost
|
|
65
|
-
|
|
66
|
-
return cs
|
|
67
|
-
|
|
68
|
-
|
|
69
21
|
class _primitive:
|
|
70
22
|
"""A private class to hold VAO data for a primitive."""
|
|
71
23
|
|
|
@@ -82,12 +34,8 @@ class _primitive:
|
|
|
82
34
|
self.vao.set_data(data)
|
|
83
35
|
vert_data_size = 8 * 4 # 4 is sizeof float and 8 is x,y,z,nx,ny,nz,uv
|
|
84
36
|
self.vao.set_vertex_attribute_pointer(0, 3, gl.GL_FLOAT, vert_data_size, 0)
|
|
85
|
-
self.vao.set_vertex_attribute_pointer(
|
|
86
|
-
|
|
87
|
-
)
|
|
88
|
-
self.vao.set_vertex_attribute_pointer(
|
|
89
|
-
2, 2, gl.GL_FLOAT, vert_data_size, 2 * Vec3.sizeof()
|
|
90
|
-
)
|
|
37
|
+
self.vao.set_vertex_attribute_pointer(1, 3, gl.GL_FLOAT, vert_data_size, Vec3.sizeof())
|
|
38
|
+
self.vao.set_vertex_attribute_pointer(2, 2, gl.GL_FLOAT, vert_data_size, 2 * Vec3.sizeof())
|
|
91
39
|
self.vao.set_num_indices(prim_data.size // 8)
|
|
92
40
|
|
|
93
41
|
|
|
@@ -104,18 +52,14 @@ class Primitives:
|
|
|
104
52
|
"""Loads the default primitives from the PrimData directory."""
|
|
105
53
|
logger.info("Loading default primitives...")
|
|
106
54
|
if not cls._loaded:
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
for p in prims.items():
|
|
110
|
-
prim_data = p[1]
|
|
55
|
+
for p in Prims:
|
|
56
|
+
prim_data = PrimData.primitive(p.value)
|
|
111
57
|
prim = _primitive(prim_data)
|
|
112
|
-
cls._primitives[p
|
|
58
|
+
cls._primitives[p.value] = prim
|
|
113
59
|
cls._loaded = True
|
|
114
60
|
|
|
115
61
|
@classmethod
|
|
116
|
-
def create_line_grid(
|
|
117
|
-
cls, name: str, width: float, depth: float, steps: int
|
|
118
|
-
) -> None:
|
|
62
|
+
def create_line_grid(cls, name: str, width: float, depth: float, steps: int) -> None:
|
|
119
63
|
"""
|
|
120
64
|
Creates a line grid primitive.
|
|
121
65
|
|
|
@@ -125,42 +69,13 @@ class Primitives:
|
|
|
125
69
|
depth: The depth of the grid.
|
|
126
70
|
steps: The number of steps in the grid.
|
|
127
71
|
"""
|
|
128
|
-
# Calculate the step size for each grid value
|
|
129
|
-
wstep = width / steps
|
|
130
|
-
ws2 = width / 2.0
|
|
131
|
-
v1 = -ws2
|
|
132
|
-
|
|
133
|
-
dstep = depth / steps
|
|
134
|
-
ds2 = depth / 2.0
|
|
135
|
-
v2 = -ds2
|
|
136
|
-
|
|
137
|
-
# Create a list to store the vertex data
|
|
138
|
-
data = []
|
|
139
|
-
|
|
140
|
-
for _ in range(steps + 1):
|
|
141
|
-
# Vertex 1 x, y, z
|
|
142
|
-
data.append([-ws2, 0.0, v1])
|
|
143
|
-
# Vertex 2 x, y, z
|
|
144
|
-
data.append([ws2, 0.0, v1])
|
|
145
|
-
|
|
146
|
-
# Vertex 1 x, y, z
|
|
147
|
-
data.append([v2, 0.0, ds2])
|
|
148
|
-
# Vertex 2 x, y, z
|
|
149
|
-
data.append([v2, 0.0, -ds2])
|
|
150
|
-
|
|
151
|
-
# Now change our step value
|
|
152
|
-
v1 += wstep
|
|
153
|
-
v2 += dstep
|
|
154
|
-
|
|
155
72
|
# Convert the list to a NumPy array
|
|
156
|
-
data_array =
|
|
73
|
+
data_array = PrimData.line_grid(width, depth, steps)
|
|
157
74
|
prim = _primitive(data_array)
|
|
158
75
|
cls._primitives[name] = prim
|
|
159
76
|
|
|
160
77
|
@classmethod
|
|
161
|
-
def create_triangle_plane(
|
|
162
|
-
cls, name: str, width: float, depth: float, w_p: int, d_p: int, v_n: Vec3
|
|
163
|
-
) -> None:
|
|
78
|
+
def create_triangle_plane(cls, name: str, width: float, depth: float, w_p: int, d_p: int, v_n: Vec3) -> None:
|
|
164
79
|
"""
|
|
165
80
|
Creates a triangle plane primitive.
|
|
166
81
|
|
|
@@ -172,46 +87,8 @@ class Primitives:
|
|
|
172
87
|
d_p: The number of depth partitions.
|
|
173
88
|
v_n: The normal vector for the plane.
|
|
174
89
|
"""
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
w_step = width / w_p
|
|
178
|
-
d_step = depth / d_p
|
|
179
|
-
|
|
180
|
-
du = 0.9 / w_p
|
|
181
|
-
dv = 0.9 / d_p
|
|
182
|
-
|
|
183
|
-
data = []
|
|
184
|
-
v = 0.0
|
|
185
|
-
d = -d2
|
|
186
|
-
for _ in range(d_p):
|
|
187
|
-
u = 0.0
|
|
188
|
-
w = -w2
|
|
189
|
-
for _ in range(w_p):
|
|
190
|
-
# tri 1
|
|
191
|
-
# vert 1
|
|
192
|
-
data.extend([w, 0.0, d + d_step, v_n.x, v_n.y, v_n.z, u, v + dv])
|
|
193
|
-
# vert 2
|
|
194
|
-
data.extend(
|
|
195
|
-
[w + w_step, 0.0, d + d_step, v_n.x, v_n.y, v_n.z, u + du, v + dv]
|
|
196
|
-
)
|
|
197
|
-
# vert 3
|
|
198
|
-
data.extend([w, 0.0, d, v_n.x, v_n.y, v_n.z, u, v])
|
|
199
|
-
|
|
200
|
-
# tri 2
|
|
201
|
-
# vert 1
|
|
202
|
-
data.extend(
|
|
203
|
-
[w + w_step, 0.0, d + d_step, v_n.x, v_n.y, v_n.z, u + du, v + dv]
|
|
204
|
-
)
|
|
205
|
-
# vert 2
|
|
206
|
-
data.extend([w + w_step, 0.0, d, v_n.x, v_n.y, v_n.z, u + du, v])
|
|
207
|
-
# vert 3
|
|
208
|
-
data.extend([w, 0.0, d, v_n.x, v_n.y, v_n.z, u, v])
|
|
209
|
-
u += du
|
|
210
|
-
w += w_step
|
|
211
|
-
v += dv
|
|
212
|
-
d += d_step
|
|
213
|
-
|
|
214
|
-
data_array = np.array(data, dtype=np.float32)
|
|
90
|
+
|
|
91
|
+
data_array = PrimData.triangle_plane(width, depth, w_p, d_p, v_n)
|
|
215
92
|
prim = _primitive(data_array)
|
|
216
93
|
cls._primitives[name] = prim
|
|
217
94
|
|
|
@@ -242,82 +119,13 @@ class Primitives:
|
|
|
242
119
|
radius: The radius of the sphere.
|
|
243
120
|
precision: The precision of the sphere (number of slices).
|
|
244
121
|
"""
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
# the next part of the code calculates the P,N,UV of the sphere for triangles
|
|
248
|
-
|
|
249
|
-
# Disallow a negative number for radius.
|
|
250
|
-
if radius < 0.0:
|
|
251
|
-
radius = -radius
|
|
252
|
-
|
|
253
|
-
# Disallow a negative number for precision.
|
|
254
|
-
if precision < 4:
|
|
255
|
-
precision = 4
|
|
256
|
-
|
|
257
|
-
# Create a numpy array to store our verts
|
|
258
|
-
data = []
|
|
259
|
-
|
|
260
|
-
for i in range(precision // 2):
|
|
261
|
-
theta1 = i * 2.0 * np.pi / precision - np.pi / 2.0
|
|
262
|
-
theta2 = (i + 1) * 2.0 * np.pi / precision - np.pi / 2.0
|
|
263
|
-
|
|
264
|
-
for j in range(precision):
|
|
265
|
-
theta3 = j * 2.0 * np.pi / precision
|
|
266
|
-
theta4 = (j + 1) * 2.0 * np.pi / precision
|
|
267
|
-
|
|
268
|
-
# First triangle
|
|
269
|
-
nx1 = np.cos(theta2) * np.cos(theta3)
|
|
270
|
-
ny1 = np.sin(theta2)
|
|
271
|
-
nz1 = np.cos(theta2) * np.sin(theta3)
|
|
272
|
-
x1 = radius * nx1
|
|
273
|
-
y1 = radius * ny1
|
|
274
|
-
z1 = radius * nz1
|
|
275
|
-
u1 = j / precision
|
|
276
|
-
v1 = 2.0 * (i + 1) / precision
|
|
277
|
-
data.append([x1, y1, z1, nx1, ny1, nz1, u1, v1])
|
|
278
|
-
|
|
279
|
-
nx2 = np.cos(theta1) * np.cos(theta3)
|
|
280
|
-
ny2 = np.sin(theta1)
|
|
281
|
-
nz2 = np.cos(theta1) * np.sin(theta3)
|
|
282
|
-
x2 = radius * nx2
|
|
283
|
-
y2 = radius * ny2
|
|
284
|
-
z2 = radius * nz2
|
|
285
|
-
u2 = j / precision
|
|
286
|
-
v2 = 2.0 * i / precision
|
|
287
|
-
data.append([x2, y2, z2, nx2, ny2, nz2, u2, v2])
|
|
288
|
-
|
|
289
|
-
nx3 = np.cos(theta1) * np.cos(theta4)
|
|
290
|
-
ny3 = np.sin(theta1)
|
|
291
|
-
nz3 = np.cos(theta1) * np.sin(theta4)
|
|
292
|
-
x3 = radius * nx3
|
|
293
|
-
y3 = radius * ny3
|
|
294
|
-
z3 = radius * nz3
|
|
295
|
-
u3 = (j + 1) / precision
|
|
296
|
-
v3 = 2.0 * i / precision
|
|
297
|
-
data.append([x3, y3, z3, nx3, ny3, nz3, u3, v3])
|
|
298
|
-
|
|
299
|
-
# Second triangle
|
|
300
|
-
nx4 = np.cos(theta2) * np.cos(theta4)
|
|
301
|
-
ny4 = np.sin(theta2)
|
|
302
|
-
nz4 = np.cos(theta2) * np.sin(theta4)
|
|
303
|
-
x4 = radius * nx4
|
|
304
|
-
y4 = radius * ny4
|
|
305
|
-
z4 = radius * nz4
|
|
306
|
-
u4 = (j + 1) / precision
|
|
307
|
-
v4 = 2.0 * (i + 1) / precision
|
|
308
|
-
data.append([x4, y4, z4, nx4, ny4, nz4, u4, v4])
|
|
309
|
-
|
|
310
|
-
data.append([x1, y1, z1, nx1, ny1, nz1, u1, v1])
|
|
311
|
-
data.append([x3, y3, z3, nx3, ny3, nz3, u3, v3])
|
|
312
|
-
|
|
313
|
-
data_array = np.array(data, dtype=np.float32)
|
|
122
|
+
|
|
123
|
+
data_array = PrimData.sphere(radius, precision)
|
|
314
124
|
prim = _primitive(data_array)
|
|
315
125
|
cls._primitives[name] = prim
|
|
316
126
|
|
|
317
127
|
@classmethod
|
|
318
|
-
def create_cone(
|
|
319
|
-
cls, name: str, base: float, height: float, slices: int, stacks: int
|
|
320
|
-
) -> None:
|
|
128
|
+
def create_cone(cls, name: str, base: float, height: float, slices: int, stacks: int) -> None:
|
|
321
129
|
"""
|
|
322
130
|
Creates a cone primitive.
|
|
323
131
|
|
|
@@ -328,247 +136,46 @@ class Primitives:
|
|
|
328
136
|
slices: The number of divisions around the cone.
|
|
329
137
|
stacks: The number of divisions along the cone's height.
|
|
330
138
|
"""
|
|
331
|
-
|
|
332
|
-
r_step = base / (stacks if stacks > 0 else 1)
|
|
333
|
-
|
|
334
|
-
cosn = height / np.sqrt(height * height + base * base)
|
|
335
|
-
sinn = base / np.sqrt(height * height + base * base)
|
|
336
|
-
|
|
337
|
-
cs = _circle_table(slices)
|
|
338
|
-
|
|
339
|
-
z0 = 0.0
|
|
340
|
-
z1 = z_step
|
|
341
|
-
|
|
342
|
-
r0 = base
|
|
343
|
-
r1 = r0 - r_step
|
|
344
|
-
|
|
345
|
-
du = 1.0 / stacks
|
|
346
|
-
dv = 1.0 / slices
|
|
347
|
-
|
|
348
|
-
u = 1.0
|
|
349
|
-
v = 1.0
|
|
350
|
-
|
|
351
|
-
data = []
|
|
352
|
-
|
|
353
|
-
for _ in range(stacks):
|
|
354
|
-
for j in range(slices):
|
|
355
|
-
# First triangle
|
|
356
|
-
d1 = [0] * 8
|
|
357
|
-
d1[6] = u
|
|
358
|
-
d1[7] = v
|
|
359
|
-
d1[3] = cs[j, 0] * cosn # nx
|
|
360
|
-
d1[4] = cs[j, 1] * sinn # ny
|
|
361
|
-
d1[5] = sinn # nz
|
|
362
|
-
d1[0] = cs[j, 0] * r0 # x
|
|
363
|
-
d1[1] = cs[j, 1] * r0 # y
|
|
364
|
-
d1[2] = z0 # z
|
|
365
|
-
data.append(d1)
|
|
366
|
-
|
|
367
|
-
d2 = [0] * 8
|
|
368
|
-
d2[6] = u
|
|
369
|
-
d2[7] = v - dv
|
|
370
|
-
d2[3] = cs[j, 0] * cosn # nx
|
|
371
|
-
d2[4] = cs[j, 1] * sinn # ny
|
|
372
|
-
d2[5] = sinn # nz
|
|
373
|
-
d2[0] = cs[j, 0] * r1 # x
|
|
374
|
-
d2[1] = cs[j, 1] * r1 # y
|
|
375
|
-
d2[2] = z1 # z
|
|
376
|
-
data.append(d2)
|
|
377
|
-
|
|
378
|
-
d3 = [0] * 8
|
|
379
|
-
d3[6] = u - du
|
|
380
|
-
d3[7] = v - dv
|
|
381
|
-
d3[3] = cs[j + 1, 0] * cosn # nx
|
|
382
|
-
d3[4] = cs[j + 1, 1] * sinn # ny
|
|
383
|
-
d3[5] = sinn # nz
|
|
384
|
-
d3[0] = cs[j + 1, 0] * r1 # x
|
|
385
|
-
d3[1] = cs[j + 1, 1] * r1 # y
|
|
386
|
-
d3[2] = z1 # z
|
|
387
|
-
data.append(d3)
|
|
388
|
-
|
|
389
|
-
# Second triangle
|
|
390
|
-
d4 = [0] * 8
|
|
391
|
-
d4[6] = u
|
|
392
|
-
d4[7] = v
|
|
393
|
-
d4[3] = cs[j, 0] * cosn # nx
|
|
394
|
-
d4[4] = cs[j, 1] * sinn # ny
|
|
395
|
-
d4[5] = sinn # nz
|
|
396
|
-
d4[0] = cs[j, 0] * r0 # x
|
|
397
|
-
d4[1] = cs[j, 1] * r0 # y
|
|
398
|
-
d4[2] = z0 # z
|
|
399
|
-
data.append(d4)
|
|
400
|
-
|
|
401
|
-
d5 = [0] * 8
|
|
402
|
-
d5[6] = u - du
|
|
403
|
-
d5[7] = v - dv
|
|
404
|
-
d5[3] = cs[j + 1, 0] * cosn # nx
|
|
405
|
-
d5[4] = cs[j + 1, 1] * sinn # ny
|
|
406
|
-
d5[5] = sinn # nz
|
|
407
|
-
d5[0] = cs[j + 1, 0] * r1 # x
|
|
408
|
-
d5[1] = cs[j + 1, 1] * r1 # y
|
|
409
|
-
d5[2] = z1 # z
|
|
410
|
-
data.append(d5)
|
|
411
|
-
|
|
412
|
-
d6 = [0] * 8
|
|
413
|
-
d6[6] = u - du
|
|
414
|
-
d6[7] = v
|
|
415
|
-
d6[3] = cs[j + 1, 0] * cosn # nx
|
|
416
|
-
d6[4] = cs[j + 1, 1] * sinn # ny
|
|
417
|
-
d6[5] = sinn # nz
|
|
418
|
-
d6[0] = cs[j + 1, 0] * r0 # x
|
|
419
|
-
d6[1] = cs[j + 1, 1] * r0 # y
|
|
420
|
-
d6[2] = z0 # z
|
|
421
|
-
data.append(d6)
|
|
422
|
-
|
|
423
|
-
u -= du
|
|
424
|
-
|
|
425
|
-
v -= dv
|
|
426
|
-
u = 1.0
|
|
427
|
-
z0 = z1
|
|
428
|
-
z1 += z_step
|
|
429
|
-
r0 = r1
|
|
430
|
-
r1 -= r_step
|
|
431
|
-
|
|
432
|
-
data_array = np.array(data, dtype=np.float32)
|
|
139
|
+
data_array = PrimData.cone(base, height, slices, stacks)
|
|
433
140
|
prim = _primitive(data_array)
|
|
434
141
|
cls._primitives[name] = prim
|
|
435
142
|
|
|
436
143
|
@classmethod
|
|
437
|
-
def create_capsule(
|
|
438
|
-
cls, name: str, radius: float, height: float, precision: int
|
|
439
|
-
) -> None:
|
|
144
|
+
def create_capsule(cls, name: str, radius: float, height: float, precision: int) -> None:
|
|
440
145
|
"""
|
|
441
146
|
Creates a capsule primitive.
|
|
442
147
|
The capsule is aligned along the y-axis.
|
|
443
148
|
It is composed of a cylinder and two hemispherical caps.
|
|
444
149
|
based on code from here https://code.google.com/p/rgine/source/browse/trunk/RGine/opengl/src/RGLShapes.cpp
|
|
445
150
|
and adapted
|
|
151
|
+
|
|
152
|
+
Args:
|
|
153
|
+
name: The name of the primitive.
|
|
154
|
+
radius: The radius of the capsule.
|
|
155
|
+
height: The height of the capsule.
|
|
156
|
+
precision: The precision of the capsule.
|
|
446
157
|
"""
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
if height < 0.0:
|
|
450
|
-
raise ValueError("Height must be non-negative")
|
|
451
|
-
if precision < 4:
|
|
452
|
-
precision = 4
|
|
453
|
-
|
|
454
|
-
data = []
|
|
455
|
-
h = height / 2.0
|
|
456
|
-
ang = np.pi / precision
|
|
457
|
-
|
|
458
|
-
# Cylinder sides
|
|
459
|
-
for i in range(2 * precision):
|
|
460
|
-
c = radius * np.cos(ang * i)
|
|
461
|
-
c1 = radius * np.cos(ang * (i + 1))
|
|
462
|
-
s = radius * np.sin(ang * i)
|
|
463
|
-
s1 = radius * np.sin(ang * (i + 1))
|
|
464
|
-
|
|
465
|
-
# normals for cylinder sides
|
|
466
|
-
nc = np.cos(ang * i)
|
|
467
|
-
ns = np.sin(ang * i)
|
|
468
|
-
nc1 = np.cos(ang * (i + 1))
|
|
469
|
-
ns1 = np.sin(ang * (i + 1))
|
|
470
|
-
|
|
471
|
-
# side top
|
|
472
|
-
data.extend([c1, h, s1, nc1, 0.0, ns1, 0.0, 0.0])
|
|
473
|
-
data.extend([c, h, s, nc, 0.0, ns, 0.0, 0.0])
|
|
474
|
-
data.extend([c, -h, s, nc, 0.0, ns, 0.0, 0.0])
|
|
475
|
-
|
|
476
|
-
# side bot
|
|
477
|
-
data.extend([c, -h, s, nc, 0.0, ns, 0.0, 0.0])
|
|
478
|
-
data.extend([c1, -h, s1, nc1, 0.0, ns1, 0.0, 0.0])
|
|
479
|
-
data.extend([c1, h, s1, nc1, 0.0, ns1, 0.0, 0.0])
|
|
480
|
-
# Hemispherical caps
|
|
481
|
-
for i in range(2 * precision):
|
|
482
|
-
# longitude
|
|
483
|
-
s = -np.sin(ang * i)
|
|
484
|
-
s1 = -np.sin(ang * (i + 1))
|
|
485
|
-
c = np.cos(ang * i)
|
|
486
|
-
c1 = np.cos(ang * (i + 1))
|
|
487
|
-
|
|
488
|
-
for j in range(precision + 1):
|
|
489
|
-
o = h if j < precision / 2 else -h
|
|
490
|
-
|
|
491
|
-
# latitude
|
|
492
|
-
sb = radius * np.sin(ang * j)
|
|
493
|
-
sb1 = radius * np.sin(ang * (j + 1))
|
|
494
|
-
cb = radius * np.cos(ang * j)
|
|
495
|
-
cb1 = radius * np.cos(ang * (j + 1))
|
|
496
|
-
|
|
497
|
-
if j != precision - 1:
|
|
498
|
-
nx, ny, nz = sb * c, cb, sb * s
|
|
499
|
-
data.extend([nx, ny + o, nz, nx, ny, nz, 0.0, 0.0])
|
|
500
|
-
nx, ny, nz = sb1 * c, cb1, sb1 * s
|
|
501
|
-
data.extend([nx, ny + o, nz, nx, ny, nz, 0.0, 0.0])
|
|
502
|
-
nx, ny, nz = sb1 * c1, cb1, sb1 * s1
|
|
503
|
-
data.extend([nx, ny + o, nz, nx, ny, nz, 0.0, 0.0])
|
|
504
|
-
|
|
505
|
-
if j != 0:
|
|
506
|
-
nx, ny, nz = sb * c, cb, sb * s
|
|
507
|
-
data.extend([nx, ny + o, nz, nx, ny, nz, 0.0, 0.0])
|
|
508
|
-
nx, ny, nz = sb1 * c1, cb1, sb1 * s1
|
|
509
|
-
data.extend([nx, ny + o, nz, nx, ny, nz, 0.0, 0.0])
|
|
510
|
-
nx, ny, nz = sb * c1, cb, sb * s1
|
|
511
|
-
data.extend([nx, ny + o, nz, nx, ny, nz, 0.0, 0.0])
|
|
512
|
-
|
|
513
|
-
data_array = np.array(data, dtype=np.float32)
|
|
158
|
+
|
|
159
|
+
data_array = PrimData.capsule(radius, height, precision)
|
|
514
160
|
prim = _primitive(data_array)
|
|
515
161
|
cls._primitives[name] = prim
|
|
516
162
|
|
|
517
163
|
@classmethod
|
|
518
|
-
def create_cylinder(
|
|
519
|
-
cls, name: str, radius: float, height: float, slices: int, stacks: int
|
|
520
|
-
) -> None:
|
|
164
|
+
def create_cylinder(cls, name: str, radius: float, height: float, slices: int, stacks: int) -> None:
|
|
521
165
|
"""
|
|
522
166
|
Creates a cylinder primitive.
|
|
523
167
|
The cylinder is aligned along the y-axis.
|
|
524
168
|
This method generates the cylinder walls, but not the top and bottom caps.
|
|
169
|
+
|
|
170
|
+
Args:
|
|
171
|
+
name: The name of the primitive.
|
|
172
|
+
radius: The radius of the cylinder.
|
|
173
|
+
height: The height of the cylinder.
|
|
174
|
+
slices: The number of slices.
|
|
175
|
+
stacks: The number of stacks.
|
|
525
176
|
"""
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
if height < 0.0:
|
|
529
|
-
raise ValueError("Height must be non-negative")
|
|
530
|
-
if slices < 3:
|
|
531
|
-
slices = 3
|
|
532
|
-
if stacks < 1:
|
|
533
|
-
stacks = 1
|
|
534
|
-
|
|
535
|
-
data = []
|
|
536
|
-
h2 = height / 2.0
|
|
537
|
-
y_step = height / stacks
|
|
538
|
-
|
|
539
|
-
cs = _circle_table(slices)
|
|
540
|
-
|
|
541
|
-
du = 1.0 / slices
|
|
542
|
-
dv = 1.0 / stacks
|
|
543
|
-
|
|
544
|
-
for i in range(stacks):
|
|
545
|
-
y0 = -h2 + i * y_step
|
|
546
|
-
y1 = -h2 + (i + 1) * y_step
|
|
547
|
-
v = i * dv
|
|
548
|
-
for j in range(slices):
|
|
549
|
-
u = j * du
|
|
550
|
-
|
|
551
|
-
nx1, nz1 = cs[j, 0], cs[j, 1]
|
|
552
|
-
x1, z1 = radius * nx1, radius * nz1
|
|
553
|
-
|
|
554
|
-
nx2, nz2 = cs[j + 1, 0], cs[j + 1, 1]
|
|
555
|
-
x2, z2 = radius * nx2, radius * nz2
|
|
556
|
-
|
|
557
|
-
p_bl = [x1, y0, z1, nx1, 0, nz1, u, v]
|
|
558
|
-
p_br = [x2, y0, z2, nx2, 0, nz2, u + du, v]
|
|
559
|
-
p_tl = [x1, y1, z1, nx1, 0, nz1, u, v + dv]
|
|
560
|
-
p_tr = [x2, y1, z2, nx2, 0, nz2, u + du, v + dv]
|
|
561
|
-
|
|
562
|
-
# Triangle 1
|
|
563
|
-
data.extend(p_bl)
|
|
564
|
-
data.extend(p_tl)
|
|
565
|
-
data.extend(p_br)
|
|
566
|
-
# Triangle 2
|
|
567
|
-
data.extend(p_br)
|
|
568
|
-
data.extend(p_tl)
|
|
569
|
-
data.extend(p_tr)
|
|
570
|
-
|
|
571
|
-
data_array = np.array(data, dtype=np.float32)
|
|
177
|
+
|
|
178
|
+
data_array = PrimData.cylinder(radius, height, slices, stacks)
|
|
572
179
|
prim = _primitive(data_array)
|
|
573
180
|
cls._primitives[name] = prim
|
|
574
181
|
|
|
@@ -582,43 +189,8 @@ class Primitives:
|
|
|
582
189
|
radius: The radius of the disk.
|
|
583
190
|
slices: The number of slices to divide the disk into.
|
|
584
191
|
"""
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
if slices < 3:
|
|
588
|
-
slices = 3
|
|
589
|
-
|
|
590
|
-
data = []
|
|
591
|
-
cs = _circle_table(slices)
|
|
592
|
-
|
|
593
|
-
center = [0, 0, 0, 0, 1, 0, 0.5, 0.5]
|
|
594
|
-
|
|
595
|
-
for i in range(slices):
|
|
596
|
-
p1 = [
|
|
597
|
-
radius * cs[i, 0],
|
|
598
|
-
0,
|
|
599
|
-
radius * cs[i, 1],
|
|
600
|
-
0,
|
|
601
|
-
1,
|
|
602
|
-
0,
|
|
603
|
-
cs[i, 0] * 0.5 + 0.5,
|
|
604
|
-
cs[i, 1] * 0.5 + 0.5,
|
|
605
|
-
]
|
|
606
|
-
p2 = [
|
|
607
|
-
radius * cs[i + 1, 0],
|
|
608
|
-
0,
|
|
609
|
-
radius * cs[i + 1, 1],
|
|
610
|
-
0,
|
|
611
|
-
1,
|
|
612
|
-
0,
|
|
613
|
-
cs[i + 1, 0] * 0.5 + 0.5,
|
|
614
|
-
cs[i + 1, 1] * 0.5 + 0.5,
|
|
615
|
-
]
|
|
616
|
-
|
|
617
|
-
data.extend(center)
|
|
618
|
-
data.extend(p2)
|
|
619
|
-
data.extend(p1)
|
|
620
|
-
|
|
621
|
-
data_array = np.array(data, dtype=np.float32)
|
|
192
|
+
|
|
193
|
+
data_array = PrimData.disk(radius, slices)
|
|
622
194
|
prim = _primitive(data_array)
|
|
623
195
|
cls._primitives[name] = prim
|
|
624
196
|
|
|
@@ -641,66 +213,7 @@ class Primitives:
|
|
|
641
213
|
sides: The number of sides for each ring.
|
|
642
214
|
rings: The number of rings for the torus.
|
|
643
215
|
"""
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
if sides < 3 or rings < 3:
|
|
647
|
-
raise ValueError("Sides and rings must be at least 3")
|
|
648
|
-
|
|
649
|
-
d_psi = 2.0 * np.pi / rings
|
|
650
|
-
d_phi = -2.0 * np.pi / sides
|
|
651
|
-
|
|
652
|
-
psi = 0.0
|
|
653
|
-
|
|
654
|
-
vertices = []
|
|
655
|
-
normals = []
|
|
656
|
-
uvs = []
|
|
657
|
-
|
|
658
|
-
for j in range(rings + 1):
|
|
659
|
-
c_psi = np.cos(psi)
|
|
660
|
-
s_psi = np.sin(psi)
|
|
661
|
-
phi = 0.0
|
|
662
|
-
for i in range(sides + 1):
|
|
663
|
-
c_phi = np.cos(phi)
|
|
664
|
-
s_phi = np.sin(phi)
|
|
665
|
-
|
|
666
|
-
x = c_psi * (major_radius + c_phi * minor_radius)
|
|
667
|
-
z = s_psi * (major_radius + c_phi * minor_radius)
|
|
668
|
-
y = s_phi * minor_radius
|
|
669
|
-
vertices.append([x, y, z])
|
|
670
|
-
|
|
671
|
-
nx = c_psi * c_phi
|
|
672
|
-
nz = s_psi * c_phi
|
|
673
|
-
ny = s_phi
|
|
674
|
-
normals.append([nx, ny, nz])
|
|
675
|
-
|
|
676
|
-
u = i / sides
|
|
677
|
-
v = j / rings
|
|
678
|
-
uvs.append([u, v])
|
|
679
|
-
|
|
680
|
-
phi += d_phi
|
|
681
|
-
psi += d_psi
|
|
682
|
-
|
|
683
|
-
data = []
|
|
684
|
-
for j in range(rings):
|
|
685
|
-
for i in range(sides):
|
|
686
|
-
idx1 = j * (sides + 1) + i
|
|
687
|
-
idx2 = j * (sides + 1) + (i + 1)
|
|
688
|
-
idx3 = (j + 1) * (sides + 1) + i
|
|
689
|
-
idx4 = (j + 1) * (sides + 1) + (i + 1)
|
|
690
|
-
|
|
691
|
-
p1 = vertices[idx1] + normals[idx1] + uvs[idx1]
|
|
692
|
-
p2 = vertices[idx2] + normals[idx2] + uvs[idx2]
|
|
693
|
-
p3 = vertices[idx3] + normals[idx3] + uvs[idx3]
|
|
694
|
-
p4 = vertices[idx4] + normals[idx4] + uvs[idx4]
|
|
695
|
-
|
|
696
|
-
data.extend(p1)
|
|
697
|
-
data.extend(p3)
|
|
698
|
-
data.extend(p2)
|
|
699
|
-
|
|
700
|
-
data.extend(p2)
|
|
701
|
-
data.extend(p3)
|
|
702
|
-
data.extend(p4)
|
|
703
|
-
|
|
704
|
-
data_array = np.array(data, dtype=np.float32)
|
|
216
|
+
|
|
217
|
+
data_array = PrimData.torus(minor_radius, major_radius, sides, rings)
|
|
705
218
|
prim = _primitive(data_array)
|
|
706
219
|
cls._primitives[name] = prim
|
ncca/ngl/quaternion.py
CHANGED
|
@@ -75,7 +75,9 @@ class Quaternion:
|
|
|
75
75
|
return Quaternion(s, x, y, z)
|
|
76
76
|
|
|
77
77
|
def __add__(self, rhs):
|
|
78
|
-
return Quaternion(
|
|
78
|
+
return Quaternion(
|
|
79
|
+
self.s + rhs.s, self.x + rhs.x, self.y + rhs.y, self.z + rhs.z
|
|
80
|
+
)
|
|
79
81
|
|
|
80
82
|
def __iadd__(self, rhs):
|
|
81
83
|
self.s += rhs.s
|
|
@@ -85,7 +87,9 @@ class Quaternion:
|
|
|
85
87
|
return self
|
|
86
88
|
|
|
87
89
|
def __sub__(self, rhs):
|
|
88
|
-
return Quaternion(
|
|
90
|
+
return Quaternion(
|
|
91
|
+
self.s - rhs.s, self.x - rhs.x, self.y - rhs.y, self.z - rhs.z
|
|
92
|
+
)
|
|
89
93
|
|
|
90
94
|
def __isub__(self, rhs):
|
|
91
95
|
return self.__sub__(rhs)
|