In the Properties editor, add Action selectors to the Material properties and the Camera properties. For the Material, two Action selectors are shown: for the Material itself and for its shader node tree. Those are separate IDs of different types, and thus will always have separate Actions (until the Slotted Actions are commonplace). When the 'Slotted Actions' experimental feature is enabled, also show the Action Slot selector underneath each Action selector. The Animation panel in the Properties editor is (by default) always at the bottom, just above the Custom Properties panel. Pull Request: https://projects.blender.org/blender/blender/pulls/125666
617 lines
20 KiB
Python
617 lines
20 KiB
Python
# SPDX-FileCopyrightText: 2009-2023 Blender Authors
|
|
#
|
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
import bpy
|
|
from bpy.types import Panel
|
|
from bpy.app.translations import contexts as i18n_contexts
|
|
from rna_prop_ui import PropertyPanel
|
|
from bl_ui.utils import PresetPanel
|
|
from .space_properties import PropertiesAnimationMixin
|
|
|
|
|
|
class CameraButtonsPanel:
|
|
bl_space_type = 'PROPERTIES'
|
|
bl_region_type = 'WINDOW'
|
|
bl_context = "data"
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
engine = context.engine
|
|
return context.camera and (engine in cls.COMPAT_ENGINES)
|
|
|
|
|
|
class CAMERA_PT_presets(PresetPanel, Panel):
|
|
bl_label = "Camera Presets"
|
|
preset_subdir = "camera"
|
|
preset_operator = "script.execute_preset"
|
|
preset_add_operator = "camera.preset_add"
|
|
COMPAT_ENGINES = {
|
|
'BLENDER_RENDER',
|
|
'BLENDER_EEVEE',
|
|
'BLENDER_EEVEE_NEXT',
|
|
'BLENDER_WORKBENCH',
|
|
}
|
|
|
|
|
|
class CAMERA_PT_safe_areas_presets(PresetPanel, Panel):
|
|
bl_label = "Camera Presets"
|
|
preset_subdir = "safe_areas"
|
|
preset_operator = "script.execute_preset"
|
|
preset_add_operator = "camera.safe_areas_preset_add"
|
|
COMPAT_ENGINES = {
|
|
'BLENDER_RENDER',
|
|
'BLENDER_EEVEE',
|
|
'BLENDER_EEVEE_NEXT',
|
|
'BLENDER_WORKBENCH',
|
|
}
|
|
|
|
|
|
class DATA_PT_context_camera(CameraButtonsPanel, Panel):
|
|
bl_label = ""
|
|
bl_options = {'HIDE_HEADER'}
|
|
COMPAT_ENGINES = {
|
|
'BLENDER_RENDER',
|
|
'BLENDER_EEVEE',
|
|
'BLENDER_EEVEE_NEXT',
|
|
'BLENDER_WORKBENCH',
|
|
}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
|
|
ob = context.object
|
|
cam = context.camera
|
|
space = context.space_data
|
|
|
|
if ob:
|
|
layout.template_ID(ob, "data")
|
|
elif cam:
|
|
layout.template_ID(space, "pin_id")
|
|
|
|
|
|
class DATA_PT_lens(CameraButtonsPanel, Panel):
|
|
bl_label = "Lens"
|
|
bl_translation_context = i18n_contexts.id_camera
|
|
COMPAT_ENGINES = {
|
|
'BLENDER_RENDER',
|
|
'BLENDER_EEVEE',
|
|
'BLENDER_EEVEE_NEXT',
|
|
'BLENDER_WORKBENCH',
|
|
}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
|
|
cam = context.camera
|
|
|
|
layout.prop(cam, "type")
|
|
|
|
col = layout.column()
|
|
col.separator()
|
|
|
|
if cam.type == 'PERSP':
|
|
if cam.lens_unit == 'MILLIMETERS':
|
|
col.prop(cam, "lens")
|
|
elif cam.lens_unit == 'FOV':
|
|
col.prop(cam, "angle")
|
|
col.prop(cam, "lens_unit")
|
|
|
|
elif cam.type == 'ORTHO':
|
|
col.prop(cam, "ortho_scale")
|
|
|
|
elif cam.type == 'PANO':
|
|
engine = context.engine
|
|
if engine == 'CYCLES':
|
|
col.prop(cam, "panorama_type")
|
|
if cam.panorama_type == 'FISHEYE_EQUIDISTANT':
|
|
col.prop(cam, "fisheye_fov")
|
|
elif cam.panorama_type == 'FISHEYE_EQUISOLID':
|
|
col.prop(cam, "fisheye_lens", text="Lens")
|
|
col.prop(cam, "fisheye_fov")
|
|
elif cam.panorama_type == 'EQUIRECTANGULAR':
|
|
sub = col.column(align=True)
|
|
sub.prop(cam, "latitude_min", text="Latitude Min")
|
|
sub.prop(cam, "latitude_max", text="Max")
|
|
sub = col.column(align=True)
|
|
sub.prop(cam, "longitude_min", text="Longitude Min")
|
|
sub.prop(cam, "longitude_max", text="Max")
|
|
elif cam.panorama_type == 'FISHEYE_LENS_POLYNOMIAL':
|
|
col.prop(cam, "fisheye_fov")
|
|
col.prop(cam, "fisheye_polynomial_k0", text="K0")
|
|
col.prop(cam, "fisheye_polynomial_k1", text="K1")
|
|
col.prop(cam, "fisheye_polynomial_k2", text="K2")
|
|
col.prop(cam, "fisheye_polynomial_k3", text="K3")
|
|
col.prop(cam, "fisheye_polynomial_k4", text="K4")
|
|
elif cam.panorama_type == 'CENTRAL_CYLINDRICAL':
|
|
sub = col.column(align=True)
|
|
sub.prop(cam, "central_cylindrical_range_v_min", text="Height Min")
|
|
sub.prop(cam, "central_cylindrical_range_v_max", text="Max")
|
|
sub = col.column(align=True)
|
|
sub.prop(cam, "central_cylindrical_range_u_min", text="Longitude Min")
|
|
sub.prop(cam, "central_cylindrical_range_u_max", text="Max")
|
|
sub = col.column(align=True)
|
|
sub.prop(cam, "central_cylindrical_radius", text="Cylinder radius")
|
|
|
|
elif engine in {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_EEVEE_NEXT', 'BLENDER_WORKBENCH'}:
|
|
if cam.lens_unit == 'MILLIMETERS':
|
|
col.prop(cam, "lens")
|
|
elif cam.lens_unit == 'FOV':
|
|
col.prop(cam, "angle")
|
|
col.prop(cam, "lens_unit")
|
|
|
|
col = layout.column()
|
|
col.separator()
|
|
|
|
sub = col.column(align=True)
|
|
sub.prop(cam, "shift_x", text="Shift X")
|
|
sub.prop(cam, "shift_y", text="Y")
|
|
|
|
col.separator()
|
|
sub = col.column(align=True)
|
|
sub.prop(cam, "clip_start", text="Clip Start")
|
|
sub.prop(cam, "clip_end", text="End")
|
|
|
|
|
|
class DATA_PT_camera_stereoscopy(CameraButtonsPanel, Panel):
|
|
bl_label = "Stereoscopy"
|
|
COMPAT_ENGINES = {
|
|
'BLENDER_RENDER',
|
|
'BLENDER_EEVEE',
|
|
'BLENDER_EEVEE_NEXT',
|
|
'BLENDER_WORKBENCH',
|
|
}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
render = context.scene.render
|
|
return (super().poll(context) and render.use_multiview and render.views_format == 'STEREO_3D')
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
|
|
render = context.scene.render
|
|
st = context.camera.stereo
|
|
cam = context.camera
|
|
|
|
is_spherical_stereo = cam.type != 'ORTHO' and render.use_spherical_stereo
|
|
use_spherical_stereo = is_spherical_stereo and st.use_spherical_stereo
|
|
|
|
layout.prop(st, "convergence_mode")
|
|
|
|
col = layout.column()
|
|
sub = col.column()
|
|
sub.active = st.convergence_mode != 'PARALLEL'
|
|
sub.prop(st, "convergence_distance")
|
|
|
|
col.prop(st, "interocular_distance")
|
|
|
|
if is_spherical_stereo:
|
|
col.separator()
|
|
col.prop(st, "use_spherical_stereo")
|
|
sub = col.column()
|
|
sub.active = st.use_spherical_stereo
|
|
sub.prop(st, "use_pole_merge")
|
|
|
|
sub = col.column(align=True)
|
|
sub.active = st.use_pole_merge
|
|
sub.prop(st, "pole_merge_angle_from", text="Pole Merge Angle Start")
|
|
sub.prop(st, "pole_merge_angle_to", text="End")
|
|
|
|
col = layout.column()
|
|
col.active = not use_spherical_stereo
|
|
col.separator()
|
|
col.prop(st, "pivot")
|
|
|
|
|
|
class DATA_PT_camera(CameraButtonsPanel, Panel):
|
|
bl_label = "Camera"
|
|
bl_options = {'DEFAULT_CLOSED'}
|
|
COMPAT_ENGINES = {
|
|
'BLENDER_RENDER',
|
|
'BLENDER_EEVEE',
|
|
'BLENDER_EEVEE_NEXT',
|
|
'BLENDER_WORKBENCH',
|
|
}
|
|
|
|
def draw_header_preset(self, _context):
|
|
CAMERA_PT_presets.draw_panel_header(self.layout)
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
|
|
cam = context.camera
|
|
|
|
layout.use_property_split = True
|
|
|
|
col = layout.column()
|
|
col.prop(cam, "sensor_fit")
|
|
|
|
if cam.sensor_fit == 'AUTO':
|
|
col.prop(cam, "sensor_width", text="Size")
|
|
else:
|
|
sub = col.column(align=True)
|
|
sub.active = cam.sensor_fit == 'HORIZONTAL'
|
|
sub.prop(cam, "sensor_width", text="Width")
|
|
|
|
sub = col.column(align=True)
|
|
sub.active = cam.sensor_fit == 'VERTICAL'
|
|
sub.prop(cam, "sensor_height", text="Height")
|
|
|
|
|
|
class DATA_PT_camera_dof(CameraButtonsPanel, Panel):
|
|
bl_label = "Depth of Field"
|
|
bl_options = {'DEFAULT_CLOSED'}
|
|
COMPAT_ENGINES = {'BLENDER_EEVEE', 'BLENDER_EEVEE_NEXT', 'BLENDER_WORKBENCH'}
|
|
|
|
def draw_header(self, context):
|
|
cam = context.camera
|
|
dof = cam.dof
|
|
self.layout.prop(dof, "use_dof", text="")
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
|
|
cam = context.camera
|
|
dof = cam.dof
|
|
layout.active = dof.use_dof
|
|
|
|
col = layout.column()
|
|
col.prop(dof, "focus_object", text="Focus on Object")
|
|
if dof.focus_object and dof.focus_object.type == 'ARMATURE':
|
|
col.prop_search(dof, "focus_subtarget", dof.focus_object.data, "bones", text="Focus on Bone")
|
|
|
|
sub = col.column()
|
|
sub.active = (dof.focus_object is None)
|
|
row = sub.row(align=True)
|
|
row.prop(dof, "focus_distance", text="Focus Distance")
|
|
row.operator(
|
|
"ui.eyedropper_depth",
|
|
icon='EYEDROPPER',
|
|
text="").prop_data_path = "scene.camera.data.dof.focus_distance"
|
|
|
|
|
|
class DATA_PT_camera_dof_aperture(CameraButtonsPanel, Panel):
|
|
bl_label = "Aperture"
|
|
bl_parent_id = "DATA_PT_camera_dof"
|
|
COMPAT_ENGINES = {'BLENDER_EEVEE', 'BLENDER_EEVEE_NEXT', 'BLENDER_WORKBENCH'}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
|
|
cam = context.camera
|
|
dof = cam.dof
|
|
layout.active = dof.use_dof
|
|
|
|
flow = layout.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=False)
|
|
|
|
col = flow.column()
|
|
col.prop(dof, "aperture_fstop")
|
|
|
|
col = flow.column()
|
|
col.prop(dof, "aperture_blades")
|
|
col.prop(dof, "aperture_rotation")
|
|
col.prop(dof, "aperture_ratio")
|
|
|
|
|
|
class DATA_PT_camera_background_image(CameraButtonsPanel, Panel):
|
|
bl_label = "Background Images"
|
|
bl_options = {'DEFAULT_CLOSED'}
|
|
COMPAT_ENGINES = {
|
|
'BLENDER_RENDER',
|
|
'BLENDER_EEVEE',
|
|
'BLENDER_EEVEE_NEXT',
|
|
'BLENDER_WORKBENCH',
|
|
}
|
|
|
|
def draw_header(self, context):
|
|
cam = context.camera
|
|
|
|
self.layout.prop(cam, "show_background_images", text="")
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = False
|
|
|
|
cam = context.camera
|
|
use_multiview = context.scene.render.use_multiview
|
|
|
|
col = layout.column()
|
|
col.operator("view3d.camera_background_image_add", text="Add Image")
|
|
|
|
for i, bg in enumerate(cam.background_images):
|
|
layout.active = cam.show_background_images
|
|
box = layout.box()
|
|
row = box.row(align=True)
|
|
row.prop(bg, "show_expanded", text="", emboss=False)
|
|
if bg.source == 'IMAGE' and bg.image:
|
|
row.prop(bg.image, "name", text="", emboss=False)
|
|
elif bg.source == 'MOVIE_CLIP' and bg.clip:
|
|
row.prop(bg.clip, "name", text="", emboss=False)
|
|
elif bg.source and bg.use_camera_clip:
|
|
row.label(text="Active Clip")
|
|
else:
|
|
row.label(text="Not Set")
|
|
|
|
row.prop(
|
|
bg,
|
|
"show_background_image",
|
|
text="",
|
|
emboss=False,
|
|
icon='RESTRICT_VIEW_OFF' if bg.show_background_image else 'RESTRICT_VIEW_ON',
|
|
)
|
|
|
|
row.operator("view3d.camera_background_image_remove", text="", emboss=False, icon='X').index = i
|
|
|
|
if bg.show_expanded:
|
|
row = box.row()
|
|
row.prop(bg, "source", expand=True)
|
|
|
|
has_bg = False
|
|
if bg.source == 'IMAGE':
|
|
row = box.row()
|
|
row.template_ID(bg, "image", open="image.open")
|
|
if bg.image is not None:
|
|
box.template_image(bg, "image", bg.image_user, compact=True)
|
|
has_bg = True
|
|
|
|
if use_multiview:
|
|
box.prop(bg.image, "use_multiview")
|
|
|
|
column = box.column()
|
|
column.active = bg.image.use_multiview
|
|
|
|
column.label(text="Views Format:")
|
|
column.row().prop(bg.image, "views_format", expand=True)
|
|
|
|
sub = column.box()
|
|
sub.active = bg.image.views_format == 'STEREO_3D'
|
|
sub.template_image_stereo_3d(bg.image.stereo_3d_format)
|
|
|
|
elif bg.source == 'MOVIE_CLIP':
|
|
box.prop(bg, "use_camera_clip", text="Active Clip")
|
|
|
|
column = box.column()
|
|
column.active = not bg.use_camera_clip
|
|
column.template_ID(bg, "clip", open="clip.open")
|
|
|
|
if bg.clip:
|
|
column.template_movieclip(bg, "clip", compact=True)
|
|
|
|
if bg.use_camera_clip or bg.clip:
|
|
has_bg = True
|
|
|
|
column = box.column()
|
|
column.active = has_bg
|
|
column.prop(bg.clip_user, "use_render_undistorted")
|
|
column.prop(bg.clip_user, "proxy_render_size")
|
|
|
|
if has_bg:
|
|
col = box.column()
|
|
if bg.image is not None:
|
|
col.prop(bg.image, "use_view_as_render")
|
|
col.prop(bg, "alpha")
|
|
col.row().prop(bg, "display_depth", expand=True)
|
|
|
|
col.row().prop(bg, "frame_method", expand=True)
|
|
|
|
row = box.row()
|
|
row.prop(bg, "offset")
|
|
|
|
col = box.column()
|
|
col.prop(bg, "rotation")
|
|
col.prop(bg, "scale")
|
|
|
|
col = box.column(heading="Flip", heading_ctxt=i18n_contexts.id_image)
|
|
col.prop(bg, "use_flip_x", text="X")
|
|
col.prop(bg, "use_flip_y", text="Y")
|
|
|
|
|
|
class DATA_PT_camera_display(CameraButtonsPanel, Panel):
|
|
bl_label = "Viewport Display"
|
|
bl_options = {'DEFAULT_CLOSED'}
|
|
COMPAT_ENGINES = {
|
|
'BLENDER_RENDER',
|
|
'BLENDER_EEVEE',
|
|
'BLENDER_EEVEE_NEXT',
|
|
'BLENDER_WORKBENCH',
|
|
}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
|
|
cam = context.camera
|
|
|
|
col = layout.column(align=True)
|
|
|
|
col.prop(cam, "display_size", text="Size")
|
|
|
|
col = layout.column(heading="Show")
|
|
col.prop(cam, "show_limits", text="Limits")
|
|
col.prop(cam, "show_mist", text="Mist")
|
|
col.prop(cam, "show_sensor", text="Sensor")
|
|
col.prop(cam, "show_name", text="Name")
|
|
|
|
col = layout.column(align=False, heading="Passepartout")
|
|
col.use_property_decorate = False
|
|
row = col.row(align=True)
|
|
sub = row.row(align=True)
|
|
sub.prop(cam, "show_passepartout", text="")
|
|
sub = sub.row(align=True)
|
|
sub.active = cam.show_passepartout
|
|
sub.prop(cam, "passepartout_alpha", text="")
|
|
row.prop_decorator(cam, "passepartout_alpha")
|
|
|
|
|
|
class DATA_PT_camera_display_composition_guides(CameraButtonsPanel, Panel):
|
|
bl_label = "Composition Guides"
|
|
bl_parent_id = "DATA_PT_camera_display"
|
|
bl_options = {'DEFAULT_CLOSED'}
|
|
COMPAT_ENGINES = {
|
|
'BLENDER_RENDER',
|
|
'BLENDER_EEVEE',
|
|
'BLENDER_EEVEE_NEXT',
|
|
'BLENDER_WORKBENCH',
|
|
}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
|
|
cam = context.camera
|
|
|
|
layout.prop(cam, "show_composition_thirds")
|
|
|
|
col = layout.column(heading="Center", align=True)
|
|
col.prop(cam, "show_composition_center")
|
|
col.prop(cam, "show_composition_center_diagonal", text="Diagonal")
|
|
|
|
col = layout.column(heading="Golden", align=True)
|
|
col.prop(cam, "show_composition_golden", text="Ratio")
|
|
col.prop(cam, "show_composition_golden_tria_a", text="Triangle A")
|
|
col.prop(cam, "show_composition_golden_tria_b", text="Triangle B")
|
|
|
|
col = layout.column(heading="Harmony", align=True)
|
|
col.prop(cam, "show_composition_harmony_tri_a", text="Triangle A")
|
|
col.prop(cam, "show_composition_harmony_tri_b", text="Triangle B")
|
|
|
|
|
|
class DATA_PT_camera_safe_areas(CameraButtonsPanel, Panel):
|
|
bl_label = "Safe Areas"
|
|
bl_options = {'DEFAULT_CLOSED'}
|
|
COMPAT_ENGINES = {
|
|
'BLENDER_RENDER',
|
|
'BLENDER_EEVEE',
|
|
'BLENDER_EEVEE_NEXT',
|
|
'BLENDER_WORKBENCH',
|
|
}
|
|
|
|
def draw_header(self, context):
|
|
cam = context.camera
|
|
|
|
self.layout.prop(cam, "show_safe_areas", text="")
|
|
|
|
def draw_header_preset(self, _context):
|
|
CAMERA_PT_safe_areas_presets.draw_panel_header(self.layout)
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
safe_data = context.scene.safe_areas
|
|
camera = context.camera
|
|
|
|
layout.use_property_split = True
|
|
|
|
layout.active = camera.show_safe_areas
|
|
|
|
col = layout.column()
|
|
|
|
sub = col.column()
|
|
sub.prop(safe_data, "title", slider=True)
|
|
sub.prop(safe_data, "action", slider=True)
|
|
|
|
|
|
class DATA_PT_camera_safe_areas_center_cut(CameraButtonsPanel, Panel):
|
|
bl_label = "Center-Cut Safe Areas"
|
|
bl_parent_id = "DATA_PT_camera_safe_areas"
|
|
bl_options = {'DEFAULT_CLOSED'}
|
|
COMPAT_ENGINES = {
|
|
'BLENDER_RENDER',
|
|
'BLENDER_EEVEE',
|
|
'BLENDER_EEVEE_NEXT',
|
|
'BLENDER_WORKBENCH',
|
|
}
|
|
|
|
def draw_header(self, context):
|
|
cam = context.camera
|
|
|
|
layout = self.layout
|
|
layout.active = cam.show_safe_areas
|
|
layout.prop(cam, "show_safe_center", text="")
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
safe_data = context.scene.safe_areas
|
|
camera = context.camera
|
|
|
|
layout.use_property_split = True
|
|
|
|
layout.active = camera.show_safe_areas and camera.show_safe_center
|
|
|
|
col = layout.column()
|
|
col.prop(safe_data, "title_center", slider=True)
|
|
col.prop(safe_data, "action_center", slider=True)
|
|
|
|
|
|
class DATA_PT_camera_animation(CameraButtonsPanel, PropertiesAnimationMixin, PropertyPanel, Panel):
|
|
COMPAT_ENGINES = {
|
|
'BLENDER_RENDER',
|
|
'BLENDER_EEVEE',
|
|
'BLENDER_EEVEE_NEXT',
|
|
'BLENDER_WORKBENCH',
|
|
}
|
|
_animated_id_context_property = 'camera'
|
|
|
|
|
|
class DATA_PT_custom_props_camera(CameraButtonsPanel, PropertyPanel, Panel):
|
|
COMPAT_ENGINES = {
|
|
'BLENDER_RENDER',
|
|
'BLENDER_EEVEE',
|
|
'BLENDER_EEVEE_NEXT',
|
|
'BLENDER_WORKBENCH',
|
|
}
|
|
_context_path = "object.data"
|
|
_property_type = bpy.types.Camera
|
|
|
|
|
|
def draw_display_safe_settings(layout, safe_data, settings):
|
|
show_safe_areas = settings.show_safe_areas
|
|
show_safe_center = settings.show_safe_center
|
|
|
|
layout.use_property_split = True
|
|
|
|
col = layout.column()
|
|
col.active = show_safe_areas
|
|
|
|
sub = col.column()
|
|
sub.prop(safe_data, "title", slider=True)
|
|
sub.prop(safe_data, "action", slider=True)
|
|
|
|
col.separator()
|
|
|
|
col.prop(settings, "show_safe_center", text="Center-Cut Safe Areas")
|
|
|
|
sub = col.column()
|
|
sub.active = show_safe_areas and show_safe_center
|
|
sub.prop(safe_data, "title_center", slider=True)
|
|
sub.prop(safe_data, "action_center", slider=True)
|
|
|
|
|
|
classes = (
|
|
CAMERA_PT_presets,
|
|
CAMERA_PT_safe_areas_presets,
|
|
DATA_PT_context_camera,
|
|
DATA_PT_lens,
|
|
DATA_PT_camera_dof,
|
|
DATA_PT_camera_dof_aperture,
|
|
DATA_PT_camera,
|
|
DATA_PT_camera_stereoscopy,
|
|
DATA_PT_camera_safe_areas,
|
|
DATA_PT_camera_safe_areas_center_cut,
|
|
DATA_PT_camera_background_image,
|
|
DATA_PT_camera_display,
|
|
DATA_PT_camera_display_composition_guides,
|
|
DATA_PT_camera_animation,
|
|
DATA_PT_custom_props_camera,
|
|
)
|
|
|
|
if __name__ == "__main__": # only for live edit.
|
|
from bpy.utils import register_class
|
|
for cls in classes:
|
|
register_class(cls)
|