fix: join component cause missing

feat: extract mesh from node
This commit is contained in:
2024-09-13 16:42:18 +08:00
parent 80da400891
commit 133702619e
11 changed files with 194 additions and 48 deletions

Binary file not shown.

View File

@@ -2,7 +2,7 @@ from ast import literal_eval
from pathlib import Path
import bpy
from ..constants import NODE_LIB_DIRPATH, VERSIONS
from ..constants import LATEST_NODE_LIB_PATH, NODE_LIB_DIRPATH, VERSIONS
from ..utils import get_cache_dir
@@ -244,7 +244,7 @@ def get_node_lib_path(node_version):
def local_lib_not_updated():
addon_version = VERSIONS[0]["node_version"]
addon_lib_path = get_node_lib_path(addon_version)
addon_lib_path = LATEST_NODE_LIB_PATH
use_local = False
for node_group in bpy.data.node_groups:
@@ -258,3 +258,12 @@ def local_lib_not_updated():
not_update = get_node_version() != addon_version
return use_local and not_update
def get_output_node(node_group):
try:
output_node = get_nodes_by_type(node_group,
'NodeGroupOutput')[0]
except:
output_node = node_group.nodes.new("NodeGroupOutput")
return output_node

View File

@@ -8,7 +8,7 @@ from mathutils import Matrix, Vector
from .layer import Layer, layer_to_obj, obj_to_layer
from .common import (get_container_layer_objs,
get_layer_prop_value,
get_nodes_by_type,
get_nodes_by_type, get_output_node,
move_node_to_node)
from .node import add_node_to_graph
from ..utils import get_use_link
@@ -82,11 +82,7 @@ def add_layers(layers: list[Layer],
cache_dir: str):
node_group = container_obj.modifiers[0].node_group
try:
output_node = get_nodes_by_type(node_group,
'NodeGroupOutput')[0]
except:
output_node = node_group.nodes.new("NodeGroupOutput")
output_node = get_output_node(node_group)
for i, layer in enumerate(layers):
layer_obj = layer_to_obj(layer, container_obj, cache_dir)

View File

@@ -4,7 +4,7 @@ import bpy
from .common import get_file_prop, get_node_lib_path, set_file_prop
from ..exceptions import Incompatible, NoFound
from ..constants import VERSIONS
from ..constants import LATEST_NODE_LIB_PATH, VERSIONS
def get_node_group(node_type: str, use_link=True):
@@ -14,7 +14,7 @@ def get_node_group(node_type: str, use_link=True):
# added node is always from latest node version
addon_version = VERSIONS[0]["node_version"]
addon_lib_path = get_node_lib_path(addon_version)
addon_lib_path = LATEST_NODE_LIB_PATH
if get_file_prop("node_version") is None:
set_file_prop("node_version", addon_version)

View File

@@ -1,7 +1,7 @@
schema_version = "1.0.0"
id = "bioxelnodes"
version = "1.0.0"
version = "1.0.1"
name = "Bioxel Nodes"
tagline = "For scientific volumetric data visualization in Blender"
maintainer = "Ma Nan <icrdr2010@outlook.com>"
@@ -10,7 +10,7 @@ website = "https://omoolab.github.io/BioxelNodes/latest"
tags = ["Geometry Nodes", "Render", "Import-Export"]
blender_version_min = "4.2.0"
license = ["SPDX:MIT"]
license = ['SPDX:GPL-3.0-or-later']
copyright = ["2024 OmooLab"]
platforms = ["windows-x64", "linux-x64", "macos-arm64", "macos-x64"]

View File

