From 74bdc36093a4fc4e612537edfbff22c5a4b49eca Mon Sep 17 00:00:00 2001 From: Carifio24 Date: Fri, 29 Nov 2024 02:56:34 -0500 Subject: [PATCH 1/4] Sanitize USD path for scatter layer. --- glue_ar/common/scatter_usd.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/glue_ar/common/scatter_usd.py b/glue_ar/common/scatter_usd.py index 8d35fca..98953ee 100644 --- a/glue_ar/common/scatter_usd.py +++ b/glue_ar/common/scatter_usd.py @@ -14,6 +14,7 @@ from glue_ar.common.usd_builder import USDBuilder from glue_ar.common.shapes import cone_triangles, cone_points, cylinder_points, cylinder_triangles, \ normalize, rectangular_prism_triangulation, sphere_triangles +from glue_ar.usd_utils import sanitize_path from glue_ar.utils import Viewer3DState, export_label_for_layer, iterable_has_nan, hex_to_components, \ layer_color, offset_triangles, xyz_for_layer, Bounds, NoneType @@ -94,7 +95,7 @@ def add_scatter_layer_usd( color_mode_attr = "color_mode" if vispy_layer_state else "cmap_mode" fixed_color = getattr(layer_state, color_mode_attr, "Fixed") == "Fixed" - identifier = export_label_for_layer(layer_state).replace(" ", "_") + identifier = sanitize_path(export_label_for_layer(layer_state)) mask = scatter_layer_mask(viewer_state, layer_state, bounds, clip_to_bounds) data = xyz_for_layer(viewer_state, layer_state, From 7c6bacd3cc86544287ef88b14a6881698a893591 Mon Sep 17 00:00:00 2001 From: Carifio24 Date: Fri, 29 Nov 2024 02:58:21 -0500 Subject: [PATCH 2/4] Use combined meshes for voxel USD export. Bin opacities before alpha compositing. --- glue_ar/common/volume_export_options.py | 2 +- glue_ar/common/voxels.py | 63 ++++++++++++++++--------- 2 files changed, 41 insertions(+), 24 deletions(-) diff --git a/glue_ar/common/volume_export_options.py b/glue_ar/common/volume_export_options.py index 18cf3a7..155bd55 100644 --- a/glue_ar/common/volume_export_options.py +++ b/glue_ar/common/volume_export_options.py @@ -12,4 +12,4 @@ class ARIsosurfaceExportOptions(State): class ARVoxelExportOptions(State): opacity_cutoff = RangedCallbackProperty(default=0.1, min_value=0.01, max_value=1, resolution=0.01) - opacity_resolution = RangedCallbackProperty(default=0.02, min_value=0.01, max_value=1, resolution=0.01) + opacity_resolution = RangedCallbackProperty(default=0.02, min_value=0.005, max_value=1, resolution=0.005) diff --git a/glue_ar/common/voxels.py b/glue_ar/common/voxels.py index e2450b0..e142fce 100644 --- a/glue_ar/common/voxels.py +++ b/glue_ar/common/voxels.py @@ -1,3 +1,4 @@ +from collections import defaultdict from glue_vispy_viewers.volume.viewer_state import Vispy3DVolumeViewerState from numpy import isfinite, argwhere, transpose from typing import Iterable, Optional @@ -9,10 +10,10 @@ from glue_ar.common.stl_builder import STLBuilder from glue_ar.common.usd_builder import USDBuilder from glue_ar.common.volume_export_options import ARVoxelExportOptions -from glue_ar.usd_utils import material_for_color +from glue_ar.usd_utils import material_for_color, sanitize_path from glue_ar.utils import BoundsWithResolution, alpha_composite, binned_opacity, clamp, clamped_opacity, \ clip_sides, frb_for_layer, hex_to_components, isomin_for_layer, \ - isomax_for_layer, layer_color, unique_id, xyz_bounds + isomax_for_layer, layer_color, offset_triangles, unique_id, xyz_bounds from glue_ar.gltf_utils import add_points_to_bytearray, add_triangles_to_bytearray, \ index_mins, index_maxes @@ -83,7 +84,7 @@ def add_voxel_layers_gltf(builder: GLTFBuilder, for indices in nonempty_indices: value = data[tuple(indices)] - adjusted_opacity = clamped_opacity(layer_state.alpha * opacity_factor * (value - isomin) / isorange) + adjusted_opacity = binned_opacity(layer_state.alpha * opacity_factor * (value - isomin) / isorange, opacity_resolution) indices_tpl = tuple(indices) if indices_tpl in occupied_voxels: current_color = occupied_voxels[indices_tpl] @@ -126,7 +127,7 @@ def add_voxel_layers_gltf(builder: GLTFBuilder, mins=pt_mins, maxes=pt_maxes, ) - rgba_tpl = tuple(rgba[:3] + [binned_opacity(rgba[3], opacity_resolution)]) + rgba_tpl = tuple(rgba) if rgba_tpl in materials_map: material_index = materials_map[rgba_tpl] else: @@ -162,8 +163,11 @@ def add_voxel_layers_usd(builder: USDBuilder, triangles = rectangular_prism_triangulation() + identifier = sanitize_path(f"voxels_{unique_id()}") + opacity_factor = 1 occupied_voxels = {} + colors_map = defaultdict(set) for layer_state, option in zip(layer_states, options): opacity_cutoff = clamp(option.opacity_cutoff, 0, 1) @@ -185,37 +189,49 @@ def add_voxel_layers_usd(builder: USDBuilder, for indices in nonempty_indices: value = data[tuple(indices)] - adjusted_opacity = clamped_opacity(layer_state.alpha * opacity_factor * (value - isomin) / isorange) + adjusted_opacity = binned_opacity(layer_state.alpha * opacity_factor * (value - isomin) / isorange, opacity_resolution) indices_tpl = tuple(indices) if indices_tpl in occupied_voxels: current_color = occupied_voxels[indices_tpl] adjusted_a_color = color_components[:3] + [adjusted_opacity] new_color = alpha_composite(adjusted_a_color, current_color) occupied_voxels[indices_tpl] = new_color + colors_map[current_color].remove(indices_tpl) + colors_map[new_color].add(indices_tpl) elif adjusted_opacity >= opacity_cutoff: - occupied_voxels[indices_tpl] = color_components[:3] + [adjusted_opacity] + color = color_components[:3] + [adjusted_opacity] + occupied_voxels[indices_tpl] = color + colors_map[tuple(color)].add(indices_tpl) + materials_map = {} - mesh = None - first_point = None - for indices, rgba in occupied_voxels.items(): + + for rgba, indices_set in colors_map.items(): if rgba[-1] < opacity_cutoff: continue - center = tuple((index + 0.5) * side for index, side in zip(indices, sides)) - rgba_tpl = tuple(rgba[:3] + [binned_opacity(rgba[3], opacity_resolution)]) - if rgba_tpl in materials_map: - material = materials_map[rgba_tpl] + if rgba in materials_map: + material = materials_map[rgba] else: material = material_for_color(builder.stage, rgba[:3], rgba[3]) - materials_map[rgba_tpl] = material - - points = rectangular_prism_points(center, sides) - if mesh is None: - mesh = builder.add_mesh(points, triangles, rgba[:3], rgba[3]) - first_point = center - else: - translation = tuple(p - fp for p, fp in zip(center, first_point)) - builder.add_translated_reference(mesh, translation, material) + materials_map[rgba] = material + points = [] + tris = [] + triangle_offset = 0 + for indices in indices_set: + center = tuple((index + 0.5) * side for index, side in zip(indices, sides)) + pts = rectangular_prism_points(center, sides) + points.append(pts) + pt_triangles = offset_triangles(triangles, triangle_offset) + triangle_offset += len(pts) + tris.append(pt_triangles) + + mesh_points = [pt for pts in points for pt in pts] + mesh_triangles = [tri for sphere in tris for tri in sphere] + builder.add_mesh(mesh_points, + mesh_triangles, + color=rgba[:3], + opacity=rgba[-1], + identifier=identifier) return builder @@ -238,6 +254,7 @@ def add_voxel_layers_stl(builder: STLBuilder, for layer_state, option in zip(layer_states, options): opacity_cutoff = clamp(option.opacity_cutoff, 0, 1) + opacity_resolution = clamp(option.opacity_resolution, 0, 1) data = frb_for_layer(viewer_state, layer_state, bounds) isomin = isomin_for_layer(viewer_state, layer_state) @@ -255,7 +272,7 @@ def add_voxel_layers_stl(builder: STLBuilder, for indices in nonempty_indices: value = data[tuple(indices)] - adjusted_opacity = clamped_opacity(layer_state.alpha * opacity_factor * (value - isomin) / isorange) + adjusted_opacity = binned_opacity(layer_state.alpha * opacity_factor * (value - isomin) / isorange, opacity_resolution) indices_tpl = tuple(indices) if indices_tpl in occupied_voxels: current_color = occupied_voxels[indices_tpl] From d5cfadf6c9bfe3a801f8154ebba2b0788ad19633 Mon Sep 17 00:00:00 2001 From: Carifio24 Date: Mon, 2 Dec 2024 09:58:57 -0500 Subject: [PATCH 3/4] Codestyle fixes. --- glue_ar/common/voxels.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/glue_ar/common/voxels.py b/glue_ar/common/voxels.py index e142fce..de9d388 100644 --- a/glue_ar/common/voxels.py +++ b/glue_ar/common/voxels.py @@ -11,7 +11,7 @@ from glue_ar.common.usd_builder import USDBuilder from glue_ar.common.volume_export_options import ARVoxelExportOptions from glue_ar.usd_utils import material_for_color, sanitize_path -from glue_ar.utils import BoundsWithResolution, alpha_composite, binned_opacity, clamp, clamped_opacity, \ +from glue_ar.utils import BoundsWithResolution, alpha_composite, binned_opacity, clamp, \ clip_sides, frb_for_layer, hex_to_components, isomin_for_layer, \ isomax_for_layer, layer_color, offset_triangles, unique_id, xyz_bounds @@ -84,7 +84,8 @@ def add_voxel_layers_gltf(builder: GLTFBuilder, for indices in nonempty_indices: value = data[tuple(indices)] - adjusted_opacity = binned_opacity(layer_state.alpha * opacity_factor * (value - isomin) / isorange, opacity_resolution) + adjusted_opacity = binned_opacity(layer_state.alpha * opacity_factor * (value - isomin) / isorange, + opacity_resolution) indices_tpl = tuple(indices) if indices_tpl in occupied_voxels: current_color = occupied_voxels[indices_tpl] @@ -189,7 +190,8 @@ def add_voxel_layers_usd(builder: USDBuilder, for indices in nonempty_indices: value = data[tuple(indices)] - adjusted_opacity = binned_opacity(layer_state.alpha * opacity_factor * (value - isomin) / isorange, opacity_resolution) + adjusted_opacity = binned_opacity(layer_state.alpha * opacity_factor * (value - isomin) / isorange, + opacity_resolution) indices_tpl = tuple(indices) if indices_tpl in occupied_voxels: current_color = occupied_voxels[indices_tpl] @@ -199,7 +201,7 @@ def add_voxel_layers_usd(builder: USDBuilder, colors_map[current_color].remove(indices_tpl) colors_map[new_color].add(indices_tpl) elif adjusted_opacity >= opacity_cutoff: - color = color_components[:3] + [adjusted_opacity] + color = color_components[:3] + [adjusted_opacity] occupied_voxels[indices_tpl] = color colors_map[tuple(color)].add(indices_tpl) @@ -272,7 +274,8 @@ def add_voxel_layers_stl(builder: STLBuilder, for indices in nonempty_indices: value = data[tuple(indices)] - adjusted_opacity = binned_opacity(layer_state.alpha * opacity_factor * (value - isomin) / isorange, opacity_resolution) + adjusted_opacity = binned_opacity(layer_state.alpha * opacity_factor * (value - isomin) / isorange, + opacity_resolution) indices_tpl = tuple(indices) if indices_tpl in occupied_voxels: current_color = occupied_voxels[indices_tpl] From e47bbc7df87d2642aa2f11539f159d1225880637 Mon Sep 17 00:00:00 2001 From: Carifio24 Date: Mon, 2 Dec 2024 13:41:30 -0500 Subject: [PATCH 4/4] Replace spaces with underscores when sanitizing USD paths. --- glue_ar/usd_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/glue_ar/usd_utils.py b/glue_ar/usd_utils.py index cc714dc..c9aa2f6 100644 --- a/glue_ar/usd_utils.py +++ b/glue_ar/usd_utils.py @@ -39,4 +39,4 @@ def material_for_mesh(mesh: UsdGeom.Mesh) -> UsdShade.Material: def sanitize_path(path: str) -> str: - return sub(r"[-\(\)\[\]]+", "_", path) + return sub(r"[-\(\)\[\] ]+", "_", path)