Skip to content

fix: label join scalar cannot get scalar offset #16

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions bioxelnodes/assets/Nodes/BioxelNodes_4.0.blend
Git LFS file not shown
4 changes: 2 additions & 2 deletions bioxelnodes/assets/Nodes/BioxelNodes_4.1.blend
Git LFS file not shown
12 changes: 7 additions & 5 deletions bioxelnodes/customnodes/menus.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,16 +163,18 @@ def find_item(self, node_type: str):

def add_node(self, node_tree, node_type: str):
item = self.find_item(node_type)
op = AddCustomNode()
op.nodes_file = self.nodes_file
op.node_type = node_type
if item:
op = AddCustomNode()
op.nodes_file = self.nodes_file
op.node_type = item['node_type']
op.node_label = item.get('label') or ""
op.node_link = item.get('link') or True
op.node_callback = item.get('node_callback') or ""
return op.add_node(node_tree)
else:
raise RuntimeError("Not found in menu.")
op.node_label = ""
op.node_link = True
op.node_callback = ""
return op.add_node(node_tree)

def register(self):
for cls in self.menu_classes:
Expand Down
30 changes: 16 additions & 14 deletions bioxelnodes/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,14 +236,14 @@ def execute(self, context):

if self.read_as == "labels":
if "vector" in image.GetPixelIDTypeAsString():
print("Convet to Grayscale...")
print("Conveting to Grayscale...")
image = x2gray(image)
else:
image = sitk.Cast(image, sitk.sitkUInt16)
default_value = 0
elif self.read_as == "scalar":
if "vector" in image.GetPixelIDTypeAsString():
print("Convet to Grayscale...")
print("Conveting to Grayscale...")
image = rgb2gray(image)
else:
image = sitk.Cast(image, sitk.sitkFloat32)
Expand All @@ -258,6 +258,9 @@ def execute(self, context):
interpolator = sitk.sitkNearestNeighbor
elif self.resample_method == "gaussian":
interpolator = sitk.sitkGaussian

if self.read_as == "labels":
interpolator = sitk.sitkNearestNeighbor

print(f"Resampling...")
image = sitk.Resample(
Expand Down Expand Up @@ -448,16 +451,15 @@ def create_layer(array, layer_name, layer_type="scalar"):
input_node = get_node_by_type(nodes, 'NodeGroupInput')[0]
output_node = get_node_by_type(nodes, 'NodeGroupOutput')[0]

node_type = 'BioxelNodes_AsLabel' if layer_type == "label" else 'BioxelNodes_AsScalar'
source_node = custom_nodes.add_node(nodes, node_type)
to_layer_node = custom_nodes.add_node(nodes, "BioxelNodes__ConvertToLayer")

links.new(input_node.outputs[0], source_node.inputs[0])
links.new(source_node.outputs[0], output_node.inputs[0])
links.new(input_node.outputs[0], to_layer_node.inputs[0])
links.new(to_layer_node.outputs[0], output_node.inputs[0])

source_node.inputs['Bioxel Size'].default_value = bioxel_size
source_node.inputs['Shape'].default_value = layer_shape
source_node.inputs['Origin'].default_value = layer_origin
source_node.inputs['Rotation'].default_value = layer_rotation
to_layer_node.inputs['Bioxel Size'].default_value = bioxel_size
to_layer_node.inputs['Shape'].default_value = layer_shape
to_layer_node.inputs['Origin'].default_value = layer_origin
to_layer_node.inputs['Rotation'].default_value = layer_rotation

return layer

Expand Down Expand Up @@ -511,10 +513,10 @@ def create_layer(array, layer_name, layer_type="scalar"):
layer_type="scalar")

layer_node_tree = layer.modifiers[0].node_group
source_node = layer_node_tree.nodes['BioxelNodes_AsScalar']
source_node.inputs['Offset'].default_value = scalar_offset
source_node.inputs['Max'].default_value = orig_max
source_node.inputs['Min'].default_value = orig_min
to_layer_node = layer_node_tree.nodes['BioxelNodes__ConvertToLayer']
to_layer_node.inputs['Scalar Offset'].default_value = scalar_offset
to_layer_node.inputs['Scalar Max'].default_value = orig_max
to_layer_node.inputs['Scalar Min'].default_value = orig_min

