-
Notifications
You must be signed in to change notification settings - Fork 62
/
Copy pathfast_mesh.py
96 lines (74 loc) · 3.11 KB
/
fast_mesh.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import bpy
import numpy as np
from bpy.types import Mesh
from SourceIO.library.utils.perf_sampler import timed
class FastMesh(Mesh):
__slots__ = ()
@classmethod
def new(cls, name: str) -> 'FastMesh':
mesh = bpy.data.meshes.new(name)
mesh.__class__ = cls
return mesh
@timed
def from_pydata(self,
vertices: np.ndarray,
edges: np.ndarray,
faces: np.ndarray,
shade_flat=True):
"""
Make a mesh from a list of vertices/edges/faces
Until we have a nicer way to make geometry, use this.
:arg vertices:
float triplets each representing (X, Y, Z)
eg: [(0.0, 1.0, 0.5), ...].
:type vertices: iterable object
:arg edges:
int pairs, each pair contains two indices to the
*vertices* argument. eg: [(1, 2), ...]
When an empty iterable is passed in, the edges are inferred from the polygons.
:type edges: iterable object
:arg faces:
iterator of faces, each faces contains three or more indices to
the *vertices* argument. eg: [(5, 6, 8, 9), (1, 2, 3), ...]
:type faces: iterable object
.. warning::
Invalid mesh data
*(out of range indices, edges with matching indices,
2 sided faces... etc)* are **not** prevented.
If the data used for mesh creation isn't known to be valid,
run :class:`Mesh.validate` after this function.
"""
has_faces = len(faces) > 0
has_edges = len(edges) > 0
vertices_len = len(vertices)
self.vertices.add(vertices_len)
if has_faces:
if not isinstance(faces, np.ndarray):
raise NotImplementedError("FastMesh only works with numpy arrays")
face_lengths = faces.shape[1]
faces_len = faces.shape[0]
self.loops.add(faces_len * face_lengths)
self.polygons.add(faces_len)
loop_starts = np.arange(0, faces_len * face_lengths, face_lengths, dtype=np.uint32)
self.polygons.foreach_set("loop_start", loop_starts)
self.polygons.foreach_set("vertices", faces.ravel())
self.vertices.foreach_set("co", vertices.ravel())
if has_edges:
if not isinstance(edges, np.ndarray):
raise NotImplementedError("FastMesh only works with numpy arrays")
self.edges.add(len(edges))
self.edges.foreach_set("vertices", edges.ravel())
if shade_flat:
self.shade_flat()
if has_edges or has_faces:
self.update(
# Needed to either:
# - Calculate edges that don't exist for polygons.
# - Assign edges to polygon loops.
calc_edges=has_edges,
# Flag loose edges.
calc_edges_loose=has_faces,
)
@timed
def update(self, calc_edges: bool = False, calc_edges_loose: bool = False) -> None:
return super().update(calc_edges=calc_edges, calc_edges_loose=calc_edges_loose)