io_scene_3ds: Added pivot origin option and fixed camera and light ranges #104818

Merged
Sebastian Sille merged 75 commits from :main into main 2023-08-05 00:02:57 +02:00
6 changed files with 438 additions and 0 deletions
Showing only changes of commit 54158fab72 - Show all commits

35
hydra_storm/__init__.py Normal file
View File

@ -0,0 +1,35 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2011-2022 Blender Foundation
# <pep8 compliant>
bl_info = {
"name": "Hydra Storm render engine",
"author": "AMD",
"version": (1, 0, 0),
"blender": (4, 0, 0),
"description": "USD's high performance rasterizing renderer",
"tracker_url": "",
"doc_url": "",
"community": "",
"downloads": "",
"main_web": "",
"support": 'OFFICIAL',
"category": "Render"
}
from . import engine, properties, ui
def register():
engine.register()
properties.register()
ui.register()
def unregister():
ui.unregister()
properties.unregister()
engine.unregister()

44
hydra_storm/engine.py Normal file
View File

@ -0,0 +1,44 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2011-2022 Blender Foundation
# <pep8 compliant>
import bpy
class StormHydraRenderEngine(bpy.types.HydraRenderEngine):
bl_idname = 'HYDRA_STORM'
bl_label = "Hydra Storm"
bl_info = "USD's high performance rasterizing renderer"
bl_use_preview = True
bl_use_gpu_context = True
bl_delegate_id = 'HdStormRendererPlugin'
def get_render_settings(self, engine_type):
settings = bpy.context.scene.hydra_storm.viewport if engine_type == 'VIEWPORT' else \
bpy.context.scene.hydra_storm.final
result = {
'enableTinyPrimCulling': settings.enable_tiny_prim_culling,
'volumeRaymarchingStepSize': settings.volume_raymarching_step_size,
'volumeRaymarchingStepSizeLighting': settings.volume_raymarching_step_size_lighting,
'volumeMaxTextureMemoryPerField': settings.volume_max_texture_memory_per_field,
'maxLights': settings.max_lights,
}
if engine_type != 'VIEWPORT':
result |= {
'aovToken:Combined': "color",
'aovToken:Depth': "depth",
}
return result
def update_render_passes(self, scene, render_layer):
if render_layer.use_pass_z:
self.register_pass(scene, render_layer, 'Depth', 1, 'Z', 'VALUE')
register, unregister = bpy.utils.register_classes_factory((
StormHydraRenderEngine,
))

63
hydra_storm/properties.py Normal file
View File

@ -0,0 +1,63 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2011-2022 Blender Foundation
# <pep8 compliant>
import bpy
class Properties(bpy.types.PropertyGroup):
type = None
@classmethod
def register(cls):
cls.type.hydra_storm = bpy.props.PointerProperty(
name="Hydra Storm",
description="Hydra Storm properties",
type=cls,
)
@classmethod
def unregister(cls):
del cls.type.hydra_storm
class RenderProperties(bpy.types.PropertyGroup):
enable_tiny_prim_culling: bpy.props.BoolProperty(
name="Tiny Prim Culling",
description="Enable Tiny Prim Culling",
default=False,
)
volume_raymarching_step_size: bpy.props.FloatProperty(
name="Volume Raymarching Step Size",
description="Step size when raymarching volume",
default=1.0,
)
volume_raymarching_step_size_lighting: bpy.props.FloatProperty(
name="Volume Raymarching Step Size Lighting",
description="Step size when raymarching volume for lighting computation",
default=10.0,
)
volume_max_texture_memory_per_field: bpy.props.FloatProperty(
name="Max Texture Memory Per Field",
description="Maximum memory for a volume field texture in Mb (unless overridden by field prim)",
default=128.0,
)
max_lights: bpy.props.IntProperty(
name="Max Lights",
description="Limit maximum number of lights",
default=16, min=0, max=16,
)
class SceneProperties(Properties):
type = bpy.types.Scene
final: bpy.props.PointerProperty(type=RenderProperties)
viewport: bpy.props.PointerProperty(type=RenderProperties)
register, unregister = bpy.utils.register_classes_factory((
RenderProperties,
SceneProperties,
))

243
hydra_storm/ui.py Normal file
View File