output_node = get_node_by_type(container_node_tree.nodes,
'NodeGroupOutput')[0]
Expand Down
50 changes: 2 additions & 48 deletions bioxelnodes/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,29 +166,6 @@ def set_prop_to_node_factory(source_prop, target_prop):
'icon': 'CONSTRAINT_BONE',
'node_type': 'BioxelNodes_JoinComponent',
'node_description': ''
},
{
'label': 'Separate Component',
'node_type': 'BioxelNodes_SeparateComponent',
'node_description': ''
}
]
},
{
'label': 'Others',
'icon': 'PACKAGE',
'items': [
{
'label': 'Source As Label',
'icon': 'GP_SELECT_POINTS',
'node_type': 'BioxelNodes_AsLabel',
'node_description': ''
},
{
'label': 'Source As Scalar',
'icon': 'GP_SELECT_STROKES',
'node_type': 'BioxelNodes_AsScalar',
'node_description': ''
}
]
}
Expand Down Expand Up @@ -286,9 +263,9 @@ def set_prop_to_node_factory(source_prop, target_prop):
'icon': 'MOD_BEVEL',
'items': [
{
'label': 'Apply Cutters',
'label': 'Cut',
'icon': 'MOD_BEVEL',
'node_type': 'BioxelNodes_ApplyCutters',
'node_type': 'BioxelNodes_Cut',
'node_description': ''
},
"separator",
Expand All @@ -315,29 +292,6 @@ def set_prop_to_node_factory(source_prop, target_prop):
'icon': 'CONSTRAINT_BONE',
'node_type': 'BioxelNodes_JoinComponent',
'node_description': ''
},
{
'label': 'Separate Component',
'node_type': 'BioxelNodes_SeparateComponent',
'node_description': ''
}
]
},
{
'label': 'Others',
'icon': 'PACKAGE',
'items': [
{
'label': 'Source As Label',
'icon': 'GP_SELECT_POINTS',
'node_type': 'BioxelNodes_AsLabel',
'node_description': ''
},
{
'label': 'Source As Scalar',
'icon': 'GP_SELECT_STROKES',
'node_type': 'BioxelNodes_AsScalar',
'node_description': ''
}
]
}
Expand Down
52 changes: 45 additions & 7 deletions bioxelnodes/operators.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,14 @@ def execute(self, context):

layers = []
if self.scalar_layer != "None":
layers.append(bpy.data.objects[self.scalar_layer])
scalar_layer = bpy.data.objects[self.scalar_layer]
layers.append(scalar_layer)

if self.label_layer != "None":
layers.append(bpy.data.objects[self.label_layer])
label_layer = bpy.data.objects[self.label_layer]
layers.append(label_layer)

# if self.color_layer:
# layers.append(bpy.data.objects[self.color_layer])
# TODO: add color and vector

if len(layers) == 0:
self.report({"WARNING"}, "No additinal layers setted.")
Expand All @@ -106,8 +107,45 @@ def execute(self, context):
filepath=str(vdb_path), align='WORLD', location=(0, 0, 0), scale=(1, 1, 1))

joined_layer = bpy.context.active_object
bpy.ops.object.modifier_add(type='NODES')
joined_layer.modifiers[0].node_group = base_layer.modifiers[0].node_group

base_layer_node = base_layer.modifiers[0].node_group.nodes['BioxelNodes__ConvertToLayer']
bioxel_size = base_layer_node.inputs['Bioxel Size'].default_value
layer_shape = base_layer_node.inputs['Shape'].default_value
layer_origin = base_layer_node.inputs['Origin'].default_value
layer_rotation = base_layer_node.inputs['Rotation'].default_value
scalar_offset = base_layer_node.inputs['Scalar Offset'].default_value
scalar_min = base_layer_node.inputs['Scalar Min'].default_value
scalar_max = base_layer_node.inputs['Scalar Max'].default_value

if self.scalar_layer != "None":
scalar_layer_node = scalar_layer.modifiers[0].node_group.nodes['BioxelNodes__ConvertToLayer']
scalar_offset = scalar_layer_node.inputs['Scalar Offset'].default_value
scalar_min = scalar_layer_node.inputs['Scalar Min'].default_value
scalar_max = scalar_layer_node.inputs['Scalar Max'].default_value

