feat: support eevee
This commit is contained in:
12
README.md
12
README.md
@@ -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.
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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>"
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user