From b0a1cf2c9ae696b07f7a236bc855a5ab4a493dcb Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Tue, 17 Mar 2020 14:41:48 +0100 Subject: Objects: add Volume object type, and prototypes for Hair and PointCloud Only the volume object is exposed in the user interface. It is based on OpenVDB internally. Drawing and rendering code will follow in another commit. https://wiki.blender.org/wiki/Source/Objects/Volume https://wiki.blender.org/wiki/Reference/Release_Notes/2.83/Volumes Hair and PointCloud object types are hidden behind a WITH_NEW_OBJECT_TYPES build option. These are unfinished, and included only to make it easier to cooperate on development in the future and avoid tricky merges. https://wiki.blender.org/wiki/Source/Objects/New_Object_Types Ref T73201, T68981 Differential Revision: https://developer.blender.org/D6945 --- release/scripts/startup/bl_ui/__init__.py | 3 + .../scripts/startup/bl_ui/properties_data_hair.py | 78 ++++++++++ .../startup/bl_ui/properties_data_pointcloud.py | 78 ++++++++++ .../startup/bl_ui/properties_data_volume.py | 173 +++++++++++++++++++++ release/scripts/startup/bl_ui/properties_object.py | 2 +- release/scripts/startup/bl_ui/space_dopesheet.py | 6 + release/scripts/startup/bl_ui/space_filebrowser.py | 3 + release/scripts/startup/bl_ui/space_node.py | 3 +- release/scripts/startup/bl_ui/space_outliner.py | 3 + release/scripts/startup/bl_ui/space_userpref.py | 9 +- release/scripts/startup/bl_ui/space_view3d.py | 24 +++ 11 files changed, 378 insertions(+), 4 deletions(-) create mode 100644 release/scripts/startup/bl_ui/properties_data_hair.py create mode 100644 release/scripts/startup/bl_ui/properties_data_pointcloud.py create mode 100644 release/scripts/startup/bl_ui/properties_data_volume.py (limited to 'release/scripts/startup') diff --git a/release/scripts/startup/bl_ui/__init__.py b/release/scripts/startup/bl_ui/__init__.py index c2bcb7d5ea5..7d3ecceca41 100644 --- a/release/scripts/startup/bl_ui/__init__.py +++ b/release/scripts/startup/bl_ui/__init__.py @@ -35,14 +35,17 @@ _modules = [ "properties_data_curve", "properties_data_empty", "properties_data_gpencil", + "properties_data_hair", "properties_data_light", "properties_data_lattice", "properties_data_mesh", "properties_data_metaball", "properties_data_modifier", + "properties_data_pointcloud", "properties_data_shaderfx", "properties_data_lightprobe", "properties_data_speaker", + "properties_data_volume", "properties_mask_common", "properties_material", "properties_material_gpencil", diff --git a/release/scripts/startup/bl_ui/properties_data_hair.py b/release/scripts/startup/bl_ui/properties_data_hair.py new file mode 100644 index 00000000000..6017765b83d --- /dev/null +++ b/release/scripts/startup/bl_ui/properties_data_hair.py @@ -0,0 +1,78 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +# +import bpy +from bpy.types import Panel, UIList +from rna_prop_ui import PropertyPanel + + +class DataButtonsPanel: + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "data" + + @classmethod + def poll(cls, context): + engine = context.scene.render.engine + return hasattr(context, 'hair') and context.hair and (engine in cls.COMPAT_ENGINES) + + +class DATA_PT_context_hair(DataButtonsPanel, Panel): + bl_label = "" + bl_options = {'HIDE_HEADER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} + + def draw(self, context): + layout = self.layout + + ob = context.object + hair = context.hair + space = context.space_data + + if ob: + layout.template_ID(ob, "data") + elif hair: + layout.template_ID(space, "pin_id") + + +class DATA_PT_hair(DataButtonsPanel, Panel): + bl_label = "Hair" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} + + def draw(self, context): + layout = self.layout + hair = context.hair + pass + +class DATA_PT_custom_props_hair(DataButtonsPanel, PropertyPanel, Panel): + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} + _context_path = "object.data" + _property_type = bpy.types.Hair if hasattr(bpy.types, "Hair") else None + + +classes = ( + DATA_PT_context_hair, + DATA_PT_hair, + DATA_PT_custom_props_hair, +) + +if __name__ == "__main__": # only for live edit. + from bpy.utils import register_class + for cls in classes: + register_class(cls) diff --git a/release/scripts/startup/bl_ui/properties_data_pointcloud.py b/release/scripts/startup/bl_ui/properties_data_pointcloud.py new file mode 100644 index 00000000000..10ebdea3155 --- /dev/null +++ b/release/scripts/startup/bl_ui/properties_data_pointcloud.py @@ -0,0 +1,78 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +# +import bpy +from bpy.types import Panel, UIList +from rna_prop_ui import PropertyPanel + + +class DataButtonsPanel: + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "data" + + @classmethod + def poll(cls, context): + engine = context.scene.render.engine + return hasattr(context, 'pointcloud') and context.pointcloud and (engine in cls.COMPAT_ENGINES) + + +class DATA_PT_context_pointcloud(DataButtonsPanel, Panel): + bl_label = "" + bl_options = {'HIDE_HEADER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} + + def draw(self, context): + layout = self.layout + + ob = context.object + pointcloud = context.pointcloud + space = context.space_data + + if ob: + layout.template_ID(ob, "data") + elif pointcloud: + layout.template_ID(space, "pin_id") + + +class DATA_PT_pointcloud(DataButtonsPanel, Panel): + bl_label = "Point Cloud" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} + + def draw(self, context): + layout = self.layout + pointcloud = context.pointcloud + pass + +class DATA_PT_custom_props_pointcloud(DataButtonsPanel, PropertyPanel, Panel): + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} + _context_path = "object.data" + _property_type = bpy.types.PointCloud if hasattr(bpy.types, "PointCloud") else None + + +classes = ( + DATA_PT_context_pointcloud, + DATA_PT_pointcloud, + DATA_PT_custom_props_pointcloud, +) + +if __name__ == "__main__": # only for live edit. + from bpy.utils import register_class + for cls in classes: + register_class(cls) diff --git a/release/scripts/startup/bl_ui/properties_data_volume.py b/release/scripts/startup/bl_ui/properties_data_volume.py new file mode 100644 index 00000000000..29e28aa2c02 --- /dev/null +++ b/release/scripts/startup/bl_ui/properties_data_volume.py @@ -0,0 +1,173 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +# +import bpy +from bpy.types import Panel, UIList +from rna_prop_ui import PropertyPanel + + +class DataButtonsPanel: + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "data" + + @classmethod + def poll(cls, context): + engine = context.scene.render.engine + return context.volume and (engine in cls.COMPAT_ENGINES) + + +class DATA_PT_context_volume(DataButtonsPanel, Panel): + bl_label = "" + bl_options = {'HIDE_HEADER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} + + def draw(self, context): + layout = self.layout + + ob = context.object + volume = context.volume + space = context.space_data + + if ob: + layout.template_ID(ob, "data") + elif volume: + layout.template_ID(space, "pin_id") + + +class DATA_PT_volume_file(DataButtonsPanel, Panel): + bl_label = "OpenVDB File" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} + + def draw(self, context): + layout = self.layout + + volume = context.volume + volume.grids.load() + + layout.prop(volume, "filepath", text="") + + if len(volume.filepath): + layout.use_property_split = True + layout.use_property_decorate = False + + col = layout.column(align=True) + col.prop(volume, "is_sequence") + if volume.is_sequence: + col.prop(volume, "frame_duration", text="Frames") + col.prop(volume, "frame_start", text="Start") + col.prop(volume, "frame_offset", text="Offset") + col.prop(volume, "sequence_mode", text="Mode") + + error_msg = volume.grids.error_message + if len(error_msg): + layout.separator() + col = layout.column(align=True) + col.label(text="Failed to load volume:") + col.label(text=error_msg) + + +class VOLUME_UL_grids(UIList): + def draw_item(self, context, layout, data, grid, icon, active_data, active_propname, index): + name = grid.name + data_type = grid.bl_rna.properties['data_type'].enum_items[grid.data_type] + + layout.label(text=name) + row = layout.row() + row.alignment = 'RIGHT' + row.active = False + row.label(text=data_type.name) + + +class DATA_PT_volume_grids(DataButtonsPanel, Panel): + bl_label = "Grids" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} + + def draw(self, context): + layout = self.layout + + volume = context.volume + volume.grids.load() + + layout.template_list("VOLUME_UL_grids", "grids", volume, "grids", volume.grids, "active_index", rows=3) + + +class DATA_PT_volume_render(DataButtonsPanel, Panel): + bl_label = "Render" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + scene = context.scene + volume = context.volume + render = volume.render + + col = layout.column(align=True) + col.prop(render, "space") + col.prop(render, "step_size") + + if scene.render.engine == 'CYCLES': + col = layout.column(align=True) + col.prop(render, "clipping") + + +class DATA_PT_volume_viewport_display(DataButtonsPanel, Panel): + bl_label = "Viewport Display" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + volume = context.volume + display = volume.display + + col = layout.column(align=True) + col.prop(display, "wireframe_type") + sub = col.row() + sub.active = display.wireframe_type in {'BOXES', 'POINTS'} + sub.prop(display, "wireframe_detail", text="Detail") + + layout.prop(display, "density") + + +class DATA_PT_custom_props_volume(DataButtonsPanel, PropertyPanel, Panel): + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'} + _context_path = "object.data" + _property_type = bpy.types.Volume + + +classes = ( + DATA_PT_context_volume, + DATA_PT_volume_grids, + DATA_PT_volume_file, + DATA_PT_volume_viewport_display, + DATA_PT_volume_render, + DATA_PT_custom_props_volume, + VOLUME_UL_grids, +) + +if __name__ == "__main__": # only for live edit. + from bpy.utils import register_class + for cls in classes: + register_class(cls) diff --git a/release/scripts/startup/bl_ui/properties_object.py b/release/scripts/startup/bl_ui/properties_object.py index 33ba981e235..91bd055741c 100644 --- a/release/scripts/startup/bl_ui/properties_object.py +++ b/release/scripts/startup/bl_ui/properties_object.py @@ -216,7 +216,7 @@ class OBJECT_PT_display(ObjectButtonsPanel, Panel): obj = context.object obj_type = obj.type - is_geometry = (obj_type in {'MESH', 'CURVE', 'SURFACE', 'META', 'FONT'}) + is_geometry = (obj_type in {'MESH', 'CURVE', 'SURFACE', 'META', 'FONT', 'VOLUME', 'HAIR', 'POINTCLOUD'}) is_wire = (obj_type in {'CAMERA', 'EMPTY'}) is_empty_image = (obj_type == 'EMPTY' and obj.empty_display_type == 'IMAGE') is_dupli = (obj.instance_type != 'NONE') diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py index 76ba4dfb78e..3f8c41e4f21 100644 --- a/release/scripts/startup/bl_ui/space_dopesheet.py +++ b/release/scripts/startup/bl_ui/space_dopesheet.py @@ -126,6 +126,12 @@ class DopesheetFilterPopoverBase: flow.prop(dopesheet, "show_lattices", text="Lattices") if bpy.data.metaballs: flow.prop(dopesheet, "show_metaballs", text="Metaballs") + if hasattr(bpy.data, "hairs") and bpy.data.hairs: + flow.prop(dopesheet, "show_hairs", text="Hairs") + if hasattr(bpy.data, "pointclouds") and bpy.data.pointclouds: + flow.prop(dopesheet, "show_pointclouds", text="Point Clouds") + if bpy.data.volumes: + flow.prop(dopesheet, "show_volumes", text="Volumes") # data types flow.prop(dopesheet, "show_worlds", text="Worlds") diff --git a/release/scripts/startup/bl_ui/space_filebrowser.py b/release/scripts/startup/bl_ui/space_filebrowser.py index 95046678b27..3bf5bbf7b46 100644 --- a/release/scripts/startup/bl_ui/space_filebrowser.py +++ b/release/scripts/startup/bl_ui/space_filebrowser.py @@ -137,6 +137,9 @@ class FILEBROWSER_PT_filter(Panel): row = col.row() row.label(icon='FILE_TEXT') row.prop(params, "use_filter_text", text="Text Files", toggle=0) + row = col.row() + row.label(icon='FILE_VOLUME') + row.prop(params, "use_filter_volume", text="Volume Files", toggle=0) col.separator() diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py index 8fe758b8bf6..bdda0ebbe9a 100644 --- a/release/scripts/startup/bl_ui/space_node.py +++ b/release/scripts/startup/bl_ui/space_node.py @@ -76,7 +76,8 @@ class NODE_HT_header(Header): layout.separator_spacer() - types_that_support_material = {'MESH', 'CURVE', 'SURFACE', 'FONT', 'META', 'GPENCIL'} + types_that_support_material = {'MESH', 'CURVE', 'SURFACE', 'FONT', 'META', + 'GPENCIL', 'VOLUME', 'HAIR', 'POINTCLOUD'} # disable material slot buttons when pinned, cannot find correct slot within id_from (#36589) # disable also when the selected object does not support materials has_material_slots = not snode.pin and ob_type in types_that_support_material diff --git a/release/scripts/startup/bl_ui/space_outliner.py b/release/scripts/startup/bl_ui/space_outliner.py index 6ac31aeb3d0..cc773300d9e 100644 --- a/release/scripts/startup/bl_ui/space_outliner.py +++ b/release/scripts/startup/bl_ui/space_outliner.py @@ -397,6 +397,9 @@ class OUTLINER_PT_filter(Panel): if ( bpy.data.curves or bpy.data.metaballs or + (hasattr(bpy.data, "hairs") and bpy.data.hairs) or + (hasattr(bpy.data, "pointclouds") and bpy.data.pointclouds) or + bpy.data.volumes or bpy.data.lightprobes or bpy.data.lattices or bpy.data.fonts or diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index 2ca0e73bd74..4cccf429179 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -390,18 +390,23 @@ class USERPREF_PT_edit_objects_duplicate_data(EditingPanel, CenterAlignMixIn, Pa col.prop(edit, "use_duplicate_armature", text="Armature") col.prop(edit, "use_duplicate_curve", text="Curve") # col.prop(edit, "use_duplicate_fcurve", text="F-Curve") # Not implemented. + col.prop(edit, "use_duplicate_grease_pencil", text="Grease Pencil") + if hasattr(edit, "use_duplicate_hair"): + col.prop(edit, "use_duplicate_hair", text="Hair") col.prop(edit, "use_duplicate_light", text="Light") - col.prop(edit, "use_duplicate_lightprobe", text="Light Probe") col = flow.column() + col.prop(edit, "use_duplicate_lightprobe", text="Light Probe") col.prop(edit, "use_duplicate_material", text="Material") col.prop(edit, "use_duplicate_mesh", text="Mesh") col.prop(edit, "use_duplicate_metaball", text="Metaball") col.prop(edit, "use_duplicate_particle", text="Particle") col = flow.column() + if hasattr(edit, "use_duplicate_pointcloud"): + col.prop(edit, "use_duplicate_pointcloud", text="Point Cloud") col.prop(edit, "use_duplicate_surface", text="Surface") col.prop(edit, "use_duplicate_text", text="Text") # col.prop(edit, "use_duplicate_texture", text="Texture") # Not implemented. - col.prop(edit, "use_duplicate_grease_pencil", text="Grease Pencil") + col.prop(edit, "use_duplicate_volume", text="Volume") class USERPREF_PT_edit_cursor(EditingPanel, CenterAlignMixIn, Panel): diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index f8b291c0c5f..a2bfd711c04 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -2157,6 +2157,16 @@ class VIEW3D_MT_camera_add(Menu): layout.operator("object.camera_add", text="Camera", icon='OUTLINER_OB_CAMERA') +class VIEW3D_MT_volume_add(Menu): + bl_idname = "VIEW3D_MT_volume_add" + bl_label = "Volume" + + def draw(self, _context): + layout = self.layout + layout.operator("object.volume_import", text="Import OpenVDB...", icon='OUTLINER_DATA_VOLUME') + layout.operator("object.volume_add", text="Empty", icon='OUTLINER_DATA_VOLUME') + + class VIEW3D_MT_add(Menu): bl_label = "Add" bl_translation_context = i18n_contexts.operator_default @@ -2179,6 +2189,11 @@ class VIEW3D_MT_add(Menu): layout.menu("VIEW3D_MT_surface_add", icon='OUTLINER_OB_SURFACE') layout.menu("VIEW3D_MT_metaball_add", text="Metaball", icon='OUTLINER_OB_META') layout.operator("object.text_add", text="Text", icon='OUTLINER_OB_FONT') + if hasattr(bpy.data, "hairs"): + layout.operator("object.hair_add", text="Hair", icon='OUTLINER_OB_HAIR') + if hasattr(bpy.data, "pointclouds"): + layout.operator("object.pointcloud_add", text="Point Cloud", icon='OUTLINER_OB_POINTCLOUD') + layout.menu("VIEW3D_MT_volume_add", text="Volume", icon='OUTLINER_OB_VOLUME') layout.operator_menu_enum("object.gpencil_add", "type", text="Grease Pencil", icon='OUTLINER_OB_GREASEPENCIL') layout.separator() @@ -5428,6 +5443,9 @@ class VIEW3D_PT_object_type_visibility(Panel): ("surf", "Surface"), ("meta", "Meta"), ("font", "Text"), + ("hair", "Hair"), + ("pointcloud", "Point Cloud"), + ("volume", "Volume"), ("grease_pencil", "Grease Pencil"), (None, None), # Other @@ -5445,6 +5463,11 @@ class VIEW3D_PT_object_type_visibility(Panel): col.separator() continue + if attr == "hair" and not hasattr(bpy.data, "hairs"): + continue + elif attr == "pointcloud" and not hasattr(bpy.data, "pointclouds"): + continue + attr_v = "show_object_viewport_" f"{attr:s}" attr_s = "show_object_select_" f"{attr:s}" @@ -7254,6 +7277,7 @@ classes = ( VIEW3D_MT_light_add, VIEW3D_MT_lightprobe_add, VIEW3D_MT_camera_add, + VIEW3D_MT_volume_add, VIEW3D_MT_add, VIEW3D_MT_image_add, VIEW3D_MT_object, -- cgit v1.2.3