io_scene_3ds: Added pivot origin option and fixed camera and light ranges #104818
35
hydra_storm/__init__.py
Normal file
35
hydra_storm/__init__.py
Normal 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
44
hydra_storm/engine.py
Normal 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
63
hydra_storm/properties.py
Normal 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
243
hydra_storm/ui.py
Normal 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)
|
@ -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)
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user