@@ -1,12 +1,31 @@
from pathlib import Path
VERSIONS = [{"label": "Current", "node_version": (1, 0, 0)},
VERSIONS = [{"label": "Latest", "node_version": (1, 0, 1)},
{"label": "v0.3.x", "node_version": (0, 3, 3)},
{"label": "v0.2.x", "node_version": (0, 2, 9)}]
NODE_LIB_DIRPATH = Path(Path(__file__).parent,
"assets/Nodes").resolve()
LATEST_NODE_LIB_PATH = lib_path = Path(NODE_LIB_DIRPATH,
"BioxelNodes_latest.blend").resolve()
COMPONENT_OUTPUT_NODES = [
"CutoutByThreshold",
"CutoutByRange",
"CutoutByHue",
"JoinComponent",
"SetProperties",
"SetColor",
"SetColorByColor",
"SetColorByColor",
"SetColorByRamp2",
"SetColorByRamp3",
"SetColorByRamp4",
"SetColorByRamp5",
"Cut",
]
MENU_ITEMS = [
{
'label': 'Component',
@@ -179,9 +198,9 @@ MENU_ITEMS = [
'icon': 'MODIFIER',
'items': [
{
'label': 'Fetch Surface',
'label': 'Fetch Mesh',
'icon': 'OUTLINER_OB_MESH',
'name': 'FetchSurface',
'name': 'FetchMesh',
'description': ''
},
{

View File

@@ -10,16 +10,19 @@ from .operators.layer import (FetchLayer, RelocateLayer, RetimeLayer, RenameLaye
RemoveSelectedLayers, SaveSelectedLayersCache,
ResampleLayer, SignScalar, CombineLabels,
FillByLabel, FillByThreshold, FillByRange)
from .operators.container import (AddLocator, AddSlicer, ExtractShapeWire,
from .operators.container import (AddLocator, AddSlicer, ContainerProps,
SaveContainerLayersCache, RemoveContainerMissingLayers,
SaveContainer, LoadContainer,
AddPieCutter, AddPlaneCutter,
AddCylinderCutter, AddCubeCutter, AddSphereCutter,
ExtractBboxWire, ExtractSurface, ExtractVolume, ContainerProps)
ExtractBboxWire, ExtractMesh, ExtractVolume, ExtractShapeWire,
ExtractNodeMesh, ExtractNodeBboxWire, ExtractNodeVolume, ExtractNodeShapeWire)
from .operators.io import (ImportAsLabel, ImportAsScalar, ImportAsColor)
from .operators.misc import (CleanTemp,
ReLinkNodeLib, RemoveAllMissingLayers, RenderSettingPreset, SaveAllLayersCache, SaveNodeLib, SliceViewer)
ReLinkNodeLib, RemoveAllMissingLayers,
RenderSettingPreset, SaveAllLayersCache,
SaveNodeLib, SliceViewer)
class IncompatibleMenu(bpy.types.Menu):
@@ -76,7 +79,7 @@ class ExtractFromContainerMenu(bpy.types.Menu):
def draw(self, context):
layout = self.layout
layout.operator(ExtractSurface.bl_idname)
layout.operator(ExtractMesh.bl_idname)
layout.operator(ExtractVolume.bl_idname)
layout.operator(ExtractShapeWire.bl_idname)
layout.operator(ExtractBboxWire.bl_idname)
@@ -199,8 +202,8 @@ class BioxelNodesTopbarMenu(bpy.types.Menu):
layout.operator(RemoveAllMissingLayers.bl_idname)
layout.separator()
layout.operator(SaveNodeLib.bl_idname)
layout.menu(ReLinkNodeLibMenu.bl_idname)
layout.operator(SaveNodeLib.bl_idname)
layout.separator()
layout.menu(DangerZoneMenu.bl_idname)
@@ -257,6 +260,12 @@ class NodeContextMenu(bpy.types.Menu):
def draw(self, context):
layout = self.layout
layout.operator(ExtractNodeMesh.bl_idname)
layout.operator(ExtractNodeVolume.bl_idname)
layout.operator(ExtractNodeShapeWire.bl_idname)
layout.operator(ExtractNodeBboxWire.bl_idname)
layout.separator()
layout.operator(SaveSelectedLayersCache.bl_idname,
icon=SaveSelectedLayersCache.bl_icon)
layout.operator(RemoveSelectedLayers.bl_idname)

View File

@@ -1,13 +1,15 @@
import bpy
import bmesh
from ..constants import COMPONENT_OUTPUT_NODES
from ..utils import get_cache_dir, get_use_link, select_object
from ..bioxel.io import load_container, save_container
from ..bioxelutils.container import container_to_obj, obj_to_container
from ..bioxelutils.node import add_node_to_graph
from ..bioxelutils.common import (get_container_layer_objs, get_container_obj,
get_nodes_by_type, is_missing_layer,
from ..bioxelutils.common import (get_container_layer_objs, get_container_obj, get_node_type,
get_nodes_by_type, get_output_node, is_missing_layer,
move_node_between_nodes,
move_node_to_node,
get_all_layer_objs)
@@ -77,7 +79,7 @@ class LoadContainer(bpy.types.Operator):
return {'RUNNING_MODAL'}
class ExtractObject():
class ExtractNodeObject():
bl_options = {'UNDO'}
def execute(self, context):
@@ -87,6 +89,26 @@ class ExtractObject():
self.report({"WARNING"}, "Cannot find any bioxel container.")
return {'FINISHED'}
# nodes = [node for node in context.selected_nodes
# if get_node_type(node).removeprefix("BioxelNodes_") in COMPONENT_OUTPUT_NODES]
if len(context.selected_nodes) == 0:
self.report({"WARNING"}, "No node selected.")
return {'FINISHED'}
selected_node = context.selected_nodes[0]
container_node_group = container_obj.modifiers[0].node_group
container_output_node = get_output_node(container_node_group)
if len(container_output_node.inputs[0].links) == 0:
pre_socket = None
else:
pre_socket = container_output_node.inputs[0].links[0].from_socket
container_node_group.links.new(selected_node.outputs[0],
container_output_node.inputs[0])
bpy.ops.mesh.primitive_cube_add(
size=2, enter_editmode=False, align='WORLD', location=(0, 0, 0), scale=(1, 1, 1))
obj = bpy.context.active_object
@@ -106,6 +128,15 @@ class ExtractObject():
fetch_mesh_node.inputs[0].default_value = container_obj
node_group.links.new(fetch_mesh_node.outputs[0], output_node.inputs[0])
for modifier in obj.modifiers:
bpy.ops.object.modifier_apply(modifier=modifier.name)
obj.data.materials.clear()
if pre_socket:
container_node_group.links.new(pre_socket,
container_output_node.inputs[0])
select_object(obj)
self.report({"INFO"}, f"Successfully picked")
@@ -113,16 +144,90 @@ class ExtractObject():
return {'FINISHED'}
class ExtractSurface(bpy.types.Operator, ExtractObject):
bl_idname = "bioxelnodes.fetch_mesh"
bl_label = "Extract Surface"
bl_description = "Extract Surface"
class ExtractNodeMesh(bpy.types.Operator, ExtractNodeObject):
bl_idname = "bioxelnodes.extract_node_mesh"
bl_label = "Extract Mesh"
bl_description = "Extract Mesh"
bl_icon = "OUTLINER_OB_MESH"
object_type = "Surface"
object_type = "Mesh"
class ExtractNodeVolume(bpy.types.Operator, ExtractNodeObject):
bl_idname = "bioxelnodes.extract_node_volume"
bl_label = "Extract Volume"
bl_description = "Extract Volume"
bl_icon = "OUTLINER_OB_VOLUME"
object_type = "Volume"
class ExtractNodeShapeWire(bpy.types.Operator, ExtractNodeObject):
bl_idname = "bioxelnodes.extract_node_shape_wire"
bl_label = "Extract Shape Wire"
bl_description = "Extract Shape Wire"
bl_icon = "FILE_VOLUME"
object_type = "ShapeWire"
class ExtractNodeBboxWire(bpy.types.Operator, ExtractNodeObject):
bl_idname = "bioxelnodes.extract_node_bbox_wire"
bl_label = "Extract Bbox Wire"
bl_description = "Extract Bbox Wire"
bl_icon = "MESH_CUBE"
object_type = "BboxWire"
class ExtractObject():
bl_options = {'UNDO'}
def execute(self, context):
container_obj = get_container_obj(context.object)
if container_obj is None:
self.report({"WARNING"}, "Cannot find any bioxel container.")
return {'FINISHED'}
bpy.ops.mesh.primitive_cube_add(
size=2, enter_editmode=False, align='WORLD', location=(0, 0, 0), scale=(1, 1, 1))
obj = bpy.context.active_object
obj.name = f"{container_obj.name}_{self.object_type}"
bpy.ops.node.new_geometry_nodes_modifier()
modifier = obj.modifiers[0]
node_group = modifier.node_group
output_node = get_output_node(node_group)
fetch_mesh_node = add_node_to_graph(f"Fetch{self.object_type}",
node_group,
node_label=f"Fetch {self.object_type}",
use_link=get_use_link())
fetch_mesh_node.inputs[0].default_value = container_obj
node_group.links.new(fetch_mesh_node.outputs[0], output_node.inputs[0])
for modifier in obj.modifiers:
bpy.ops.object.modifier_apply(modifier=modifier.name)
obj.data.materials.clear()
select_object(obj)
self.report({"INFO"}, f"Successfully picked")
return {'FINISHED'}
class ExtractMesh(bpy.types.Operator, ExtractObject):
bl_idname = "bioxelnodes.extract_mesh"
bl_label = "Extract Mesh"
bl_description = "Extract Mesh"
bl_icon = "OUTLINER_OB_MESH"
object_type = "Mesh"
class ExtractVolume(bpy.types.Operator, ExtractObject):
bl_idname = "bioxelnodes.pick_volume"
bl_idname = "bioxelnodes.extract_volume"
bl_label = "Extract Volume"
bl_description = "Extract Volume"
bl_icon = "OUTLINER_OB_VOLUME"
@@ -130,7 +235,7 @@ class ExtractVolume(bpy.types.Operator, ExtractObject):
class ExtractShapeWire(bpy.types.Operator, ExtractObject):
bl_idname = "bioxelnodes.pick_shape_wire"
bl_idname = "bioxelnodes.extract_shape_wire"
bl_label = "Extract Shape Wire"
bl_description = "Extract Shape Wire"
bl_icon = "FILE_VOLUME"
@@ -138,7 +243,7 @@ class ExtractShapeWire(bpy.types.Operator, ExtractObject):
class ExtractBboxWire(bpy.types.Operator, ExtractObject):
bl_idname = "bioxelnodes.pick_bbox_wire"
bl_idname = "bioxelnodes.extract_bbox_wire"
bl_label = "Extract Bbox Wire"
bl_description = "Extract Bbox Wire"
bl_icon = "MESH_CUBE"
@@ -253,8 +358,8 @@ class AddCutter():
node_group,
use_link=get_use_link())
output_node = get_nodes_by_type(node_group,
'NodeGroupOutput')[0]
output_node = get_output_node(node_group)
if len(output_node.inputs[0].links) == 0:
node_group.links.new(cut_node.outputs[0],
output_node.inputs[0])
@@ -277,7 +382,7 @@ class AddCutter():
node_name="ObjectCutter",
node_label=name)
node = bpy.context.active_node
node.inputs[0].default_value = name
node.inputs[0].default_value = self.cutter_type.capitalize()
node.inputs[1].default_value = cutter_obj
return {'FINISHED'}
@@ -368,8 +473,8 @@ class AddSlicer(bpy.types.Operator):
slice_node.inputs[1].default_value = slicer_obj
output_node = get_nodes_by_type(node_group,
'NodeGroupOutput')[0]
output_node = get_output_node(node_group)
if len(output_node.inputs[0].links) == 0:
node_group.links.new(slice_node.outputs[0],
output_node.inputs[0])
@@ -419,8 +524,8 @@ class AddLocator(bpy.types.Operator):
parent_node.inputs[1].default_value = locator_obj
output_node = get_nodes_by_type(node_group,
'NodeGroupOutput')[0]
output_node = get_output_node(node_group)
if len(output_node.inputs[0].links) == 0:
node_group.links.new(parent_node.outputs[0],
output_node.inputs[0])

View File

@@ -5,7 +5,7 @@ import shutil
from ..bioxelutils.common import get_all_layer_objs, get_node_lib_path, get_node_version, is_missing_layer, set_file_prop
from .layer import RemoveLayers, SaveLayersCache
from ..constants import NODE_LIB_DIRPATH, VERSIONS
from ..constants import LATEST_NODE_LIB_PATH, VERSIONS
from ..utils import get_cache_dir
@@ -19,7 +19,8 @@ class ReLinkNodeLib(bpy.types.Operator):
def execute(self, context):
node_version = VERSIONS[self.index]['node_version']
lib_path = get_node_lib_path(node_version)
lib_path = get_node_lib_path(node_version) \
if self.index != 0 else LATEST_NODE_LIB_PATH
node_libs = []
for node_group in bpy.data.node_groups:
@@ -56,16 +57,23 @@ class SaveNodeLib(bpy.types.Operator):
def execute(self, context):
node_version = get_node_version()
if node_version is None:
node_version = VERSIONS[0]["node_version"]
else:
if node_version not in [v["node_version"] for v in VERSIONS]:
node_version = VERSIONS[0]["node_version"]
if node_version == VERSIONS[0]["node_version"]:
lib_path = LATEST_NODE_LIB_PATH
else:
lib_path = get_node_lib_path(node_version)
version_str = "v"+".".join([str(i) for i in list(node_version)])
lib_dir = bpy.path.abspath(self.lib_dir)
local_lib_path: Path = Path(lib_dir, lib_path.name).resolve()
local_lib_path: Path = Path(lib_dir,
f"BioxelNodes_{version_str}.blend").resolve()
node_lib_path: Path = lib_path
blend_path = Path(bpy.path.abspath("//")).resolve()

View File

@@ -1,6 +1,6 @@
[tool.poetry]
name = "bioxelnodes"
version = "1.0.0"
version = "1.0.1"
description = ""
authors = ["Ma Nan <icrdr2010@outlook.com>"]
license = "MIT"