feat: boost render speed

This commit is contained in:
2024-08-16 13:56:14 +08:00
parent 9e885865f7
commit 051df670a5
8 changed files with 160 additions and 47 deletions

View File

@@ -9,7 +9,8 @@ from uuid import uuid4
from ..nodes import custom_nodes from ..nodes import custom_nodes
from ..bioxel.layer import Layer from ..bioxel.layer import Layer
from .utils import get_layer_prop_value, move_node_between_nodes from .utils import (get_layer_prop_value,
move_node_between_nodes, add_direct_driver)
def obj_to_layer(layer_obj: bpy.types.Object): def obj_to_layer(layer_obj: bpy.types.Object):
@@ -135,9 +136,14 @@ def layer_to_obj(layer: Layer,
cache_filepaths = [cache_filepath] cache_filepaths = [cache_filepath]
layer_data = bpy.data.volumes.new(layer_display_name) layer_data = bpy.data.volumes.new(layer_display_name)
layer_data.render.space = 'WORLD'
layer_data.render.step_size = container_obj.scale[0] * layer.bioxel_size[0]
layer_data.sequence_mode = 'REPEAT' layer_data.sequence_mode = 'REPEAT'
layer_data.filepath = str(cache_filepaths[0]) layer_data.filepath = str(cache_filepaths[0])
# add_direct_driver(layer_data, "render.step_size",
# container_obj, "scale[0]")
if layer.frame_count > 1: if layer.frame_count > 1:
layer_data.is_sequence = True layer_data.is_sequence = True
layer_data.frame_duration = layer.frame_count layer_data.frame_duration = layer.frame_count
@@ -145,7 +151,6 @@ def layer_to_obj(layer: Layer,
layer_data.is_sequence = False layer_data.is_sequence = False
layer_obj = bpy.data.objects.new(layer_display_name, layer_data) layer_obj = bpy.data.objects.new(layer_display_name, layer_data)
layer_obj['bioxel_layer'] = True layer_obj['bioxel_layer'] = True
print(f"Creating Node for {layer.name}...") print(f"Creating Node for {layer.name}...")

View File

@@ -94,3 +94,35 @@ def get_all_layer_objs():
layer_objs.append(obj) layer_objs.append(obj)
return layer_objs return layer_objs
def add_driver(target, target_prop, var_sources, expression):
driver = target.driver_add(target_prop)
is_vector = isinstance(driver, list)
drivers = driver if is_vector else [driver]
for i, driver in enumerate(drivers):
for j, var_source in enumerate(var_sources):
source = var_source['source']
prop = var_source['prop']
var = driver.driver.variables.new()
var.name = f"var{j}"
var.targets[0].id_type = source.id_type
var.targets[0].id = source
var.targets[0].data_path = f'["{prop}"][{i}]'\
if is_vector else f'["{prop}"]'
driver.driver.expression = expression
def add_direct_driver(target, target_prop, source, source_prop):
drivers = [
{
"source": source,
"prop": source_prop
}
]
expression = "var0"
add_driver(target, target_prop, drivers, expression)

View File

@@ -13,10 +13,10 @@ from .operators.layer import (FetchLayerMenu, FetchLayer,
from .operators.container import (SaveAllLayerCaches, SaveContainer, LoadContainer, from .operators.container import (SaveAllLayerCaches, SaveContainer, LoadContainer,
AddPieCutter, AddPlaneCutter, AddPieCutter, AddPlaneCutter,
AddCylinderCutter, AddCubeCutter, AddSphereCutter, AddCylinderCutter, AddCubeCutter, AddSphereCutter,
PickBboxWire, PickMesh, PickVolume) PickBboxWire, PickMesh, PickVolume, ScaleContainer)
from .operators.io import (ImportAsLabel, ImportAsScalar, ImportAsColor) from .operators.io import (ImportAsLabel, ImportAsScalar, ImportAsColor)
from .operators.misc import (CleanAllCaches, from .operators.misc import (CleanAllCaches,
ReLinkNodes, RenderSettingPreset, SaveStagedData) ReLinkNodes, RenderSettingPreset, SaveStagedData, SliceViewer)
class PickFromContainerMenu(bpy.types.Menu): class PickFromContainerMenu(bpy.types.Menu):
@@ -156,19 +156,19 @@ class BioxelNodesNodeMenu(bpy.types.Menu):
active_obj_name = "" active_obj_name = ""
layout = self.layout layout = self.layout
layout.separator()
layout.menu(AddLayerMenu.bl_idname, layout.menu(AddLayerMenu.bl_idname,
icon=AddLayerMenu.bl_icon) icon=AddLayerMenu.bl_icon)
layout.operator(RemoveMissingLayers.bl_idname,
icon=RemoveMissingLayers.bl_icon)
layout.separator() layout.separator()
layout.operator(SaveContainer.bl_idname) layout.operator(SaveContainer.bl_idname)
layout.separator()
layout.operator(ScaleContainer.bl_idname)
layout.menu(AddCutterMenu.bl_idname) layout.menu(AddCutterMenu.bl_idname)
layout.menu(PickFromContainerMenu.bl_idname) layout.menu(PickFromContainerMenu.bl_idname)
layout.operator(SaveAllLayerCaches.bl_idname, layout.operator(SaveAllLayerCaches.bl_idname,
icon=SaveAllLayerCaches.bl_icon) icon=SaveAllLayerCaches.bl_icon)
layout.operator(RemoveMissingLayers.bl_idname,
icon=RemoveMissingLayers.bl_icon)
layout.separator() layout.separator()
layout.menu(FetchLayerMenu.bl_idname) layout.menu(FetchLayerMenu.bl_idname)
@@ -247,6 +247,8 @@ def NODE_PT(self, context):
sidebar.menu(AddLayerMenu.bl_idname, sidebar.menu(AddLayerMenu.bl_idname,
icon=AddLayerMenu.bl_icon, text="") icon=AddLayerMenu.bl_icon, text="")
sidebar.operator(SaveAllLayerCaches.bl_idname,
icon=SaveAllLayerCaches.bl_icon, text="")
sidebar.operator(RemoveMissingLayers.bl_idname, sidebar.operator(RemoveMissingLayers.bl_idname,
icon=RemoveMissingLayers.bl_icon, text="") icon=RemoveMissingLayers.bl_icon, text="")
@@ -285,13 +287,21 @@ def NODE_PT(self, context):
layout.separator() layout.separator()
def VIEW3D_TOPBAR(self, context):
layout = self.layout
layout.operator(SliceViewer.bl_idname,
icon=SliceViewer.bl_icon, text="")
def add(): def add():
bpy.types.VIEW3D_HT_header.append(VIEW3D_TOPBAR)
bpy.types.NODE_PT_node_tree_properties.prepend(NODE_PT) bpy.types.NODE_PT_node_tree_properties.prepend(NODE_PT)
bpy.types.TOPBAR_MT_editor_menus.append(TOPBAR) bpy.types.TOPBAR_MT_editor_menus.append(TOPBAR)
bpy.types.NODE_MT_editor_menus.append(NODE) bpy.types.NODE_MT_editor_menus.append(NODE)
def remove(): def remove():
bpy.types.VIEW3D_HT_header.remove(VIEW3D_TOPBAR)
bpy.types.NODE_PT_node_tree_properties.remove(NODE_PT) bpy.types.NODE_PT_node_tree_properties.remove(NODE_PT)
bpy.types.TOPBAR_MT_editor_menus.remove(TOPBAR) bpy.types.TOPBAR_MT_editor_menus.remove(TOPBAR)
bpy.types.NODE_MT_editor_menus.remove(NODE) bpy.types.NODE_MT_editor_menus.remove(NODE)

View File

@@ -60,9 +60,9 @@ MENU_ITEMS = [
'node_description': '' 'node_description': ''
}, },
{ {
'label': 'Set Color by Layer', 'label': 'Set Color by Color',
'icon': 'IPO_QUINT', 'icon': 'IPO_QUINT',
'node_type': 'BioxelNodes_SetColorByLayer', 'node_type': 'BioxelNodes_SetColorByColor',
'node_description': '' 'node_description': ''
}, },
{ {

View File

@@ -6,7 +6,8 @@ from ..nodes import custom_nodes
from ..customnodes.nodes import AddCustomNode from ..customnodes.nodes import AddCustomNode
from ..bioxel.io import load_container, save_container from ..bioxel.io import load_container, save_container
from ..bioxelutils.container import container_to_obj, obj_to_container from ..bioxelutils.container import container_to_obj, obj_to_container
from ..bioxelutils.utils import (get_container_layer_objs, get_container_obj, get_nodes_by_type, from ..bioxelutils.utils import (get_container_layer_objs, get_container_obj,
get_layer_prop_value, get_nodes_by_type,
move_node_between_nodes, move_node_between_nodes,
move_node_to_node, move_node_to_node,
get_all_layer_objs) get_all_layer_objs)
@@ -66,7 +67,8 @@ class LoadContainer(bpy.types.Operator):
select_object(container_obj) select_object(container_obj)
if is_first_import: if is_first_import:
change_render_setting(context) bpy.ops.bioxelnodes.render_setting_preset('EXEC_DEFAULT',
preset="preview_c")
self.report({"INFO"}, f"Successfully load {load_path}") self.report({"INFO"}, f"Successfully load {load_path}")
return {'FINISHED'} return {'FINISHED'}
@@ -158,14 +160,24 @@ class AddCutter():
bpy.ops.mesh.primitive_ico_sphere_add( bpy.ops.mesh.primitive_ico_sphere_add(
radius=1, enter_editmode=False, align='WORLD', location=(0, 0, 0), scale=(1, 1, 1)) radius=1, enter_editmode=False, align='WORLD', location=(0, 0, 0), scale=(1, 1, 1))
elif self.cutter_type == "pie": elif self.cutter_type == "pie":
bpy.ops.mesh.primitive_plane_add(
size=2, enter_editmode=False, align='WORLD', location=(0, 0, 0), scale=(1, 1, 1))
pie = bpy.context.active_object
pie.name = "Pie"
orig_data = pie.data
# Create mesh # Create mesh
pie_mesh = bpy.data.meshes.new('Pie') pie_mesh = bpy.data.meshes.new('Pie')
# Create object pie.data = pie_mesh
pie = bpy.data.objects.new('Pie', pie_mesh) bpy.data.meshes.remove(orig_data)
# # Create object
# pie = bpy.data.objects.new('Pie', pie_mesh)
# # Link object to scene
# bpy.context.scene.collection.objects.link(pie)
# Link object to scene
bpy.context.scene.collection.objects.link(pie)
# Get a BMesh representation # Get a BMesh representation
bm = bmesh.new() # create an empty BMesh bm = bmesh.new() # create an empty BMesh
bm.from_mesh(pie_mesh) # fill it in from a Mesh bm.from_mesh(pie_mesh) # fill it in from a Mesh
@@ -189,7 +201,7 @@ class AddCutter():
# Finish up, write the bmesh back to the mesh # Finish up, write the bmesh back to the mesh
bm.to_mesh(pie_mesh) bm.to_mesh(pie_mesh)
bpy.context.view_layer.objects.active = pie # bpy.context.view_layer.objects.active = pie
cutter_obj = bpy.context.active_object cutter_obj = bpy.context.active_object
cutter_obj.location = container_obj.location cutter_obj.location = container_obj.location
@@ -325,6 +337,46 @@ class AddPieCutter(bpy.types.Operator, AddCutter):
cutter_type = "pie" cutter_type = "pie"
class ScaleContainer(bpy.types.Operator):
bl_idname = "bioxelnodes.scale_container"
bl_label = "Scale Container"
bl_description = "Scale Container."
bl_icon = "FILE_TICK"
scene_scale: bpy.props.FloatProperty(name="Scene Scale",
soft_min=0.0001, soft_max=10.0,
min=1e-6, max=1e6,
default=0.01) # type: ignore
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'}
container_obj.scale[0] = self.scene_scale
container_obj.scale[1] = self.scene_scale
container_obj.scale[2] = self.scene_scale
for layer_obj in get_container_layer_objs(container_obj):
bioxel_size = get_layer_prop_value(layer_obj, "bioxel_size")
layer_obj.data.render.step_size = self.scene_scale * bioxel_size
return {'FINISHED'}
def invoke(self, context, event):
container_obj = get_container_obj(context.object)
if container_obj is None:
return self.execute(context)
else:
self.scene_scale = container_obj.scale[0]
context.window_manager.invoke_props_dialog(self,
width=500)
return {'RUNNING_MODAL'}
class SaveAllLayerCaches(bpy.types.Operator): class SaveAllLayerCaches(bpy.types.Operator):
bl_idname = "bioxelnodes.save_all_layer_caches" bl_idname = "bioxelnodes.save_all_layer_caches"
bl_label = "Save All Layer Caches" bl_label = "Save All Layer Caches"

View File

@@ -782,9 +782,8 @@ class ImportVolumetricDataDialog(bpy.types.Operator):
# Change render setting for better result # Change render setting for better result
if is_first_import: if is_first_import:
bpy.ops.bioxelnodes.render_setting_preset('EXEC_DEFAULT', bpy.ops.bioxelnodes.render_setting_preset('EXEC_DEFAULT',
preset="slice_viewer") preset="preview_c")
bpy.ops.bioxelnodes.render_setting_preset('EXEC_DEFAULT', # bpy.ops.bioxelnodes.slice_viewer('EXEC_DEFAULT')
preset="cycles_preview")
self.report({"INFO"}, "Successfully Imported") self.report({"INFO"}, "Successfully Imported")
return {'FINISHED'} return {'FINISHED'}

View File

@@ -151,20 +151,19 @@ class RenderSettingPreset(bpy.types.Operator):
bl_description = "Render Setting Preset" bl_description = "Render Setting Preset"
PRESETS = { PRESETS = {
"slice_viewer": "Slice Viewer", "preview_e": "Preview (EEVEE)",
"eevee_preview": "EEVEE Preview", "preview_c": "Preview (Cycles)",
"eevee_production": "EEVEE Production", "production_e": "Production (EEVEE)",
"cycles_preview": "Cycles Preview", "production_c": "Production (Cycles)"
"cycles_production": "Cycles Production"
} }
preset: bpy.props.EnumProperty(name="Preset", preset: bpy.props.EnumProperty(name="Preset",
default="eevee_preview", default="preview_c",
items=[(k, v, "") items=[(k, v, "")
for k, v in PRESETS.items()]) # type: ignore for k, v in PRESETS.items()]) # type: ignore
def execute(self, context): def execute(self, context):
if self.preset == "eevee_preview": if self.preset == "preview_e":
bpy.context.scene.render.engine = 'BLENDER_EEVEE_NEXT' bpy.context.scene.render.engine = 'BLENDER_EEVEE_NEXT'
bpy.context.scene.eevee.use_taa_reprojection = False bpy.context.scene.eevee.use_taa_reprojection = False
bpy.context.scene.eevee.taa_samples = 16 bpy.context.scene.eevee.taa_samples = 16
@@ -174,7 +173,7 @@ class RenderSettingPreset(bpy.types.Operator):
bpy.context.scene.eevee.volumetric_ray_depth = 16 bpy.context.scene.eevee.volumetric_ray_depth = 16
bpy.context.scene.eevee.use_volumetric_shadows = True bpy.context.scene.eevee.use_volumetric_shadows = True
elif self.preset == "eevee_production": elif self.preset == "production_e":
bpy.context.scene.render.engine = 'BLENDER_EEVEE_NEXT' bpy.context.scene.render.engine = 'BLENDER_EEVEE_NEXT'
bpy.context.scene.eevee.use_taa_reprojection = False bpy.context.scene.eevee.use_taa_reprojection = False
bpy.context.scene.eevee.taa_samples = 16 bpy.context.scene.eevee.taa_samples = 16
@@ -184,30 +183,46 @@ class RenderSettingPreset(bpy.types.Operator):
bpy.context.scene.eevee.volumetric_ray_depth = 16 bpy.context.scene.eevee.volumetric_ray_depth = 16
bpy.context.scene.eevee.use_volumetric_shadows = True bpy.context.scene.eevee.use_volumetric_shadows = True
elif self.preset == "cycles_preview": elif self.preset == "preview_c":
bpy.context.scene.render.engine = 'CYCLES' bpy.context.scene.render.engine = 'CYCLES'
bpy.context.scene.cycles.shading_system = True bpy.context.scene.cycles.shading_system = True
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
bpy.context.scene.cycles.volume_preview_step_rate = 10 bpy.context.scene.cycles.volume_preview_step_rate = 1
bpy.context.scene.cycles.volume_step_rate = 10 bpy.context.scene.cycles.volume_step_rate = 1
elif self.preset == "cycles_production": elif self.preset == "production_c":
bpy.context.scene.render.engine = 'CYCLES' bpy.context.scene.render.engine = 'CYCLES'
bpy.context.scene.cycles.shading_system = True bpy.context.scene.cycles.shading_system = True
bpy.context.scene.cycles.volume_bounces = 16 bpy.context.scene.cycles.volume_bounces = 16
bpy.context.scene.cycles.transparent_max_bounces = 32 bpy.context.scene.cycles.transparent_max_bounces = 32
bpy.context.scene.cycles.volume_preview_step_rate = 1 bpy.context.scene.cycles.volume_preview_step_rate = 0.1
bpy.context.scene.cycles.volume_step_rate = 1 bpy.context.scene.cycles.volume_step_rate = 0.1
elif self.preset == "slice_viewer":
# bpy.context.scene.render.engine = 'BLENDER_EEVEE_NEXT'
bpy.context.scene.eevee.use_taa_reprojection = False
bpy.context.scene.eevee.taa_samples = 4
bpy.context.scene.eevee.volumetric_tile_size = '2'
bpy.context.scene.eevee.volumetric_shadow_samples = 128
bpy.context.scene.eevee.volumetric_samples = 128
bpy.context.scene.eevee.volumetric_ray_depth = 1
bpy.context.scene.eevee.use_volumetric_shadows = False
return {'FINISHED'} return {'FINISHED'}
class SliceViewer(bpy.types.Operator):
bl_idname = "bioxelnodes.slice_viewer"
bl_label = "Slice Viewer"
bl_description = "Slice Viewer"
bl_icon = "FILE_VOLUME"
def execute(self, context):
bpy.context.scene.eevee.use_taa_reprojection = False
bpy.context.scene.eevee.taa_samples = 4
bpy.context.scene.eevee.volumetric_tile_size = '2'
bpy.context.scene.eevee.volumetric_shadow_samples = 128
bpy.context.scene.eevee.volumetric_samples = 128
bpy.context.scene.eevee.volumetric_ray_depth = 1
bpy.context.scene.eevee.use_volumetric_shadows = False
for area in bpy.context.screen.areas:
if area.type == 'VIEW_3D':
area.spaces[0].shading.type = 'MATERIAL'
area.spaces[0].shading.studio_light = 'studio.exr'
area.spaces[0].shading.studiolight_intensity = 2.5
area.spaces[0].shading.use_scene_lights = False
area.spaces[0].shading.use_scene_world = False
return {'FINISHED'}