@ -0,0 +1,243 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2011-2022 Blender Foundation
# <pep8 compliant>
import bpy
from .engine import StormHydraRenderEngine
class Panel(bpy.types.Panel):
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = 'render'
COMPAT_ENGINES = {StormHydraRenderEngine.bl_idname}
@classmethod
def poll(cls, context):
return context.engine in cls.COMPAT_ENGINES
#
# Final render settings
#
class STORM_HYDRA_RENDER_PT_final(Panel):
"""Final render delegate and settings"""
bl_idname = 'STORM_HYDRA_RENDER_PT_final'
bl_label = "Final Render Settings"
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
settings = context.scene.hydra_storm.final
layout.prop(settings, 'enable_tiny_prim_culling')
layout.prop(settings, 'max_lights')
class STORM_HYDRA_RENDER_PT_volume_final(bpy.types.Panel):
bl_parent_id = STORM_HYDRA_RENDER_PT_final.bl_idname
bl_label = "Volume Raymarching"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
settings = context.scene.hydra_storm.final
col = layout.column(align=True)
col.prop(settings, "volume_raymarching_step_size", text="Step Size")
col.prop(settings, "volume_raymarching_step_size_lighting", text="Step Size Lightning")
col.prop(settings, "volume_max_texture_memory_per_field")
#
# Viewport render settings
#
class STORM_HYDRA_RENDER_PT_viewport(Panel):
"""Viewport render delegate and settings"""
bl_idname = 'STORM_HYDRA_RENDER_PT_viewport'
bl_label = "Viewport Render Settings"
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
settings = context.scene.hydra_storm.viewport
layout.prop(settings, 'enable_tiny_prim_culling')
layout.prop(settings, 'max_lights')
class STORM_HYDRA_RENDER_PT_volume_viewport(bpy.types.Panel):
bl_parent_id = STORM_HYDRA_RENDER_PT_viewport.bl_idname
bl_label = "Volume Raymarching"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
settings = context.scene.hydra_storm.viewport
col = layout.column(align=True)
col.prop(settings, "volume_raymarching_step_size", text="Step Size")
col.prop(settings, "volume_raymarching_step_size_lighting", text="Step Size Lightning")
col.prop(settings, "volume_max_texture_memory_per_field")
class STORM_HYDRA_LIGHT_PT_light(Panel):
"""Physical light sources"""
bl_label = "Light"
bl_context = 'data'
@classmethod
def poll(cls, context):
return super().poll(context) and context.light
def draw(self, context):
layout = self.layout
light = context.light
layout.prop(light, "type", expand=True)
layout.use_property_split = True
layout.use_property_decorate = False
main_col = layout.column()
main_col.prop(light, "color")
main_col.prop(light, "energy")
main_col.separator()
if light.type == 'POINT':
row = main_col.row(align=True)
row.prop(light, "shadow_soft_size", text="Radius")
elif light.type == 'SPOT':
col = main_col.column(align=True)
col.prop(light, 'spot_size', slider=True)
col.prop(light, 'spot_blend', slider=True)
main_col.prop(light, 'show_cone')
elif light.type == 'SUN':
main_col.prop(light, "angle")
elif light.type == 'AREA':
main_col.prop(light, "shape", text="Shape")
sub = main_col.column(align=True)
if light.shape in {'SQUARE', 'DISK'}:
sub.prop(light, "size")
elif light.shape in {'RECTANGLE', 'ELLIPSE'}:
sub.prop(light, "size", text="Size X")
sub.prop(light, "size_y", text="Y")
else:
main_col.prop(light, 'size')
class STORM_HYDRA_RENDER_PT_film(Panel):
bl_label = "Film"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
layout.prop(context.scene.render, "film_transparent", text="Transparent Background")
class STORM_HYDRA_RENDER_PT_passes(Panel):
bl_label = "Passes"
bl_context = "view_layer"
def draw(self, context):
pass
class STORM_HYDRA_RENDER_PT_passes_data(Panel):
bl_label = "Data"
bl_context = "view_layer"
bl_parent_id = "STORM_HYDRA_RENDER_PT_passes"
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
view_layer = context.view_layer
col = layout.column(heading="Include", align=True)
col.prop(view_layer, "use_pass_z")
register_classes, unregister_classes = bpy.utils.register_classes_factory((
STORM_HYDRA_RENDER_PT_final,
STORM_HYDRA_RENDER_PT_volume_final,
STORM_HYDRA_RENDER_PT_viewport,
STORM_HYDRA_RENDER_PT_volume_viewport,
STORM_HYDRA_RENDER_PT_film,
STORM_HYDRA_LIGHT_PT_light,
STORM_HYDRA_RENDER_PT_passes,
STORM_HYDRA_RENDER_PT_passes_data,
))
def get_panels():
# Follow the Cycles model of excluding panels we don't want.
exclude_panels = {
'RENDER_PT_stamp',
'DATA_PT_light',
'DATA_PT_spot',
'NODE_DATA_PT_light',
'DATA_PT_falloff_curve',
'RENDER_PT_post_processing',
'RENDER_PT_simplify',
'SCENE_PT_audio',
'RENDER_PT_freestyle'
}
include_eevee_panels = {
'MATERIAL_PT_preview',
'EEVEE_MATERIAL_PT_context_material',
'EEVEE_MATERIAL_PT_surface',
'EEVEE_MATERIAL_PT_volume',
'EEVEE_MATERIAL_PT_settings',
'EEVEE_WORLD_PT_surface',
}
for panel_cls in bpy.types.Panel.__subclasses__():
if hasattr(panel_cls, 'COMPAT_ENGINES') and (
('BLENDER_RENDER' in panel_cls.COMPAT_ENGINES and panel_cls.__name__ not in exclude_panels) or
('BLENDER_EEVEE' in panel_cls.COMPAT_ENGINES and panel_cls.__name__ in include_eevee_panels)
):
yield panel_cls
def register():
register_classes()
for panel_cls in get_panels():
panel_cls.COMPAT_ENGINES.add(StormHydraRenderEngine.bl_idname)
def unregister():
unregister_classes()
for panel_cls in get_panels():
if StormHydraRenderEngine.bl_idname in panel_cls.COMPAT_ENGINES:
panel_cls.COMPAT_ENGINES.remove(StormHydraRenderEngine.bl_idname)

