feat: support eevee

This commit is contained in:
2024-06-12 15:23:09 +08:00
parent 322b84cc70
commit 134d8e382b
8 changed files with 88 additions and 51 deletions

View File

@@ -56,3 +56,15 @@ It is not support editing the same blender file across add-on versions. In order
But even then, there is still no guarantee that the new version of the add-on will work on the old blender file. Therefore, it is highly recommended to open a new blender file to start the creating, not based on the old one. But even then, there is still no guarantee that the new version of the add-on will work on the old blender file. Therefore, it is highly recommended to open a new blender file to start the creating, not based on the old one.
Alternatively, objects from the old file that have nothing to do with Bioxel Nodes could be append to the new blender file. Alternatively, objects from the old file that have nothing to do with Bioxel Nodes could be append to the new blender file.
## About EEVEE Render
Bioxel Nodes is designed for Cycles Render. However, it does support eevee render partially. "Solid Shader" node and "Volume Shader" node have a toggle called "EEVEE Render". If you want to render Bioxel Component in real-time, turn it on.
Also, there are some limitations:
1. Only one cutter supported.
2. You cannot use "Color Ramp" over 2 colors.
3. EEVEE Render result is not that great as Cycles does.
> "Volume Shader" node is not work properly in EEVEE Next since 4.2. It is because EEVEE Next is not support attributes from instances of volume shader by now. But the Blender 4.2 docs still say attributes reading is ok, so I suppose this feature will eventually be implemented.

View File

@@ -6,10 +6,11 @@ import numpy as np
from pathlib import Path from pathlib import Path
from uuid import uuid4 from uuid import uuid4
import mathutils import mathutils
import random
from .nodes import custom_nodes from .nodes import custom_nodes
from .props import BIOXELNODES_Series from .props import BIOXELNODES_Series
from .utils import (calc_bbox_verts, get_container, get_layer, get_text_index_str, from .utils import (calc_bbox_verts, get_all_layers, get_container, get_layer, get_text_index_str,
get_node_by_type, hide_in_ray, lock_transform, show_message) get_node_by_type, hide_in_ray, lock_transform, show_message)
try: try:
@@ -218,6 +219,7 @@ class ImportVolumeDataDialog(bpy.types.Operator):
) # type: ignore ) # type: ignore
def execute(self, context): def execute(self, context):
is_first_import = len(get_all_layers()) == 0
image, name = read_image(self.filepath, self.series_id) image, name = read_image(self.filepath, self.series_id)
container_name = self.container_name or name container_name = self.container_name or name
bioxel_size = self.bioxel_size bioxel_size = self.bioxel_size
@@ -258,7 +260,7 @@ class ImportVolumeDataDialog(bpy.types.Operator):
interpolator = sitk.sitkNearestNeighbor interpolator = sitk.sitkNearestNeighbor
elif self.resample_method == "gaussian": elif self.resample_method == "gaussian":
interpolator = sitk.sitkGaussian interpolator = sitk.sitkGaussian
if self.read_as == "labels": if self.read_as == "labels":
interpolator = sitk.sitkNearestNeighbor interpolator = sitk.sitkNearestNeighbor
@@ -451,11 +453,14 @@ class ImportVolumeDataDialog(bpy.types.Operator):
input_node = get_node_by_type(nodes, 'NodeGroupInput')[0] input_node = get_node_by_type(nodes, 'NodeGroupInput')[0]
output_node = get_node_by_type(nodes, 'NodeGroupOutput')[0] output_node = get_node_by_type(nodes, 'NodeGroupOutput')[0]
to_layer_node = custom_nodes.add_node(nodes, "BioxelNodes__ConvertToLayer") to_layer_node = custom_nodes.add_node(nodes,
"BioxelNodes__ConvertToLayer")
links.new(input_node.outputs[0], to_layer_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]) links.new(to_layer_node.outputs[0], output_node.inputs[0])
to_layer_node.inputs['Layer ID'].default_value = random.randint(-200000000,
200000000)
to_layer_node.inputs['Bioxel Size'].default_value = bioxel_size to_layer_node.inputs['Bioxel Size'].default_value = bioxel_size
to_layer_node.inputs['Shape'].default_value = layer_shape to_layer_node.inputs['Shape'].default_value = layer_shape
to_layer_node.inputs['Origin'].default_value = layer_origin to_layer_node.inputs['Origin'].default_value = layer_origin
@@ -531,7 +536,7 @@ class ImportVolumeDataDialog(bpy.types.Operator):
bpy.context.view_layer.objects.active = container bpy.context.view_layer.objects.active = container
# Change render setting for better result # Change render setting for better result
if preferences.do_change_render_setting: if preferences.do_change_render_setting and is_first_import:
bpy.context.scene.render.engine = 'CYCLES' bpy.context.scene.render.engine = 'CYCLES'
bpy.context.scene.cycles.volume_bounces = 12 bpy.context.scene.cycles.volume_bounces = 12
bpy.context.scene.cycles.transparent_max_bounces = 16 bpy.context.scene.cycles.transparent_max_bounces = 16

