Skip to content

Commit 8a5314a

Browse files
authored
Line Segment Support, Option to only show available frames, Updated README (#31)
* Added support for line segments * Added a toggle for only showing existent frames at the correct frames * Updated README and some pictures * Updated some tooltips
1 parent 07f5474 commit 8a5314a

File tree

10 files changed

+203
-100
lines changed

10 files changed

+203
-100
lines changed

Diff for: README.md

+101-38
Original file line numberDiff line numberDiff line change
@@ -86,94 +86,157 @@ After obtaining an installable `.zip` file either from the releases page or from
8686

8787
## 2. How to use
8888

89-
DISCLAIMER: Some of the screenshots may not be up to date with the most recent version of the addon, especially with respect to the text and ordering of UI elements.
89+
**Note**: When rendering the animation, please turn on the `Lock Interface`. This will prevent artifacts from occurring, especially if the user continues to operate the Blender interface during the render process.
9090

91-
After installing addon, you can find it in the toolbar, which is accessible here or toggled by pressing the `n` key.
91+
![lock interface](images/lock.png)
92+
93+
After installing addon, you can find it in the toolbar, which is accessible here or toggled by pressing the `N` key.
9294

9395
![drag](images/drag.png)
9496

9597
Then you can find it here.
9698

9799
![homepage](images/location.png)
98100

99-
### 2. Load the animation sequence you want
101+
### 1. Load the animation sequence you want
102+
103+
The easiest way to import sequences is to use the large "Import Sequences" button. After pressing it, you can select as many sequences as you want which will be imported to the scene after pressing `Accept`.
104+
105+
#### 1.1 Relative Paths
106+
107+
The first option is the "Relative Path" option which is turned off by default, i.e. it uses absolute paths by default.
108+
109+
To enable this option, the blender file has to be saved first. Then the sequences that are imported will be referenced using relative paths from the location of the saved `.blend` file. As such, if you move the `.blend` file in conjunction with the data to another directory (keeping their relative locations the same) the sequence loader will still work. This is especially useful when working with cloud synchronized folders, whose absolute paths may be different on different computers.
110+
111+
To change the "Root Directory" to be somewhere else please have a look at the "Global Settings" section.
112+
113+
#### 1.2 Import Default Normals
114+
115+
The sequence loader tries to look for already stored normals that have to meet certain criteria depending on the file types. Currently supported are .obj and .vtk.
116+
117+
For .obj:
118+
- Normals have to be normalized to 1. Vertex normals as well as face vertex normals (each vertex can have a different normal for each face) are supported.
119+
- Any normals are stored by using "vn". Vertex normals are simply referenced in the same order as the vertices and for face vertex normals, the respective index of the normal is stated in the third position where the vertex is referenced for face (e.g. 1/2/3 or 1//3 would reference the 3rd normal for the 1st vertex in some face).
120+
121+
For .vtk:
122+
- Only verex normals are supported. They have to be named "normals".
123+
124+
#### 1.3 Custom Transformation Matrix
125+
126+
When enabling this option, you can define a custom transformation matrix (using XYZ Euler Angles) that will be applied once when importing a sequence.
100127

101-
You can select the directory in which your data is located through the GUI by clicking the rightmost icon. It will open the default blender file explorer. Then you can go to the directory you want, for example, like image showed below. **You only need navigate to the directory and click "Accept". Files are shown but not selectable in this dialogue.**
128+
#### 1.4 Load sequences from folder (Legacy importer)
102129

103-
![directory](images/directory.png)
130+
You can select the directory in which your data is located through the GUI by clicking the folder icon. It will open the default blender file explorer. Then, when you are in the desired folder, click `Accept`. You can't select any files in this GUI.
104131

105-
Then the addon will automatically try to detect the sequences in this directory, so that you simply select the sequence you want. If the desired sequence is not shown, you can switch to enter a manual pattern, where a single `@` character is used to denote a running frame index.
132+
Then the addon will automatically try to detect the sequences in this directory, so that you simply select the sequence you want. If the desired sequence is not shown, you can enable the "Custom Pattern" option to enter a manual pattern, where a single `@` character is used to denote a running frame index.
133+
134+
The refresh button simply looks again for sequences in the selcted folder, in case there were any changes made.
135+
136+
Then click the `Load` Sequence" button to load the selected sequence or the `Load All` button to load all found sequences.
106137

107138
![sequence](images/sequence.png)
108139

109-
#### 2.1 Absolute vs. Relative Paths
140+
### 2. Global Settings
110141

111-
There is a small checkbox about whether to use `relative paths` or not.
142+
#### 2.1 Root Directory
112143

113-
When toggled on, the blender file must be saved before loading the sequence. Then this sequence will be loaded using relative path from the location of the saved `.blend` file. As such, if you move the `.blend` file in conjunction with the data to another directory (keeping their relative locations the same) the sequence loader will still work. This is especially useful when working with cloud synchronized folders, whose absolute paths may be different on different computers.
144+
This is where a new root directory can be set. All relative paths will be relative to this directory. If left empty, the file path of the Blender file will be used.
114145

115-
If toggled off (default), it will use absolute path to load the sequence. For this, the `.blend` file does not have to be saved in advance.
146+
#### 2.2 Print Sequence Information
116147

117-
![relative_path](images/path.png)
148+
Print some useful information during rendering in a file located in the same folder as the render output and in the console. For the latter, Blender has to be started from the console.
118149

119-
#### 2.2 Sequence List View
150+
#### 2.3 Auto Refresh Active Sequences
120151

121-
After the sequence being imported, it will be available in the `Imported Sequences` panel, with more settings being available in `Sequence Settings` panel once a sequence has been selected.
152+
Automatically refresh all active sequences whenever the frame changes. See "Refresh Sequence" for further explanations. This can be useful when generating a sequence and rendering is done simultaneously.
122153

123-
![settings](images/list.png)
154+
#### 2.4 Auto Refresh All Sequences
124155

125-
By default, all supported file formats are simply imported as geometry (a collection of vertices, lines, triangles and quads). As such, you should be able to directly play/render the animation if it contains geometry.
156+
Like the above but with all sequences.
126157

127-
Note: When rendering the animation, please turn on the `Lock Interface`. This will prevent artifacts from occurring, especially if the user continues to operate the Blender interface during the render process.
158+
### 3. Sequence List View
128159

129-
![lock interface](images/lock.png)
160+
After the sequence being imported, it will be available in the `Sequences` panel, with more settings being available in `Sequence Settings` panel once a sequence has been selected.
161+
162+
![settings](images/list.png)
163+
164+
For each sequence we show the name, a button that shows whether a sequence is active or inactive (this button is clickable, see the next section for more details on the functionality), the current frame number which is also driver that can be edited as well as the smallest and largest number of the respective sequence.
130165

131-
##### 2.2.1 Enable/ Disable
166+
##### 3.1 Activate / Deactivate Sequences
132167

133-
It is possible to individually enable and disable sequences from updating when the animation frame changes. This is very useful when working with very large files or many sequences as it reduces the computational overhead of loading these sequences.
134-
`Enabled` means, that the sequence will be updated on frame change, and `Disabled` means that the sequence won't be updated on frame change.
168+
It is possible to individually activate or deactivate sequences from updating when the animation frame changes. This is very useful when working with very large files or many sequences as it reduces the computational overhead of loading these sequences.
169+
`Activated` means, that the sequence will be updated on frame change, and `Deactivated` means that the sequence won't be updated on frame change.
135170

136-
##### 2.2.1 Refresh Sequence
171+
##### 3.2 Refresh Sequence
137172

138173
`Refresh Sequence` can be useful when the sequence is imported while the data is still being generated and not yet complete. Refreshing the sequence can detect the frames added after being imported.
139174

140-
#### 2.3 Settings
175+
#### 3.3 Activate / Deactivate All
141176

142-
#### 2.3.1 Geometry Nodes
177+
Activate or deactivate all sequences shown in the sequences view.
143178

144-
While all files are imported as plain geometry, we provide some templates that we have found to be incredibly useful for visualizing particle data.
179+
#### 3.4 Set Timeline
145180

146-
Applying the `Point Cloud` geometry node, the vertices of the mesh are converted to a point cloud, which can be rendered only by [cycles](https://docs.blender.org/manual/en/latest/render/cycles/introduction.html) and only as spheres. The exact geometry node setup can be seen in the geometry nodes tab and may be modified as desired, e.g. to set the particle radius.
181+
Sets the Blender timeline to range of the smallest to largest number of a file of the selected sequence.
147182

148-
Applying `Instances` geometry nodes, the vertices of the mesh are converted to cubes, which can be rendered by both [eevee](https://docs.blender.org/manual/en/latest/render/eevee/index.html) and [cycles](https://docs.blender.org/manual/en/latest/render/cycles/introduction.html). The exact geometry node setup can be seen in the geometry nodes tab and may be modified as desired, e.g. to set the particle radius and to change the instanced geometry. **CAUTION: Because this node setup relies on the `Realize Instances` node, the memory usage increases extremely rapidly. Make sure to save the `.blend` file before attempting this, as Blender may run out of memory!!!**
183+
### 4. Sequence Properties
149184

150-
Applying the `Mesh` geometry node will restore the default geometry nodes, which simply display the imported geometry as it is.
185+
#### 4.1 Match Blender Frame Numbers
151186

152-
Notes:
187+
This shows the file of a sequence at the frame number exactly matching the number in the file, otherwise it will not show anything. So if a file sequence goes from 2-10 and 15-30 only at these frames the respective files will be shown.
153188

154-
1. `Instances` is super memory hungry compared with `Point Cloud`.
155-
2. After applying `Point Cloud` or `Instances` geometry nodes, you need to assign the material inside the geometry nodes. So to save your work, you can simply assign the material here, then apply the `Point Cloud` or `Instances` geometry nodes.
156-
3. To access the attributes for shading, use the `Attribute` node in the Shader Editor and simply specify the attribute string. The imported attributes can be seen in the spreadsheet browser of the Geometry Nodes tab and are also listed in the addon UI.
189+
By default this option is turned off and the sequence starts in Blender from 0 and on each following frame the next available file is loaded. For frame number larger than the length of the file sequence, this procedure is looped.
157190

158-
![material](images/geometry_nodes.png)
191+
#### 4.2 Path
192+
193+
The path of the file sequence is shown here and can also be edited. Relative paths start with // which basically is placeholder for the root directory.
194+
195+
#### 4.3 Pattern
196+
197+
Here you can see and edit the pattern of a file sequence that is used to detect the sequence as well as to determine how many frames the sequence has. A pattern consists of the name, then the frame range followed by an @ and at last, the file extension.
198+
199+
#### 4.4 Current File
159200

160-
#### 2.3.2 Path Information
201+
This is read-only and shows the absolute path of the file that is currenlty loaded from the selected sequence.
161202

162-
This shows the path of the sequence for debugging purposes, however it's not editable.
203+
#### 4.5 Last Loading Time
163204

164-
#### 2.3.3 Attributes Settings
205+
Read-only field, that shows how long it took to load the current file in milliseconds.
206+
207+
#### 4.6 Attributes Settings
165208

166209
This panel shows the available **Vertex Attributes**, it's not editable.
167210

168211
Note: In order to avoid conflicts with Blenders built-in attributes, all the attributes names are renamed by prefixing `bseq_`. For example, `id` -> `bseq_id`. Keep this in mind when accessing attributes in the shader editor.
169212

170-
#### 2.3.4 Split Norm per Vertex
213+
#### 4.6.1 Split Norm per Vertex
171214

172215
We also provide the ability to use a per-vertex vector attribute as custom normals for shading.
173216
For more details check the official documentation [here](https://docs.blender.org/manual/en/latest/modeling/meshes/structure.html#modeling-meshes-normals-custom).
174217

175218
Note: the addon does not check if the selected attribute is suitable for normals or not. E.g. if the data type of the attribute is int instead of float, then Blender will simply give a runtime error.
176219

177-
#### 2.3.5 Advanced Settings
220+
### 5. Advanced Settings
221+
222+
#### 5.1 Script
223+
224+
Here you can import your own script for loading and preprocessing your file sequences. For more information look at the teplate.py file under Scripting -> Templates -> Sequence Loader -> Template.
225+
226+
#### 5.2 Geometry Nodes
227+
228+
While all files are imported as plain geometry, we provide some templates that we have found to be incredibly useful for visualizing particle data.
229+
230+
Applying the `Point Cloud` geometry node, the vertices of the mesh are converted to a point cloud, which can be rendered only by [cycles](https://docs.blender.org/manual/en/latest/render/cycles/introduction.html) and only as spheres. The exact geometry node setup can be seen in the geometry nodes tab and may be modified as desired, e.g. to set the particle radius.
231+
232+
Applying `Instances` geometry nodes, the vertices of the mesh are converted to cubes, which can be rendered by both [eevee](https://docs.blender.org/manual/en/latest/render/eevee/index.html) and [cycles](https://docs.blender.org/manual/en/latest/render/cycles/introduction.html). The exact geometry node setup can be seen in the geometry nodes tab and may be modified as desired, e.g. to set the particle radius and to change the instanced geometry. **CAUTION: Because this node setup relies on the `Realize Instances` node, the memory usage increases extremely rapidly. Make sure to save the `.blend` file before attempting this, as Blender may run out of memory!!!**
178233

179-
TODO
234+
Applying the `Mesh` geometry node will restore the default geometry nodes, which simply display the imported geometry as it is.
235+
236+
Notes:
237+
238+
1. `Instances` is super memory hungry compared with `Point Cloud`.
239+
2. After applying `Point Cloud` or `Instances` geometry nodes, you need to assign the material inside the geometry nodes. So to save your work, you can simply assign the material here, then apply the `Point Cloud` or `Instances` geometry nodes.
240+
3. To access the attributes for shading, use the `Attribute` node in the Shader Editor and simply specify the attribute string. The imported attributes can be seen in the spreadsheet browser of the Geometry Nodes tab and are also listed in the addon UI.
241+
242+
![material](images/geometry_nodes.png)

Diff for: bseq/importer.py

+37-21
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,17 @@
44
import traceback
55
import fileseq
66
import os
7-
from .utils import show_message_box, get_relative_path, get_absolute_path
7+
from .utils import show_message_box, get_relative_path, get_absolute_path, load_meshio_from_path
88
import numpy as np
99
from mathutils import Matrix
1010
import time
1111
# this import is not useless
1212
import additional_file_formats
1313

14+
def extract_edges(cell: meshio.CellBlock):
15+
if cell.type == "line":
16+
return cell.data.astype(np.uint64)
17+
return np.array([])
1418

1519
def extract_faces(cell: meshio.CellBlock):
1620
if cell.type == "triangle":
@@ -51,6 +55,8 @@ def extract_faces(cell: meshio.CellBlock):
5155
return faces
5256
elif cell.type == "vertex":
5357
return np.array([])
58+
elif cell.type == "line":
59+
return np.array([])
5460
show_message_box(cell.type + " is unsupported mesh format yet")
5561
return np.array([])
5662

@@ -124,21 +130,27 @@ def update_mesh(meshio_mesh, mesh):
124130
mesh.update()
125131
mesh.validate()
126132
return
133+
edges = np.array([], dtype=np.uint64)
127134
faces_loop_start = np.array([], dtype=np.uint64)
128135
faces_loop_total = np.array([], dtype=np.uint64)
129136
loops_vert_idx = np.array([], dtype=np.uint64)
130137
shade_scheme = False
131138
if mesh.polygons:
132139
shade_scheme = mesh.polygons[0].use_smooth
140+
133141
for cell in meshio_mesh.cells:
134-
data = extract_faces(cell)
135-
# np array can't be simply written as `if not data:`,
136-
if not data.any():
137-
continue
138-
n_poly += len(data)
139-
n_loop += data.shape[0] * data.shape[1]
140-
loops_vert_idx = np.append(loops_vert_idx, data.ravel())
141-
faces_loop_total = np.append(faces_loop_total, np.ones((len(data)), dtype=np.uint64) * data.shape[1])
142+
edge_data = extract_edges(cell)
143+
face_data = extract_faces(cell)
144+
145+
if edge_data.any():
146+
edges = np.append(edges, edge_data)
147+
148+
if face_data.any():
149+
n_poly += len(face_data)
150+
n_loop += face_data.shape[0] * face_data.shape[1]
151+
loops_vert_idx = np.append(loops_vert_idx, face_data.ravel())
152+
faces_loop_total = np.append(faces_loop_total, np.ones((len(face_data)), dtype=np.uint64) * face_data.shape[1])
153+
142154
if faces_loop_total.size > 0:
143155
faces_loop_start = np.cumsum(faces_loop_total)
144156
# Add a zero as first entry
@@ -150,18 +162,20 @@ def update_mesh(meshio_mesh, mesh):
150162
else:
151163
mesh.clear_geometry()
152164
mesh.vertices.add(n_verts)
165+
mesh.edges.add(len(edge_data))
153166
mesh.loops.add(n_loop)
154167
mesh.polygons.add(n_poly)
155168

156169
mesh.vertices.foreach_set("co", mesh_vertices.ravel())
170+
mesh.edges.foreach_set("vertices", edges)
157171
mesh.loops.foreach_set("vertex_index", loops_vert_idx)
158172
mesh.polygons.foreach_set("loop_start", faces_loop_start)
159173
mesh.polygons.foreach_set("loop_total", faces_loop_total)
160174
mesh.polygons.foreach_set("use_smooth", [shade_scheme] * len(faces_loop_total))
161175

162176
# newer function but is about 4 times slower
163177
# mesh.clear_geometry()
164-
# mesh.from_pydata(mesh_vertices, [], data)
178+
# mesh.from_pydata(mesh_vertices, edge_data, face_data)
165179

166180
mesh.update()
167181
mesh.validate()
@@ -202,7 +216,7 @@ def update_mesh(meshio_mesh, mesh):
202216
indices = [item for sublist in meshio_mesh.cell_data["obj:vn_face_idx"][0] for item in sublist]
203217
mesh.normals_split_custom_set([meshio_mesh.field_data["obj:vn"][i - 1] for i in indices])
204218

205-
# function to create a single meshio object
219+
# function to create a single meshio object (not a sequence, this just inports some file using meshio)
206220
def create_meshio_obj(filepath):
207221
meshio_mesh = None
208222
try:
@@ -316,16 +330,18 @@ def update_obj(scene, depsgraph=None):
316330
finally:
317331
del locals()['preprocess']
318332
else:
319-
filepath = fs[current_frame % len(fs)]
320-
filepath = os.path.normpath(filepath)
321-
try:
322-
meshio_mesh = meshio.read(filepath)
323-
obj.BSEQ.current_file = filepath
324-
except Exception as e:
325-
show_message_box("Error when reading: " + filepath + ",\n" + traceback.format_exc(),
326-
"Meshio Loading Error" + str(e),
327-
icon="ERROR")
328-
continue
333+
if obj.BSEQ.match_frames:
334+
fs_frames = fs.frameSet()
335+
if current_frame in fs_frames:
336+
filepath = fs[fs_frames.index(current_frame)]
337+
filepath = os.path.normpath(filepath)
338+
meshio_mesh = load_meshio_from_path(fs, filepath, obj)
339+
else:
340+
meshio_mesh = meshio.Mesh([], [])
341+
else:
342+
filepath = fs[current_frame % len(fs)]
343+
filepath = os.path.normpath(filepath)
344+
meshio_mesh = load_meshio_from_path(fs, filepath, obj)
329345

330346
if not isinstance(meshio_mesh, meshio.Mesh):
331347
show_message_box('function preprocess does not return meshio object', "ERROR")

0 commit comments

Comments
 (0)