Ну вот и всё.
Дружно тестим и исправляем баги, если найдутся.
Сам addon можно получить тут или тут
Ну или копируйте ниже:
# ##### 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 #####
bl_info = {
"name": "Dynamic Visible",
"author": "Maxim Seliverstoff",
"version": (0, 0, 1),
"blender": (2, 68, 0),
"location": "Camera > Dynamic Visible",
"description": "Controls the visibility of objects through a picture frame camera",
"warning": "",
"wiki_url": "",
"tracker_url": "",
"category": "Object"}
import bpy, bl_ui
from bpy.types import Operator
from bpy.types import Panel, Menu
from rna_prop_ui import PropertyPanel
from bpy_extras.object_utils import world_to_camera_view
from bpy.app.handlers import persistent
@persistent
def update_handler(self):
cam_obj = bpy.data.cameras[self.camera.name]
cam = self.camera
dv = cam_obj.dynamic_visible
if dv.update:
FindVisible(cam, cam_obj, dv)
bpy.app.handlers.frame_change_post.append(update_handler)
CameraButtonsPanel = bl_ui.properties_data_camera.CameraButtonsPanel
def updateDynamicVisible(self, context):
cam_obj = bpy.data.objects[context.object.name]
cam = context.camera
dv = cam.dynamic_visible
if dv.update:
FindVisible(cam_obj, cam, dv)
class DynamicVisibleSettings(bpy.types.PropertyGroup):
use = bpy.props.BoolProperty(
name = "Use Properties",
description = "Use Properties Description",
default = False
)
raise_frame = bpy.props.FloatProperty(
name = "Raise Frame",
description = "Increases the frame, the larger the value, \
the more objects will be visible",
default = 0.0,
min = 0.0,
max = 10.0,
soft_min = 0.001,
soft_max = 10.0,
step = 5,
precision = 3,
update = updateDynamicVisible
)
mode_type = bpy.props.EnumProperty(
items = [('LAYER',
'Move to Layers',
'Objects will be moved to another layer, each new frame'),
('HIDE',
'Hide Render',
'Objects will be disconnected from the rendering')],
name = "Mode Type",
description = "The method by which objects are hidden",
default = "LAYER"
)
update = bpy.props.BoolProperty(
name = "Auto Update",
description = "Select if you want to automatically hide objects",
default = False
)
hide_view = bpy.props.BoolProperty(
name = "Hide View",
description = "Hide objects in View",
default = True
)
hide_render = bpy.props.BoolProperty(
name = "Hide Render",
description = "Hide objects in Render",
default = True
)
use_animation = bpy.props.BoolProperty(
name = "Animation",
description = "Hide objects in Render",
default = True
)
animated = bpy.props.BoolProperty(
name = "anim yes",
default = False
)
out_layer = bpy.props.BoolVectorProperty(
name = 'Layer Out',
subtype = 'LAYER',
size = 20
)
include_group = bpy.props.StringProperty(
name="Include Group",
description="Use only group"
)
exclude_group = bpy.props.StringProperty(
name="Exclude Group",
description="Use only group"
)
bpy.utils.register_class(DynamicVisibleSettings)
bpy.types.Camera.dynamic_visible = bpy.props.PointerProperty(type=DynamicVisibleSettings)
class DATA_PT_camera_dynamic_visible(CameraButtonsPanel, Panel):
COMPAT_ENGINES = {'BLENDER_RENDER', 'VRAY_RENDER', 'CYCLES'}
bl_label = "Dynamic Visible Setting"
bl_options = {'DEFAULT_CLOSED'}
def button_event(evt, val):
print(evt.type)
def draw_header(self, context):
self.layout.prop(context.camera.dynamic_visible, "use", text="")
def draw(self, context):
layout = self.layout
cam = context.camera.dynamic_visible
layout.active = cam.use
split = layout.split()
split.prop(cam, "update")
if cam.update == False:
split = layout.split()
split.operator("camera.update_visible", icon="FILE_REFRESH")
split = layout.split()
split.prop(cam, "raise_frame")
layout.separator()
split = layout.split()
split.prop(cam, "mode_type", text="")
if cam.mode_type == 'HIDE':
col= split.column()
col.prop(cam, "hide_view")
col.prop(cam, "hide_render")
if cam.mode_type == 'LAYER':
col= split.column()
col.prop(cam, "out_layer", text="")
layout.separator()
layout.label(text="Include\Exclude objects:")
split = layout.split()
split.prop_search(cam, 'include_group',
bpy.data, 'groups', text="Include")
split = layout.split()
split.prop_search(cam, 'exclude_group',
bpy.data, 'groups', text="Exclude")
if cam.mode_type == 'HIDE':
layout.separator()
split = layout.split()
split.prop(cam, "use_animation")
if cam.use_animation:
split = layout.split()
split.active = not cam.animated
split.operator("camera.create_animation_visible", icon="ANIM_DATA")
split = layout.split()
split.active = cam.animated
split.operator("camera.clean_animation_visible", icon="CANCEL")
class ManualUpdate(bpy.types.Operator):
bl_idname = "camera.update_visible"
bl_label = "Update Current Frame"
def execute(self, context):
cam_obj = bpy.data.objects[context.object.name]
cam = context.camera
dv = cam.dynamic_visible
FindVisible(cam_obj, cam, dv)
return {'FINISHED'}
bpy.utils.register_class(ManualUpdate)
class CreateAnimation(bpy.types.Operator):
bl_idname = "camera.create_animation_visible"
bl_label = "Bake all frame to Animation"
def __init__(self):
bpy.context.window_manager.progress_begin(0,99)
scene = bpy.context.scene
self.start = scene.frame_start + 1
self.end = scene.frame_end + 1
self.step = scene.frame_step
self.i = 0
self._timer = None
def __del__(self):
bpy.context.window_manager.progress_end()
def execute(self, context):
self._timer = context.window_manager.event_timer_add(0.1, context.window)
self.i += 1
progress_step = self.end-self.start/100
bpy.context.window_manager.progress_update(self.i/progress_step)
cam_obj = bpy.data.objects[context.object.name]
cam = context.camera
dv = cam.dynamic_visible
bpy.context.scene.frame_set(self.i)
FindVisible(cam_obj, cam, dv, anim=True)
def modal(self, context, event):
cam = context.camera
dv = cam.dynamic_visible
if dv.animated:
return {'FINISHED'}
if self.i > self.end-self.start:
dv.animated = True
return {'FINISHED'}
if event.type in ('RIGHTMOUSE', 'ESC'):
return self.cancel(context)
self.execute(context)
return {'RUNNING_MODAL'}
def cancel(self, context):
context.window_manager.event_timer_remove(self._timer)
bpy.context.window_manager.progress_end()
return {'CANCELLED'}
def invoke(self, context, event):
context.window_manager.modal_handler_add(self)
return {'RUNNING_MODAL'}
bpy.utils.register_class(CreateAnimation)
class CleanAnimation(bpy.types.Operator):
bl_idname = "camera.clean_animation_visible"
bl_label = "Clean Animation"
def execute(self, context):
ng = bpy.data.groups["DynamicVisibleObjects"]
cam = context.camera
dv = cam.dynamic_visible
dv.animated = False
for obj in ng.objects:
anim_data = obj.animation_data
for fcurve in anim_data.action.fcurves:
if fcurve.data_path in ['hide', 'hide_render']:
anim_data.action.fcurves.remove(fcurve)
return {'FINISHED'}
bpy.utils.register_class(CleanAnimation)
def FindVisible(cam_obj, cam, dv, anim=False):
non_trace = [
"CAMERA",
"LAMP",
"CURVE",
"EMPTY",
"LATTICE"]
scene = bpy.context.scene
fr = scene.frame_current
if len(dv.include_group) > 0:
obj_list = bpy.data.groups[dv.include_group].objects
else:
obj_list = bpy.data.objects
if len(dv.exclude_group) > 0:
obj_exclude = bpy.data.groups[dv.exclude_group].objects
else:
obj_exclude = []
for ob in obj_list:
if ob.type in non_trace or ob.name in obj_exclude:
continue
else:
frame = world_to_camera_view(scene, cam_obj, ob.location)
xy_min = 0 - dv.raise_frame
xy_max = 1 + dv.raise_frame
if frame[0] >=xy_min and frame[0]<=xy_max and frame[1]>=xy_min and frame[1]<=xy_max and frame[2]>0:
if dv.mode_type == 'HIDE':
if dv.hide_view:
ob.hide = not dv.hide_view
if anim and check_key(ob, 'hide', fr, ob.hide):
add_anim_group(ob)
ob.keyframe_insert(data_path='hide', frame=fr)
if dv.hide_render:
ob.hide_render = not dv.hide_render
if anim and check_key(ob, 'hide_render', fr, ob.hide_render):
add_anim_group(ob)
ob.keyframe_insert(data_path='hide_render', frame=fr)
elif dv.mode_type == 'LAYER':
ob.layers = scene.layers
else:
if dv.mode_type == 'HIDE':
ob.hide = dv.hide_view
if anim and check_key(ob, 'hide', fr, ob.hide):
add_anim_group(ob)
ob.keyframe_insert(data_path='hide', frame=fr)
ob.hide_render = dv.hide_render
if anim and check_key(ob, 'hide_render', fr, ob.hide_render):
add_anim_group(ob)
ob.keyframe_insert(data_path='hide_render', frame=fr)
elif dv.mode_type == 'LAYER':
ob.layers = dv.out_layer
def add_anim_group(obj):
scene = bpy.context.scene
if not "DynamicVisibleObjects" in bpy.data.groups:
ng = bpy.data.groups.new("DynamicVisibleObjects")
else:
ng = bpy.data.groups["DynamicVisibleObjects"]
if obj.name in ng.objects:
return False
else:
ng.objects.link(obj)
return True
def check_key(obj, path, fr, c_val, index=0):
out = True
if c_val:
c_val = 1.0
else:
c_val = 0.0
anim_data = obj.animation_data
if anim_data.action:
for fcurve in anim_data.action.fcurves:
if fcurve.data_path == path:
if fcurve.evaluate(fr-1) == c_val:
out = False
else:
out = True
return out
else:
return True
def register():
bpy.utils.register_class(DATA_PT_camera_dynamic_visible)
def unregister():
bpy.utils.unregister_class(DATA_PT_camera_dynamic_visible)
if __name__ == "__main__":
register()
Дружно тестим и исправляем баги, если найдутся.
Сам addon можно получить тут или тут
Ну или копируйте ниже:
# ##### 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 #####
bl_info = {
"name": "Dynamic Visible",
"author": "Maxim Seliverstoff",
"version": (0, 0, 1),
"blender": (2, 68, 0),
"location": "Camera > Dynamic Visible",
"description": "Controls the visibility of objects through a picture frame camera",
"warning": "",
"wiki_url": "",
"tracker_url": "",
"category": "Object"}
import bpy, bl_ui
from bpy.types import Operator
from bpy.types import Panel, Menu
from rna_prop_ui import PropertyPanel
from bpy_extras.object_utils import world_to_camera_view
from bpy.app.handlers import persistent
@persistent
def update_handler(self):
cam_obj = bpy.data.cameras[self.camera.name]
cam = self.camera
dv = cam_obj.dynamic_visible
if dv.update:
FindVisible(cam, cam_obj, dv)
bpy.app.handlers.frame_change_post.append(update_handler)
CameraButtonsPanel = bl_ui.properties_data_camera.CameraButtonsPanel
def updateDynamicVisible(self, context):
cam_obj = bpy.data.objects[context.object.name]
cam = context.camera
dv = cam.dynamic_visible
if dv.update:
FindVisible(cam_obj, cam, dv)
class DynamicVisibleSettings(bpy.types.PropertyGroup):
use = bpy.props.BoolProperty(
name = "Use Properties",
description = "Use Properties Description",
default = False
)
raise_frame = bpy.props.FloatProperty(
name = "Raise Frame",
description = "Increases the frame, the larger the value, \
the more objects will be visible",
default = 0.0,
min = 0.0,
max = 10.0,
soft_min = 0.001,
soft_max = 10.0,
step = 5,
precision = 3,
update = updateDynamicVisible
)
mode_type = bpy.props.EnumProperty(
items = [('LAYER',
'Move to Layers',
'Objects will be moved to another layer, each new frame'),
('HIDE',
'Hide Render',
'Objects will be disconnected from the rendering')],
name = "Mode Type",
description = "The method by which objects are hidden",
default = "LAYER"
)
update = bpy.props.BoolProperty(
name = "Auto Update",
description = "Select if you want to automatically hide objects",
default = False
)
hide_view = bpy.props.BoolProperty(
name = "Hide View",
description = "Hide objects in View",
default = True
)
hide_render = bpy.props.BoolProperty(
name = "Hide Render",
description = "Hide objects in Render",
default = True
)
use_animation = bpy.props.BoolProperty(
name = "Animation",
description = "Hide objects in Render",
default = True
)
animated = bpy.props.BoolProperty(
name = "anim yes",
default = False
)
out_layer = bpy.props.BoolVectorProperty(
name = 'Layer Out',
subtype = 'LAYER',
size = 20
)
include_group = bpy.props.StringProperty(
name="Include Group",
description="Use only group"
)
exclude_group = bpy.props.StringProperty(
name="Exclude Group",
description="Use only group"
)
bpy.utils.register_class(DynamicVisibleSettings)
bpy.types.Camera.dynamic_visible = bpy.props.PointerProperty(type=DynamicVisibleSettings)
class DATA_PT_camera_dynamic_visible(CameraButtonsPanel, Panel):
COMPAT_ENGINES = {'BLENDER_RENDER', 'VRAY_RENDER', 'CYCLES'}
bl_label = "Dynamic Visible Setting"
bl_options = {'DEFAULT_CLOSED'}
def button_event(evt, val):
print(evt.type)
def draw_header(self, context):
self.layout.prop(context.camera.dynamic_visible, "use", text="")
def draw(self, context):
layout = self.layout
cam = context.camera.dynamic_visible
layout.active = cam.use
split = layout.split()
split.prop(cam, "update")
if cam.update == False:
split = layout.split()
split.operator("camera.update_visible", icon="FILE_REFRESH")
split = layout.split()
split.prop(cam, "raise_frame")
layout.separator()
split = layout.split()
split.prop(cam, "mode_type", text="")
if cam.mode_type == 'HIDE':
col= split.column()
col.prop(cam, "hide_view")
col.prop(cam, "hide_render")
if cam.mode_type == 'LAYER':
col= split.column()
col.prop(cam, "out_layer", text="")
layout.separator()
layout.label(text="Include\Exclude objects:")
split = layout.split()
split.prop_search(cam, 'include_group',
bpy.data, 'groups', text="Include")
split = layout.split()
split.prop_search(cam, 'exclude_group',
bpy.data, 'groups', text="Exclude")
if cam.mode_type == 'HIDE':
layout.separator()
split = layout.split()
split.prop(cam, "use_animation")
if cam.use_animation:
split = layout.split()
split.active = not cam.animated
split.operator("camera.create_animation_visible", icon="ANIM_DATA")
split = layout.split()
split.active = cam.animated
split.operator("camera.clean_animation_visible", icon="CANCEL")
class ManualUpdate(bpy.types.Operator):
bl_idname = "camera.update_visible"
bl_label = "Update Current Frame"
def execute(self, context):
cam_obj = bpy.data.objects[context.object.name]
cam = context.camera
dv = cam.dynamic_visible
FindVisible(cam_obj, cam, dv)
return {'FINISHED'}
bpy.utils.register_class(ManualUpdate)
class CreateAnimation(bpy.types.Operator):
bl_idname = "camera.create_animation_visible"
bl_label = "Bake all frame to Animation"
def __init__(self):
bpy.context.window_manager.progress_begin(0,99)
scene = bpy.context.scene
self.start = scene.frame_start + 1
self.end = scene.frame_end + 1
self.step = scene.frame_step
self.i = 0
self._timer = None
def __del__(self):
bpy.context.window_manager.progress_end()
def execute(self, context):
self._timer = context.window_manager.event_timer_add(0.1, context.window)
self.i += 1
progress_step = self.end-self.start/100
bpy.context.window_manager.progress_update(self.i/progress_step)
cam_obj = bpy.data.objects[context.object.name]
cam = context.camera
dv = cam.dynamic_visible
bpy.context.scene.frame_set(self.i)
FindVisible(cam_obj, cam, dv, anim=True)
def modal(self, context, event):
cam = context.camera
dv = cam.dynamic_visible
if dv.animated:
return {'FINISHED'}
if self.i > self.end-self.start:
dv.animated = True
return {'FINISHED'}
if event.type in ('RIGHTMOUSE', 'ESC'):
return self.cancel(context)
self.execute(context)
return {'RUNNING_MODAL'}
def cancel(self, context):
context.window_manager.event_timer_remove(self._timer)
bpy.context.window_manager.progress_end()
return {'CANCELLED'}
def invoke(self, context, event):
context.window_manager.modal_handler_add(self)
return {'RUNNING_MODAL'}
bpy.utils.register_class(CreateAnimation)
class CleanAnimation(bpy.types.Operator):
bl_idname = "camera.clean_animation_visible"
bl_label = "Clean Animation"
def execute(self, context):
ng = bpy.data.groups["DynamicVisibleObjects"]
cam = context.camera
dv = cam.dynamic_visible
dv.animated = False
for obj in ng.objects:
anim_data = obj.animation_data
for fcurve in anim_data.action.fcurves:
if fcurve.data_path in ['hide', 'hide_render']:
anim_data.action.fcurves.remove(fcurve)
return {'FINISHED'}
bpy.utils.register_class(CleanAnimation)
def FindVisible(cam_obj, cam, dv, anim=False):
non_trace = [
"CAMERA",
"LAMP",
"CURVE",
"EMPTY",
"LATTICE"]
scene = bpy.context.scene
fr = scene.frame_current
if len(dv.include_group) > 0:
obj_list = bpy.data.groups[dv.include_group].objects
else:
obj_list = bpy.data.objects
if len(dv.exclude_group) > 0:
obj_exclude = bpy.data.groups[dv.exclude_group].objects
else:
obj_exclude = []
for ob in obj_list:
if ob.type in non_trace or ob.name in obj_exclude:
continue
else:
frame = world_to_camera_view(scene, cam_obj, ob.location)
xy_min = 0 - dv.raise_frame
xy_max = 1 + dv.raise_frame
if frame[0] >=xy_min and frame[0]<=xy_max and frame[1]>=xy_min and frame[1]<=xy_max and frame[2]>0:
if dv.mode_type == 'HIDE':
if dv.hide_view:
ob.hide = not dv.hide_view
if anim and check_key(ob, 'hide', fr, ob.hide):
add_anim_group(ob)
ob.keyframe_insert(data_path='hide', frame=fr)
if dv.hide_render:
ob.hide_render = not dv.hide_render
if anim and check_key(ob, 'hide_render', fr, ob.hide_render):
add_anim_group(ob)
ob.keyframe_insert(data_path='hide_render', frame=fr)
elif dv.mode_type == 'LAYER':
ob.layers = scene.layers
else:
if dv.mode_type == 'HIDE':
ob.hide = dv.hide_view
if anim and check_key(ob, 'hide', fr, ob.hide):
add_anim_group(ob)
ob.keyframe_insert(data_path='hide', frame=fr)
ob.hide_render = dv.hide_render
if anim and check_key(ob, 'hide_render', fr, ob.hide_render):
add_anim_group(ob)
ob.keyframe_insert(data_path='hide_render', frame=fr)
elif dv.mode_type == 'LAYER':
ob.layers = dv.out_layer
def add_anim_group(obj):
scene = bpy.context.scene
if not "DynamicVisibleObjects" in bpy.data.groups:
ng = bpy.data.groups.new("DynamicVisibleObjects")
else:
ng = bpy.data.groups["DynamicVisibleObjects"]
if obj.name in ng.objects:
return False
else:
ng.objects.link(obj)
return True
def check_key(obj, path, fr, c_val, index=0):
out = True
if c_val:
c_val = 1.0
else:
c_val = 0.0
anim_data = obj.animation_data
if anim_data.action:
for fcurve in anim_data.action.fcurves:
if fcurve.data_path == path:
if fcurve.evaluate(fr-1) == c_val:
out = False
else:
out = True
return out
else:
return True
def register():
bpy.utils.register_class(DATA_PT_camera_dynamic_visible)
def unregister():
bpy.utils.unregister_class(DATA_PT_camera_dynamic_visible)
if __name__ == "__main__":
register()
А тестирование эффективности производилось? Сколько времени/памяти удаётся сэкономить?
ОтветитьУдалитьПока был очень беглый тест, но он показал, что разница ощутима только на больших нагрузках.
УдалитьНу вот в этой сцене примерно 15 сек. до и 13 после. А если увеличивать кол-во объектов, то разрыв растет в процентном отношении.
Чуть позже сделаю табличку более подробную, самому интересно.