Files
blender/release/scripts/startup/bl_ui/properties_object.py
Brecht Van Lommel b0a1cf2c9a 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
2020-03-18 11:23:05 +01:00

449 lines
14 KiB
Python

# ##### 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 #####
# <pep8 compliant>
from bl_ui.properties_animviz import (
MotionPathButtonsPanel,
MotionPathButtonsPanel_display,
)
import bpy
from bpy.types import Panel, Menu
from rna_prop_ui import PropertyPanel
class ObjectButtonsPanel:
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "object"
class OBJECT_PT_context_object(ObjectButtonsPanel, Panel):
bl_label = ""
bl_options = {'HIDE_HEADER'}
def draw(self, context):
layout = self.layout
space = context.space_data
if space.use_pin_id:
layout.template_ID(space, "pin_id")
else:
row = layout.row()
row.template_ID(context.view_layer.objects, "active", filter='AVAILABLE')
class OBJECT_PT_transform(ObjectButtonsPanel, Panel):
bl_label = "Transform"
def draw(self, context):
layout = self.layout
layout.use_property_split = True
ob = context.object
col = layout.column()
row = col.row(align=True)
row.prop(ob, "location")
row.use_property_decorate = False
row.prop(ob, "lock_location", text="", emboss=False, icon='DECORATE_UNLOCKED')
rotation_mode = ob.rotation_mode
if rotation_mode == 'QUATERNION':
col = layout.column()
row = col.row(align=True)
row.prop(ob, "rotation_quaternion", text="Rotation")
sub = row.column(align=True)
sub.use_property_decorate = False
sub.prop(ob, "lock_rotation_w", text="", emboss=False, icon='DECORATE_UNLOCKED')
sub.prop(ob, "lock_rotation", text="", emboss=False, icon='DECORATE_UNLOCKED')
elif rotation_mode == 'AXIS_ANGLE':
col = layout.column()
row = col.row(align=True)
row.prop(ob, "rotation_axis_angle", text="Rotation")
sub = row.column(align=True)
sub.use_property_decorate = False
sub.prop(ob, "lock_rotation_w", text="", emboss=False, icon='DECORATE_UNLOCKED')
sub.prop(ob, "lock_rotation", text="", emboss=False, icon='DECORATE_UNLOCKED')
else:
col = layout.column()
row = col.row(align=True)
row.prop(ob, "rotation_euler", text="Rotation")
row.use_property_decorate = False
row.prop(ob, "lock_rotation", text="", emboss=False, icon='DECORATE_UNLOCKED')
row = layout.row(align=True)
row.prop(ob, "rotation_mode", text="Mode")
row.label(text="", icon='BLANK1')
col = layout.column()
row = col.row(align=True)
row.prop(ob, "scale")
row.use_property_decorate = False
row.prop(ob, "lock_scale", text="", emboss=False, icon='DECORATE_UNLOCKED')
class OBJECT_PT_delta_transform(ObjectButtonsPanel, Panel):
bl_label = "Delta Transform"
bl_parent_id = "OBJECT_PT_transform"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
layout.use_property_split = True
ob = context.object
col = layout.column()
col.prop(ob, "delta_location", text="Location")
rotation_mode = ob.rotation_mode
if rotation_mode == 'QUATERNION':
col.prop(ob, "delta_rotation_quaternion", text="Rotation")
elif rotation_mode == 'AXIS_ANGLE':
pass
else:
col.prop(ob, "delta_rotation_euler", text="Rotation")
col.prop(ob, "delta_scale", text="Scale")
class OBJECT_PT_relations(ObjectButtonsPanel, Panel):
bl_label = "Relations"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
layout.use_property_split = True
flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
ob = context.object
col = flow.column()
col.prop(ob, "parent")
sub = col.column()
sub.prop(ob, "parent_type")
parent = ob.parent
if parent and ob.parent_type == 'BONE' and parent.type == 'ARMATURE':
sub.prop_search(ob, "parent_bone", parent.data, "bones")
sub.active = (parent is not None)
col.separator()
col = flow.column()
col.prop(ob, "track_axis", text="Tracking Axis")
col.prop(ob, "up_axis", text="Up Axis")
col.separator()
col = flow.column()
col.prop(ob, "pass_index")
class COLLECTION_MT_context_menu(Menu):
bl_label = "Collection Specials"
def draw(self, _context):
layout = self.layout
layout.operator("object.collection_unlink", icon='X')
layout.operator("object.collection_objects_select")
layout.operator("object.instance_offset_from_cursor")
class OBJECT_PT_collections(ObjectButtonsPanel, Panel):
bl_label = "Collections"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
obj = context.object
row = layout.row(align=True)
if bpy.data.collections:
row.operator("object.collection_link", text="Add to Collection")
else:
row.operator("object.collection_add", text="Add to Collection")
row.operator("object.collection_add", text="", icon='ADD')
obj_name = obj.name
for collection in bpy.data.collections:
# XXX this is slow and stupid!, we need 2 checks, one that's fast
# and another that we can be sure its not a name collision
# from linked library data
collection_objects = collection.objects
if obj_name in collection.objects and obj in collection_objects[:]:
col = layout.column(align=True)
col.context_pointer_set("collection", collection)
row = col.box().row()
row.prop(collection, "name", text="")
row.operator("object.collection_remove", text="", icon='X', emboss=False)
row.menu("COLLECTION_MT_context_menu", icon='DOWNARROW_HLT', text="")
row = col.box().row()
row.prop(collection, "instance_offset", text="")
class OBJECT_PT_display(ObjectButtonsPanel, Panel):
bl_label = "Viewport Display"
bl_options = {'DEFAULT_CLOSED'}
bl_order = 10
def draw(self, context):
layout = self.layout
layout.use_property_split = True
flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
obj = context.object
obj_type = obj.type
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')
is_gpencil = (obj_type == 'GPENCIL')
col = flow.column()
col.prop(obj, "show_name", text="Name")
col = flow.column()
col.prop(obj, "show_axis", text="Axis")
# Makes no sense for cameras, armatures, etc.!
# but these settings do apply to dupli instances
if is_geometry or is_dupli:
col = flow.column()
col.prop(obj, "show_wire", text="Wireframe")
if obj_type == 'MESH' or is_dupli:
col = flow.column()
col.prop(obj, "show_all_edges", text="All Edges")
col = flow.column()
if is_geometry:
col.prop(obj, "show_texture_space", text="Texture Space")
col = flow.column()
col.prop(obj.display, "show_shadows", text="Shadow")
col = flow.column()
col.prop(obj, "show_in_front", text="In Front")
# if obj_type == 'MESH' or is_empty_image:
# col.prop(obj, "show_transparent", text="Transparency")
flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
col = flow.column()
if is_wire:
# wire objects only use the max. display type for duplis
col.active = is_dupli
col.prop(obj, "display_type", text="Display As")
if is_geometry or is_dupli or is_empty_image or is_gpencil:
# Only useful with object having faces/materials...
col = flow.column()
col.prop(obj, "color")
class OBJECT_PT_display_bounds(ObjectButtonsPanel, Panel):
bl_label = "Bounds"
bl_parent_id = "OBJECT_PT_display"
bl_options = {'DEFAULT_CLOSED'}
def draw_header(self, context):
obj = context.object
self.layout.prop(obj, "show_bounds", text="")
def draw(self, context):
layout = self.layout
obj = context.object
layout.use_property_split = True
layout.active = obj.show_bounds or (obj.display_type == 'BOUNDS')
layout.prop(obj, "display_bounds_type", text="Shape")
class OBJECT_PT_instancing(ObjectButtonsPanel, Panel):
bl_label = "Instancing"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
ob = context.object
row = layout.row()
row.prop(ob, "instance_type", expand=True)
layout.use_property_split = True
flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
if ob.instance_type == 'VERTS':
layout.prop(ob, "use_instance_vertices_rotation", text="Align to Vertex Normal")
elif ob.instance_type == 'COLLECTION':
col = layout.column()
col.prop(ob, "instance_collection", text="Collection")
if ob.instance_type != 'NONE' or ob.particle_systems:
col = flow.column(align=True)
col.prop(ob, "show_instancer_for_viewport")
col.prop(ob, "show_instancer_for_render")
class OBJECT_PT_instancing_size(ObjectButtonsPanel, Panel):
bl_label = "Scale by Face Size"
bl_parent_id = "OBJECT_PT_instancing"
@classmethod
def poll(cls, context):
ob = context.object
return ob.instance_type == 'FACES'
def draw_header(self, context):
ob = context.object
self.layout.prop(ob, "use_instance_faces_scale", text="")
def draw(self, context):
layout = self.layout
ob = context.object
layout.use_property_split = True
layout.active = ob.use_instance_faces_scale
layout.prop(ob, "instance_faces_scale", text="Factor")
class OBJECT_PT_motion_paths(MotionPathButtonsPanel, Panel):
#bl_label = "Object Motion Paths"
bl_context = "object"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
return (context.object)
def draw(self, context):
# layout = self.layout
ob = context.object
avs = ob.animation_visualization
mpath = ob.motion_path
self.draw_settings(context, avs, mpath)
class OBJECT_PT_motion_paths_display(MotionPathButtonsPanel_display, Panel):
#bl_label = "Object Motion Paths"
bl_context = "object"
bl_parent_id = "OBJECT_PT_motion_paths"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
return (context.object)
def draw(self, context):
# layout = self.layout
ob = context.object
avs = ob.animation_visualization
mpath = ob.motion_path
self.draw_settings(context, avs, mpath)
class OBJECT_PT_visibility(ObjectButtonsPanel, Panel):
bl_label = "Visibility"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
@classmethod
def poll(cls, context):
return (context.object) and (context.engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
layout.use_property_split = True
flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
layout = self.layout
ob = context.object
col = flow.column()
col.prop(ob, "hide_viewport", text="Show in Viewports", toggle=False, invert_checkbox=True)
col = flow.column()
col.prop(ob, "hide_render", text="Show in Renders", toggle=False, invert_checkbox=True)
col = flow.column()
col.prop(ob, "hide_select", text="Selectable", toggle=False, invert_checkbox=True)
class OBJECT_PT_greasepencil_light(ObjectButtonsPanel, Panel):
bl_label = "Grease Pencil"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
@classmethod
def poll(cls, context):
return (context.object) and (context.engine in cls.COMPAT_ENGINES) and (context.object.type == 'GPENCIL')
def draw(self, context):
layout = self.layout
layout.use_property_split = True
flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
layout = self.layout
ob = context.object
col = flow.column()
col.prop(ob, "use_grease_pencil_lights", toggle=False)
class OBJECT_PT_custom_props(ObjectButtonsPanel, PropertyPanel, Panel):
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
_context_path = "object"
_property_type = bpy.types.Object
classes = (
OBJECT_PT_context_object,
OBJECT_PT_transform,
OBJECT_PT_delta_transform,
OBJECT_PT_relations,
COLLECTION_MT_context_menu,
OBJECT_PT_collections,
OBJECT_PT_instancing,
OBJECT_PT_instancing_size,
OBJECT_PT_motion_paths,
OBJECT_PT_motion_paths_display,
OBJECT_PT_display,
OBJECT_PT_display_bounds,
OBJECT_PT_visibility,
OBJECT_PT_greasepencil_light,
OBJECT_PT_custom_props,
)
if __name__ == "__main__": # only for live edit.
from bpy.utils import register_class
for cls in classes:
register_class(cls)