View File

@@ -1,4 +1,5 @@
from pathlib import Path from pathlib import Path
import random
import bpy import bpy
import pyopenvdb as vdb import pyopenvdb as vdb
from uuid import uuid4 from uuid import uuid4
@@ -107,45 +108,6 @@ class JoinLayers(bpy.types.Operator):
filepath=str(vdb_path), align='WORLD', location=(0, 0, 0), scale=(1, 1, 1)) filepath=str(vdb_path), align='WORLD', location=(0, 0, 0), scale=(1, 1, 1))
joined_layer = bpy.context.active_object joined_layer = bpy.context.active_object
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 # Set props to VDB object
joined_layer.name = f"{base_layer.name}_Joined" joined_layer.name = f"{base_layer.name}_Joined"
@@ -162,6 +124,52 @@ class JoinLayers(bpy.types.Operator):
joined_layer['bioxel_layer'] = True joined_layer['bioxel_layer'] = True
joined_layer.parent = base_layer.parent joined_layer.parent = base_layer.parent
for collection in layer.users_collection:
collection.objects.unlink(layer)
for collection in base_layer.users_collection:
collection.objects.link(layer)
# add convert to layer node
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['Layer ID'].default_value = random.randint(-200000000,
200000000)
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
return {'FINISHED'} return {'FINISHED'}
def invoke(self, context, event): def invoke(self, context, event):
@@ -206,8 +214,8 @@ class ConvertToMesh(bpy.types.Operator):
output_node = get_node_by_type(nodes, 'NodeGroupOutput')[0] output_node = get_node_by_type(nodes, 'NodeGroupOutput')[0]
object_node = nodes.new("GeometryNodeObjectInfo") object_node = nodes.new("GeometryNodeObjectInfo")
realize_nodes = nodes.new("GeometryNodeRealizeInstances") realize_nodes = nodes.new("GeometryNodeRealizeInstances")
separate_node = custom_nodes.add_node( separate_node = custom_nodes.add_node(nodes,
nodes, "BioxelNodes__SeparateComponent") "BioxelNodes__SeparateComponent")
object_node.inputs[0].default_value = container object_node.inputs[0].default_value = container
separate_node.inputs[1].default_value = 1 separate_node.inputs[1].default_value = 1

View File

@@ -54,3 +54,15 @@ It is not support editing the same blender file across add-on versions. In order
But even then, there is still no guarantee that the new version of the add-on will work on the old blender file. Therefore, it is highly recommended to open a new blender file to start the creating, not based on the old one. But even then, there is still no guarantee that the new version of the add-on will work on the old blender file. Therefore, it is highly recommended to open a new blender file to start the creating, not based on the old one.
Alternatively, objects from the old file that have nothing to do with Bioxel Nodes could be append to the new blender file. Alternatively, objects from the old file that have nothing to do with Bioxel Nodes could be append to the new blender file.
## About EEVEE Render
Bioxel Nodes is designed for Cycles Render. However, it does support eevee render partially. "Solid Shader" node and "Volume Shader" node have a toggle called "EEVEE Render". If you want to render Bioxel Component in real-time, turn it on.
Also, there are some limitations:
1. Only one cutter supported.
2. You cannot use "Color Ramp" over 2 colors.
3. EEVEE Render result is not that great as Cycles does.
> "Volume Shader" node is not work properly in EEVEE Next since 4.2. It is because EEVEE Next is not support attributes from instances of volume shader by now. But the Blender 4.2 docs still say attributes reading is ok, so I suppose this feature will eventually be implemented.

View File

@@ -3,7 +3,7 @@ schema_version = "1.0.0"
# Example of manifest file for a Blender extension # Example of manifest file for a Blender extension
# Change the values according to your extension # Change the values according to your extension
id = "bioxelnodes" id = "bioxelnodes"
version = "0.2.0" version = "0.2.2"
name = "Bioxel Nodes" name = "Bioxel Nodes"
tagline = "For scientific volumetric data visualization in Blender" tagline = "For scientific volumetric data visualization in Blender"
maintainer = "Ma Nan <icrdr2010@outlook.com>" maintainer = "Ma Nan <icrdr2010@outlook.com>"

View File

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