bpy.ops.node.new_geometry_nodes_modifier()
node_tree = joined_layer.modifiers[0].node_group
nodes = node_tree.nodes
links = node_tree.links

input_node = get_node_by_type(nodes, 'NodeGroupInput')[0]
output_node = get_node_by_type(nodes, 'NodeGroupOutput')[0]


joined_layer_node = custom_nodes.add_node(
nodes, "BioxelNodes__ConvertToLayer")


links.new(input_node.outputs[0], joined_layer_node.inputs[0])
links.new(joined_layer_node.outputs[0], output_node.inputs[0])

joined_layer_node.inputs['Bioxel Size'].default_value = bioxel_size
joined_layer_node.inputs['Shape'].default_value = layer_shape
joined_layer_node.inputs['Origin'].default_value = layer_origin
joined_layer_node.inputs['Rotation'].default_value = layer_rotation
joined_layer_node.inputs['Scalar Offset'].default_value = scalar_offset
joined_layer_node.inputs['Scalar Min'].default_value = scalar_min
joined_layer_node.inputs['Scalar Max'].default_value = scalar_max

# Set props to VDB object
joined_layer.name = f"{base_layer.name}_Joined"
Expand Down Expand Up @@ -169,7 +207,7 @@ def execute(self, context):
object_node = nodes.new("GeometryNodeObjectInfo")
realize_nodes = nodes.new("GeometryNodeRealizeInstances")
separate_node = custom_nodes.add_node(
nodes, "BioxelNodes_SeparateComponent")
nodes, "BioxelNodes__SeparateComponent")

object_node.inputs[0].default_value = container
separate_node.inputs[1].default_value = 1
Expand Down
2 changes: 1 addition & 1 deletion docs/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Bioxel Design Concept

According to Bioxel design concept, Bioxel Nodes imports volume data and put it into a **Container** as a **Layer**. One container may has more than one layer, and each layer stores the information of different fields under the same location, which is similar to the view layer of map app, except that here it is in 3D space. In order to render the volume the way we want it to, we need to build a renderable object from layers. We call this object **Component**. The following diagram shows the relationship of **Container**, **Layer**, and **Component**:
According to Bioxel design concept, Bioxel Nodes imports volume data and put it into a **Container** as a **Layer**. One container may has more than one layer, and each layer stores the information of different fields under the same location, which is similar to the view layers in map app, except that here it is in 3D space. In order to render the volume the way we want it to, we need to build renderable objects from layers. We call those objects **Component**. The following diagram shows the relationship of **Container**, **Layer**, and **Component**:

![alt text](assets/features_concept.png)

Expand Down
53 changes: 18 additions & 35 deletions docs/nodes.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,41 +251,6 @@ This type of node is responsible for cutting components to present cross-section

</div>

## Utils

### 📦 Join Component

<div class="grid cards" markdown>

- ![alt text](assets/nodes_join-component.png)

- Components' combination should not be done by "Join Geometry" node because Blender Cycles can't render volumes in the same position, so the node will slightly offset all components randomly to avoid this problem.

***

Node Parameter:

- **Component 0~4**, _the components_

</div>

### 🗂️ Separate Component

<div class="grid cards" markdown>

- ![alt text](assets/nodes_separate-component.png)

- Volumes, previews, and guides are included within a component. This node can split them by type.

***

Node Parameter:

- **Component**, _the upstream component_
- **Type**, _the sub-object type, 0 is volume, 1 is preview, 2 is guide_

</div>

## Colors

This type of node is responsible for setting the color properties of the shader
Expand Down Expand Up @@ -406,3 +371,21 @@ This type of node is responsible for setting the color properties of the shader
- **Contrast**, _the larger the contrast, the harder color ramp will be_

</div>

## Utils

### 📦 Join Component

<div class="grid cards" markdown>

- ![alt text](assets/nodes_join-component.png)

- Components' combination should not be done by "Join Geometry" node because Blender Cycles can't render volumes in the same position, so the node will slightly offset all components randomly to avoid this problem.

***

Node Parameter:

- **Component 0~4**, _the components_

</div>