- added renderer

- Added undo
This commit is contained in:
bklronin
2026-07-12 23:25:59 +02:00
parent 9f1387fe68
commit dda9db822b
2 changed files with 36 additions and 25 deletions
+22 -16
View File
@@ -4,19 +4,9 @@
<option name="autoReloadType" value="SELECTIVE" /> <option name="autoReloadType" value="SELECTIVE" />
</component> </component>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="8f0bafd6-58a0-4b20-aa2b-ddc3ba278873" name="Changes" comment="- Working assembly multi :)"> <list default="true" id="8f0bafd6-58a0-4b20-aa2b-ddc3ba278873" name="Changes" comment="- added renderer&#10;- Added undo">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/gui.ui" beforeDir="false" afterPath="$PROJECT_DIR$/gui.ui" afterDir="false" /> <change beforePath="$PROJECT_DIR$/src/fluency/rendering/occ_to_mesh.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/fluency/rendering/occ_to_mesh.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/gui_ui.py" beforeDir="false" afterPath="$PROJECT_DIR$/gui_ui.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/fluency/geometry/base.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/fluency/geometry/base.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/fluency/geometry_occ/sketch.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/fluency/geometry_occ/sketch.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/fluency/io/project_io.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/fluency/io/project_io.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/fluency/models/data_model.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/fluency/models/data_model.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/fluency/rendering/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/fluency/rendering/__init__.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/fluency/rendering/occ_renderer.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/fluency/rendering/occ_renderer.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/fluency/ui/main_window.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/fluency/ui/main_window.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/fluency/ui/sketch_widget.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/fluency/ui/sketch_widget.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/fluency/ui/viewer_widget.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/fluency/ui/viewer_widget.py" afterDir="false" />
</list> </list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -405,7 +395,23 @@
<option name="project" value="LOCAL" /> <option name="project" value="LOCAL" />
<updated>1783798929531</updated> <updated>1783798929531</updated>
</task> </task>
<option name="localTasksCounter" value="36" /> <task id="LOCAL-00036" summary="- added renderer">
<option name="closed" value="true" />
<created>1783887682052</created>
<option name="number" value="00036" />
<option name="presentableId" value="LOCAL-00036" />
<option name="project" value="LOCAL" />
<updated>1783887682052</updated>
</task>
<task id="LOCAL-00037" summary="- added renderer&#10;- Added undo">
<option name="closed" value="true" />
<created>1783887704766</created>
<option name="number" value="00037" />
<option name="presentableId" value="LOCAL-00037" />
<option name="project" value="LOCAL" />
<updated>1783887704766</updated>
</task>
<option name="localTasksCounter" value="38" />
<servers /> <servers />
</component> </component>
<component name="TypeScriptGeneratedFilesManager"> <component name="TypeScriptGeneratedFilesManager">
@@ -426,8 +432,6 @@
<ignored-roots> <ignored-roots>
<path value="$PROJECT_DIR$/pythonProject" /> <path value="$PROJECT_DIR$/pythonProject" />
</ignored-roots> </ignored-roots>
<MESSAGE value="init" />
<MESSAGE value="- Basic oop sketch widget implement" />
<MESSAGE value="- Renabled extrusion with new object system" /> <MESSAGE value="- Renabled extrusion with new object system" />
<MESSAGE value="- Sketch projection partly works again :)" /> <MESSAGE value="- Sketch projection partly works again :)" />
<MESSAGE value="- Added new componnt controls" /> <MESSAGE value="- Added new componnt controls" />
@@ -451,6 +455,8 @@
<MESSAGE value="- assembly draft" /> <MESSAGE value="- assembly draft" />
<MESSAGE value="- Added save file foramt&#10;- Split main.py refactor" /> <MESSAGE value="- Added save file foramt&#10;- Split main.py refactor" />
<MESSAGE value="- Working assembly multi :)" /> <MESSAGE value="- Working assembly multi :)" />
<option name="LAST_COMMIT_MESSAGE" value="- Working assembly multi :)" /> <MESSAGE value="- added renderer" />
<MESSAGE value="- added renderer&#10;- Added undo" />
<option name="LAST_COMMIT_MESSAGE" value="- added renderer&#10;- Added undo" />
</component> </component>
</project> </project>
+14 -9
View File
@@ -87,17 +87,18 @@ def occ_shape_to_ply(
f"Tessellation: {len(vertices)} vertices, {len(faces)} triangles" f"Tessellation: {len(vertices)} vertices, {len(faces)} triangles"
) )
# Compute outward-facing vertex normals from triangle geometry. # Compute outward-facing vertex normals AND correct face winding.
# This ensures consistent lighting even when OCC triangulation winding # OCC triangulation produces inconsistent winding across faces (especially
# is inconsistent across faces (e.g. after location transforms). # after location transforms). Mitsuba uses face winding for front/back
normals = _compute_outward_normals(vertices, faces, shape) # determination, so both normals AND winding must be consistent.
normals, corrected_faces = _compute_outward_normals(vertices, faces, shape)
# Write PLY with normals # Write PLY with corrected faces and normals
if output_path is None: if output_path is None:
fd, output_path = tempfile.mkstemp(suffix=".ply", prefix="fluency_render_") fd, output_path = tempfile.mkstemp(suffix=".ply", prefix="fluency_render_")
os.close(fd) os.close(fd)
_write_ply(output_path, vertices, faces, normals) _write_ply(output_path, vertices, corrected_faces, normals)
logger.info(f"Wrote PLY: {output_path}") logger.info(f"Wrote PLY: {output_path}")
return output_path return output_path
@@ -106,14 +107,18 @@ def _compute_outward_normals(
vertices: np.ndarray, vertices: np.ndarray,
faces: np.ndarray, faces: np.ndarray,
shape, shape,
) -> np.ndarray: ) -> Tuple[np.ndarray, np.ndarray]:
"""Compute outward-facing vertex normals. """Compute outward-facing vertex normals and correct face winding.
1. Compute per-face normals from cross product of triangle edges. 1. Compute per-face normals from cross product of triangle edges.
2. Determine correct orientation by checking face normals against the 2. Determine correct orientation by checking face normals against the
shape centroid (outward = away from center). shape centroid (outward = away from center).
3. Flip triangles with inward normals before accumulating to vertices. 3. Flip triangles with inward normals before accumulating to vertices.
4. Average and normalize per-vertex normals. 4. Average and normalize per-vertex normals.
Returns (normals, corrected_faces) so the PLY writer can use consistent
winding order — critical for Mitsuba which uses winding for front/back
face determination.
""" """
n_verts = len(vertices) n_verts = len(vertices)
v_normals = np.zeros((n_verts, 3), dtype=np.float64) v_normals = np.zeros((n_verts, 3), dtype=np.float64)
@@ -189,7 +194,7 @@ def _compute_outward_normals(
v_lengths[v_lengths < 1e-10] = 1.0 v_lengths[v_lengths < 1e-10] = 1.0
v_normals /= v_lengths v_normals /= v_lengths
return v_normals.astype(np.float32) return v_normals.astype(np.float32), corrected_faces.astype(np.uint32)
def occ_shape_to_stl( def occ_shape_to_stl(