View File

@ -12,6 +12,7 @@ from bpy.types import (
Context,
Menu,
Panel,
UILayout,
UIList,
WindowManager,
WorkSpace,
@ -29,12 +30,54 @@ class PoseLibraryPanel:
return cls.pose_library_panel_poll(context)
class VIEW3D_AST_pose_library(bpy.types.AssetShelf):
bl_space_type = "VIEW_3D"
# We have own keymap items to add custom drag behavior (pose blending), disable the default
# asset dragging.
bl_options = {'NO_ASSET_DRAG'}
@classmethod
def poll(cls, context: Context) -> bool:
return PoseLibraryPanel.poll(context)
@classmethod
def asset_poll(cls, asset: AssetHandle) -> bool:
return asset.file_data.id_type == 'ACTION'
@classmethod
def draw_context_menu(cls, _context: Context, _asset: AssetHandle, layout: UILayout):
# Make sure these operator properties match those used in `VIEW3D_PT_pose_library`.
layout.operator("poselib.apply_pose_asset", text="Apply Pose").flipped = False
layout.operator("poselib.apply_pose_asset", text="Apply Pose Flipped").flipped = True
with operator_context(layout, 'INVOKE_DEFAULT'):
layout.operator("poselib.blend_pose_asset", text="Blend Pose")
layout.separator()
props = layout.operator("poselib.pose_asset_select_bones", text="Select Pose Bones")
props.select = True
props = layout.operator("poselib.pose_asset_select_bones", text="Deselect Pose Bones")
props.select = False
layout.separator()
layout.operator("asset.open_containing_blend_file")
class VIEW3D_PT_pose_library(PoseLibraryPanel, Panel):
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_category = "Animation"
bl_label = "Pose Library"
@classmethod
def poll(cls, context: Context) -> bool:
prefs = context.preferences
# Use Asset Shelf as UI instead of the old asset-view template in the sidebar.
if prefs.experimental.use_asset_shelf:
return False
return PoseLibraryPanel.poll(context)
def draw(self, context: Context) -> None:
layout = self.layout
@ -194,6 +237,7 @@ classes = (
DOPESHEET_PT_asset_panel,
VIEW3D_PT_pose_library,
ASSETBROWSER_MT_asset,
VIEW3D_AST_pose_library,
)
_register, _unregister = bpy.utils.register_classes_factory(classes)

View File

@ -21,6 +21,15 @@ def register() -> None:
kmi = km.keymap_items.new("poselib.apply_pose_asset", "LEFTMOUSE", "DOUBLE_CLICK")
addon_keymaps.append((km, kmi))
# Asset Shelf
km = wm.keyconfigs.addon.keymaps.new(name="Asset Shelf")
# Click to apply pose.
kmi = km.keymap_items.new("poselib.apply_pose_asset", "LEFTMOUSE", "CLICK")
addon_keymaps.append((km, kmi))
# Drag to blend pose.
kmi = km.keymap_items.new("poselib.blend_pose_asset", "LEFTMOUSE", "CLICK_DRAG")
addon_keymaps.append((km, kmi))
def unregister() -> None:
# Clear shortcuts from the keymap.