Newer
Older
Pablo Vazquez
committed
# ##### 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": "Amaranth Toolset",
"author": "Pablo Vazquez, Bassam Kurdali, Sergey Sharybin, Lukas Tönne",
"blender": (2, 70),
"location": "Everywhere!",
Pablo Vazquez
committed
"description": "A collection of tools and settings to improve productivity",
"warning": "",
"wiki_url": "http://pablovazquez.org/amaranth",
"tracker_url": "",
"category": "Scene"}
import bpy
from bpy.types import Operator, AddonPreferences, Panel, Menu
from bpy.props import (BoolProperty, EnumProperty,
FloatProperty, FloatVectorProperty,
IntProperty, StringProperty)
Pablo Vazquez
committed
from mathutils import Vector
from bpy.app.handlers import persistent
from bl_operators.presets import AddPresetBase
Pablo Vazquez
committed
# Addon wide, we need to know if cycles is available
global cycles_exists
cycles_exists = 'cycles' in dir(bpy.types.Scene)
Pablo Vazquez
committed
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# Preferences
class AmaranthToolsetPreferences(AddonPreferences):
bl_idname = __name__
use_frame_current = BoolProperty(
name="Current Frame Slider",
description="Set the current frame from the Specials menu in the 3D View",
default=True,
)
use_file_save_reload = BoolProperty(
name="Save & Reload File",
description="File menu > Save & Reload, or Ctrl + Shift + W",
default=True,
)
use_scene_refresh = BoolProperty(
name="Refresh Scene",
description="Specials Menu [W], or hit F5",
default=True,
)
use_timeline_extra_info = BoolProperty(
name="Timeline Extra Info",
description="Timeline Header",
default=True,
)
use_image_node_display = BoolProperty(
name="Active Image Node in Editor",
description="Display active node image in image editor",
default=True,
)
use_scene_stats = BoolProperty(
name="Extra Scene Statistics",
description="Display extra scene statistics in Info editor's header",
default=True,
)
frames_jump = IntProperty(
name="Frames",
description="Number of frames to jump forward/backward",
default=10,
min=1)
use_layers_for_render = BoolProperty(
name="Current Layers for Render",
description="Save the layers that should be enabled for render",
default=True,
)
Pablo Vazquez
committed
def draw(self, context):
layout = self.layout
layout.label(
text="Here you can enable or disable specific tools, "
"in case they interfere with others or are just plain annoying")
split = layout.split(percentage=0.25)
col = split.column()
sub = col.column(align=True)
sub.label(text="3D View", icon="VIEW3D")
sub.prop(self, "use_frame_current")
sub.prop(self, "use_scene_refresh")
sub.separator()
sub.label(text="General", icon="SCENE_DATA")
sub.prop(self, "use_file_save_reload")
sub.prop(self, "use_timeline_extra_info")
sub.prop(self, "use_scene_stats")
Pablo Vazquez
committed
sub.separator()
CoDEmanX
committed
sub.label(text="Nodes Editor", icon="NODETREE")
Pablo Vazquez
committed
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
sub.prop(self, "use_image_node_display")
col = split.column()
sub = col.column(align=True)
sub.label(text="")
sub.label(
text="Set the current frame from the Specials menu in the 3D View [W]")
sub.label(
text="Refresh the current Scene. Hotkey: F5 or in Specials menu [W]")
sub.separator()
sub.label(text="") # General
sub.label(
text="Quickly save and reload the current file (no warning!). "
"File menu or Ctrl+Shift+W")
sub.label(
text="SMPTE Timecode and frames left/ahead on Timeline's header")
sub.label(
text="Display extra statistics for Scenes, Cameras, and Meshlights (Cycles)")
sub.separator()
sub.label(text="") # Nodes
sub.label(
text="When selecting an Image node, display it on the Image editor "
"(if any)")
# Properties
def init_properties():
scene = bpy.types.Scene
node = bpy.types.Node
nodes_compo = bpy.types.CompositorNodeTree
scene.use_unsimplify_render = BoolProperty(
Pablo Vazquez
committed
default=False,
name="Unsimplify Render",
description="Disable Simplify during render")
scene.simplify_status = BoolProperty(default=False)
Pablo Vazquez
committed
node.use_matching_indices = BoolProperty(
Pablo Vazquez
committed
default=True,
description="If disabled, display all available indices")
Pablo Vazquez
committed
("ALL", "All Types", "", 0),
("BLUR", "Blur", "", 1),
("BOKEHBLUR", "Bokeh Blur", "", 2),
("VECBLUR", "Vector Blur", "", 3),
("DEFOCUS", "Defocus", "", 4),
("R_LAYERS", "Render Layer", "", 5)
]
nodes_compo.types = EnumProperty(
items=nodes_compo_types, name = "Types")
Pablo Vazquez
committed
nodes_compo.toggle_mute = BoolProperty(default=False)
node.status = BoolProperty(default=False)
# Scene Debug
# Cycles Node Types
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
if cycles_exists:
cycles_shader_node_types = [
("BSDF_DIFFUSE", "Diffuse BSDF", "", 0),
("BSDF_GLOSSY", "Glossy BSDF", "", 1),
("BSDF_TRANSPARENT", "Transparent BSDF", "", 2),
("BSDF_REFRACTION", "Refraction BSDF", "", 3),
("BSDF_GLASS", "Glass BSDF", "", 4),
("BSDF_TRANSLUCENT", "Translucent BSDF", "", 5),
("BSDF_ANISOTROPIC", "Anisotropic BSDF", "", 6),
("BSDF_VELVET", "Velvet BSDF", "", 7),
("BSDF_TOON", "Toon BSDF", "", 8),
("SUBSURFACE_SCATTERING", "Subsurface Scattering", "", 9),
("EMISSION", "Emission", "", 10),
("BSDF_HAIR", "Hair BSDF", "", 11),
("BACKGROUND", "Background", "", 12),
("AMBIENT_OCCLUSION", "Ambient Occlusion", "", 13),
("HOLDOUT", "Holdout", "", 14),
("VOLUME_ABSORPTION", "Volume Absorption", "", 15),
("VOLUME_SCATTER", "Volume Scatter", "", 16)
]
scene.amaranth_cycles_node_types = EnumProperty(
items=cycles_shader_node_types, name = "Shader")
scene.amaranth_cycles_list_sampling = BoolProperty(
default=False,
name="Samples Per:")
bpy.types.CyclesRenderSettings.use_samples_final = BoolProperty(
name="Use Final Render Samples",
description="Use current shader samples as final render samples",
default=False)
scene.amaranth_lighterscorner_list_meshlights = BoolProperty(
name="List Meshlights",
description="Include light emitting meshes on the list")
scene.amaranth_debug_scene_list_missing_images = BoolProperty(
default=False,
name="List Missing Images",
description="Display a list of all the missing images")
bpy.types.ShaderNodeNormal.normal_vector = prop_normal_vector
bpy.types.CompositorNodeNormal.normal_vector = prop_normal_vector
bpy.types.Object.is_keyframe = is_keyframe
scene.amth_wire_toggle_scene_all = BoolProperty(
default=False,
name="All Scenes",
description="Toggle wire on objects in all scenes")
scene.amth_wire_toggle_is_selected = BoolProperty(
default=False,
name="Only Selected",
description="Only toggle wire on selected objects")
scene.amth_wire_toggle_edges_all = BoolProperty(
default=True,
name="All Edges",
description="Draw all edges")
scene.amth_wire_toggle_optimal = BoolProperty(
default=False,
name="Optimal Display",
description="Skip drawing/rendering of interior subdivided edges "
"on meshes with Subdivision Surface modifier")
Pablo Vazquez
committed
def clear_properties():
props = (
"use_unsimplify_render",
"simplify_status",
"use_matching_indices",
"use_simplify_nodes_vector",
"status",
"types",
"toggle_mute",
"amaranth_cycles_node_types",
"amaranth_lighterscorner_list_meshlights",
"amaranth_debug_scene_list_missing_images",
"amarath_cycles_list_sampling",
"normal_vector",
"use_samples_final",
'amth_wire_toggle_is_selected',
'amth_wire_toggle_scene_all',
"amth_wire_toggle_edges_all",
"amth_wire_toggle_optimal"
Pablo Vazquez
committed
)
Pablo Vazquez
committed
wm = bpy.context.window_manager
for p in props:
if p in wm:
del wm[p]
# Some settings are bound to be saved on a startup py file
def amaranth_text_startup(context):
amth_text_name = "AmaranthStartup.py"
amth_text_exists = False
global amth_text
try:
if bpy.data.texts:
for tx in bpy.data.texts:
if tx.name == amth_text_name:
amth_text_exists = True
amth_text = bpy.data.texts[amth_text_name]
break
else:
amth_text_exists = False
if not amth_text_exists:
bpy.ops.text.new()
amth_text = bpy.data.texts[-1]
amth_text.name = amth_text_name
amth_text.write("# Amaranth Startup Script\nimport bpy\n\n")
amth_text.use_module = True
return amth_text_exists
except AttributeError:
return None
# FUNCTION: Check if material has Emission (for select and stats)
def cycles_is_emission(context, ob):
is_emission = False
if ob.material_slots:
for ma in ob.material_slots:
if ma.material:
if ma.material.node_tree and ma.material.node_tree.nodes:
for no in ma.material.node_tree.nodes:
if no.type in {'EMISSION', 'GROUP'}:
for ou in no.outputs:
if ou.links:
if no.type == 'GROUP' and no.node_tree and no.node_tree.nodes:
for gno in no.node_tree.nodes:
if gno.type == 'EMISSION':
for gou in gno.outputs:
if ou.links and gou.links:
is_emission = True
elif no.type == 'EMISSION':
if ou.links:
is_emission = True
return is_emission
# FUNCTION: Check if object has keyframes for a specific frame
def is_keyframe(ob, frame):
if ob is not None and ob.animation_data is not None and ob.animation_data.action is not None:
for fcu in ob.animation_data.action.fcurves:
if frame in (p.co.x for p in fcu.keyframe_points):
return True
return False
Pablo Vazquez
committed
# FEATURE: Refresh Scene!
Pablo Vazquez
committed
"""Refresh the current scene"""
bl_idname = "scene.refresh"
bl_label = "Refresh!"
Pablo Vazquez
committed
def execute(self, context):
preferences = context.user_preferences.addons[__name__].preferences
scene = context.scene
Pablo Vazquez
committed
# Changing the frame is usually the best way to go
scene.frame_current = scene.frame_current
self.report({"INFO"}, "Scene Refreshed!")
Pablo Vazquez
committed
return {'FINISHED'}
def button_refresh(self, context):
preferences = context.user_preferences.addons[__name__].preferences
if preferences.use_scene_refresh:
self.layout.separator()
self.layout.operator(
Pablo Vazquez
committed
text="Refresh!",
icon='FILE_REFRESH')
# // FEATURE: Refresh Scene!
# FEATURE: Save & Reload
def save_reload(self, context, path):
if path:
bpy.ops.wm.save_mainfile()
self.report({'INFO'}, "Saved & Reloaded")
bpy.ops.wm.open_mainfile("EXEC_DEFAULT", filepath=path)
else:
bpy.ops.wm.save_as_mainfile("INVOKE_AREA")
Pablo Vazquez
committed
"""Save and Reload the current blend file"""
bl_idname = "wm.save_reload"
bl_label = "Save & Reload"
def execute(self, context):
path = bpy.data.filepath
save_reload(self, context, path)
return {'FINISHED'}
def button_save_reload(self, context):
preferences = context.user_preferences.addons[__name__].preferences
if preferences.use_file_save_reload:
self.layout.separator()
self.layout.operator(
Pablo Vazquez
committed
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
text="Save & Reload",
icon='FILE_REFRESH')
# // FEATURE: Save & Reload
# FEATURE: Current Frame
def button_frame_current(self, context):
preferences = context.user_preferences.addons[__name__].preferences
scene = context.scene
if preferences.use_frame_current:
self.layout.separator()
self.layout.prop(
scene, "frame_current",
text="Set Current Frame")
# // FEATURE: Current Frame
# FEATURE: Timeline Time + Frames Left
def label_timeline_extra_info(self, context):
preferences = context.user_preferences.addons[__name__].preferences
layout = self.layout
scene = context.scene
if preferences.use_timeline_extra_info:
row = layout.row(align=True)
row.operator(AMTH_SCREEN_OT_keyframe_jump_inbetween.bl_idname, icon="PREV_KEYFRAME", text="").backwards = True
row.operator(AMTH_SCREEN_OT_keyframe_jump_inbetween.bl_idname, icon="NEXT_KEYFRAME", text="").backwards = False
Pablo Vazquez
committed
# Check for preview range
frame_start = scene.frame_preview_start if scene.use_preview_range else scene.frame_start
frame_end = scene.frame_preview_end if scene.use_preview_range else scene.frame_end
Pablo Vazquez
committed
row.label(text="%s / %s" % (bpy.utils.smpte_from_frame(scene.frame_current - frame_start),
bpy.utils.smpte_from_frame(frame_end - frame_start)))
if (scene.frame_current > frame_end):
row.label(text="%s Frames Ahead" % ((frame_end - scene.frame_current) * -1))
elif (scene.frame_current == frame_start):
row.label(text="Start Frame (%s left)" % (frame_end - scene.frame_current))
Pablo Vazquez
committed
elif (scene.frame_current == frame_end):
row.label(text="%s End Frame" % scene.frame_current)
else:
row.label(text="%s Frames Left" % (frame_end - scene.frame_current))
# // FEATURE: Timeline Time + Frames Left
# FEATURE: Directory Current Blend
class AMTH_FILE_OT_directory_current_blend(Operator):
Pablo Vazquez
committed
"""Go to the directory of the currently open blend file"""
bl_idname = "file.directory_current_blend"
bl_label = "Current Blend's Folder"
def execute(self, context):
bpy.ops.file.select_bookmark(dir='//')
return {'FINISHED'}
def button_directory_current_blend(self, context):
if bpy.data.filepath:
self.layout.operator(
Pablo Vazquez
committed
text="Current Blend's Folder",
icon='APPEND_BLEND')
# // FEATURE: Directory Current Blend
# FEATURE: Libraries panel on file browser
bl_space_type = 'FILE_BROWSER'
bl_region_type = 'CHANNELS'
bl_label = "Libraries"
def draw(self, context):
layout = self.layout
libs = bpy.data.libraries
libslist = []
# Build the list of folders from libraries
for lib in libs:
directory_name = os.path.dirname(lib.filepath)
libslist.append(directory_name)
# Remove duplicates and sort by name
libslist = set(libslist)
libslist = sorted(libslist)
# Draw the box with libs
row = layout.row()
box = row.box()
for filepath in libslist:
if filepath != '//':
row.alignment = 'LEFT'
props = row.operator(
text=filepath, icon="BOOKMARKS",
emboss=False)
props.filepath = filepath
else:
box.label(text='No libraries loaded')
"""Go to this library's directory"""
bl_idname = "file.directory_go_to"
bl_label = "Go To"
filepath = bpy.props.StringProperty(subtype="FILE_PATH")
def execute(self, context):
bpy.ops.file.select_bookmark(dir=self.filepath)
return {'FINISHED'}
Pablo Vazquez
committed
# FEATURE: Node Templates
class AMTH_NODE_OT_AddTemplateVignette(Operator):
Pablo Vazquez
committed
bl_idname = "node.template_add_vignette"
bl_label = "Add Vignette"
bl_description = "Add a vignette effect"
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
space = context.space_data
return space.type == 'NODE_EDITOR' \
and space.node_tree is not None \
and space.tree_type == 'CompositorNodeTree'
# used as reference the setup scene script from master nazgul
def _setupNodes(self, context):
scene = context.scene
space = context.space_data
tree = scene.node_tree
has_act = True if tree.nodes.active else False
Pablo Vazquez
committed
bpy.ops.node.select_all(action='DESELECT')
ellipse = tree.nodes.new(type='CompositorNodeEllipseMask')
ellipse.width = 0.8
ellipse.height = 0.4
blur = tree.nodes.new(type='CompositorNodeBlur')
blur.use_relative = True
blur.factor_x = 30
blur.factor_y = 50
ramp = tree.nodes.new(type='CompositorNodeValToRGB')
ramp.color_ramp.interpolation = 'B_SPLINE'
ramp.color_ramp.elements[1].color = (0.6, 0.6, 0.6, 1)
overlay = tree.nodes.new(type='CompositorNodeMixRGB')
overlay.blend_type = 'OVERLAY'
overlay.inputs[0].default_value = 0.8
overlay.inputs[1].default_value = (0.5, 0.5, 0.5, 1)
tree.links.new(ellipse.outputs["Mask"],blur.inputs["Image"])
tree.links.new(blur.outputs["Image"],ramp.inputs[0])
tree.links.new(ramp.outputs["Image"],overlay.inputs[2])
if has_act:
tree.links.new(tree.nodes.active.outputs[0],overlay.inputs[1])
Pablo Vazquez
committed
if has_act:
overlay.location = tree.nodes.active.location
overlay.location += Vector((350.0, 0.0))
Pablo Vazquez
committed
else:
overlay.location += Vector((space.cursor_location[0], space.cursor_location[1]))
ellipse.location = overlay.location
ellipse.location += Vector((-715.0, -400))
ellipse.inputs[0].hide = True
ellipse.inputs[1].hide = True
Pablo Vazquez
committed
blur.location = ellipse.location
blur.location += Vector((300.0, 0.0))
blur.inputs['Size'].hide = True
Pablo Vazquez
committed
ramp.location = blur.location
ramp.location += Vector((175.0, 0))
Pablo Vazquez
committed
for node in {ellipse, blur, ramp, overlay}:
node.select = True
node.show_preview = False
bpy.ops.node.join()
frame = ellipse.parent
frame.label = 'Vignette'
frame.use_custom_color = True
Pablo Vazquez
committed
overlay.parent = None
overlay.label = 'Vignette Overlay'
def execute(self, context):
self._setupNodes(context)
return {'FINISHED'}
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
class AMTH_NODE_OT_AddTemplateVectorBlur(Operator):
bl_idname = "node.template_add_vectorblur"
bl_label = "Add Vector Blur"
bl_description = "Add a vector blur filter"
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
space = context.space_data
tree = context.scene.node_tree
return space.type == 'NODE_EDITOR' \
and space.node_tree is not None \
and space.tree_type == 'CompositorNodeTree' \
and tree \
and tree.nodes.active \
and tree.nodes.active.type == 'R_LAYERS'
def _setupNodes(self, context):
scene = context.scene
space = context.space_data
tree = scene.node_tree
bpy.ops.node.select_all(action='DESELECT')
act_node = tree.nodes.active
rlayer = act_node.scene.render.layers[act_node.layer]
if not rlayer.use_pass_vector:
rlayer.use_pass_vector = True
vblur = tree.nodes.new(type='CompositorNodeVecBlur')
vblur.use_curved = True
vblur.factor = 0.5
tree.links.new(act_node.outputs["Image"],vblur.inputs["Image"])
tree.links.new(act_node.outputs["Z"],vblur.inputs["Z"])
tree.links.new(act_node.outputs["Speed"],vblur.inputs["Speed"])
if tree.nodes.active:
vblur.location = tree.nodes.active.location
vblur.location += Vector((250.0, 0.0))
else:
vblur.location += Vector((space.cursor_location[0], space.cursor_location[1]))
vblur.select = True
def execute(self, context):
self._setupNodes(context)
return {'FINISHED'}
Pablo Vazquez
committed
# Node Templates Menu
class AMTH_NODE_MT_amaranth_templates(Menu):
bl_idname = 'AMTH_NODE_MT_amaranth_templates'
Pablo Vazquez
committed
bl_space_type = 'NODE_EDITOR'
bl_label = "Templates"
bl_description = "List of Amaranth Templates"
def draw(self, context):
layout = self.layout
layout.operator(
AMTH_NODE_OT_AddTemplateVectorBlur.bl_idname,
text="Vector Blur",
icon='FORCE_HARMONIC')
Pablo Vazquez
committed
layout.operator(
Pablo Vazquez
committed
text="Vignette",
icon='COLOR')
def node_templates_pulldown(self, context):
if context.space_data.tree_type == 'CompositorNodeTree':
layout = self.layout
row = layout.row(align=True)
row.scale_x = 1.3
Pablo Vazquez
committed
# // FEATURE: Node Templates
def node_stats(self,context):
if context.scene.node_tree:
tree_type = context.space_data.tree_type
nodes = context.scene.node_tree.nodes
nodes_total = len(nodes.keys())
nodes_selected = 0
for n in nodes:
if n.select:
nodes_selected = nodes_selected + 1
if tree_type == 'CompositorNodeTree':
layout = self.layout
row = layout.row(align=True)
row.label(text="Nodes: %s/%s" % (nodes_selected, str(nodes_total)))
# FEATURE: Simplify Compo Nodes
Pablo Vazquez
committed
'''Simplify Compositor Panel'''
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'UI'
bl_label = 'Simplify'
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
space = context.space_data
return space.type == 'NODE_EDITOR' \
and space.node_tree is not None \
and space.tree_type == 'CompositorNodeTree'
Pablo Vazquez
committed
def draw(self, context):
layout = self.layout
node_tree = context.scene.node_tree
if node_tree is not None:
layout.prop(node_tree, 'types')
layout.operator(AMTH_NODE_OT_toggle_mute.bl_idname,
Pablo Vazquez
committed
text="Turn On" if node_tree.toggle_mute else "Turn Off",
icon='RESTRICT_VIEW_OFF' if node_tree.toggle_mute else 'RESTRICT_VIEW_ON')
Pablo Vazquez
committed
if node_tree.types == 'VECBLUR':
layout.label(text="This will also toggle the Vector pass {}".format(
"on" if node_tree.toggle_mute else "off"), icon="INFO")
Pablo Vazquez
committed
""""""
bl_idname = "node.toggle_mute"
bl_label = "Toggle Mute"
def execute(self, context):
scene = context.scene
node_tree = scene.node_tree
node_type = node_tree.types
rlayers = scene.render
Pablo Vazquez
committed
if not 'amaranth_pass_vector' in scene.keys():
scene['amaranth_pass_vector'] = []
Pablo Vazquez
committed
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
#can't extend() the list, so make a dummy one
pass_vector = scene['amaranth_pass_vector']
if not pass_vector:
pass_vector = []
if node_tree.toggle_mute:
for node in node_tree.nodes:
if node_type == 'ALL':
node.mute = node.status
if node.type == node_type:
node.mute = node.status
if node_type == 'VECBLUR':
for layer in rlayers.layers:
if layer.name in pass_vector:
layer.use_pass_vector = True
pass_vector.remove(layer.name)
node_tree.toggle_mute = False
else:
for node in node_tree.nodes:
if node_type == 'ALL':
node.mute = True
if node.type == node_type:
node.status = node.mute
node.mute = True
if node_type == 'VECBLUR':
for layer in rlayers.layers:
if layer.use_pass_vector:
pass_vector.append(layer.name)
layer.use_pass_vector = False
pass
node_tree.toggle_mute = True
# Write back to the custom prop
pass_vector = sorted(set(pass_vector))
scene['amaranth_pass_vector'] = pass_vector
return {'FINISHED'}
Pablo Vazquez
committed
# FEATURE: OB/MA ID panel in Node Editor
Pablo Vazquez
committed
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
'''Object / Material Indices Panel'''
bl_space_type = 'NODE_EDITOR'
bl_region_type = 'UI'
bl_label = 'Object / Material Indices'
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
node = context.active_node
return node and node.type == 'ID_MASK'
def draw(self, context):
layout = self.layout
objects = bpy.data.objects
materials = bpy.data.materials
node = context.active_node
show_ob_id = False
show_ma_id = False
matching_ids = False
if context.active_object:
ob_act = context.active_object
else:
ob_act = False
for ob in objects:
if ob and ob.pass_index > 0:
show_ob_id = True
for ma in materials:
if ma and ma.pass_index > 0:
show_ma_id = True
Pablo Vazquez
committed
row.prop(node, 'index', text="Mask Index")
row.prop(node, 'use_matching_indices', text="Only Matching IDs")
Pablo Vazquez
committed
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
layout.separator()
if not show_ob_id and not show_ma_id:
layout.label(text="No objects or materials indices so far.", icon="INFO")
if show_ob_id:
split = layout.split()
col = split.column()
col.label(text="Object Name")
split.label(text="ID Number")
row = layout.row()
for ob in objects:
icon = "OUTLINER_DATA_" + ob.type
if ob.library:
icon = "LIBRARY_DATA_DIRECT"
elif ob.is_library_indirect:
icon = "LIBRARY_DATA_INDIRECT"
if ob and node.use_matching_indices \
and ob.pass_index == node.index \
and ob.pass_index != 0:
matching_ids = True
row.label(
text="[{}]".format(ob.name)
if ob_act and ob.name == ob_act.name else ob.name,
icon=icon)
row.label(text="%s" % ob.pass_index)
row = layout.row()
elif ob and not node.use_matching_indices \
and ob.pass_index > 0:
matching_ids = True
row.label(
text="[{}]".format(ob.name)
if ob_act and ob.name == ob_act.name else ob.name,
icon=icon)
row.label(text="%s" % ob.pass_index)
row = layout.row()
if node.use_matching_indices and not matching_ids:
row.label(text="No objects with ID %s" % node.index, icon="INFO")
layout.separator()
if show_ma_id:
split = layout.split()
col = split.column()
col.label(text="Material Name")
split.label(text="ID Number")
row = layout.row()
for ma in materials:
icon = "BLANK1"
if ma.use_nodes:
icon = "NODETREE"
elif ma.library:
icon = "LIBRARY_DATA_DIRECT"
if ma.is_library_indirect:
icon = "LIBRARY_DATA_INDIRECT"
if ma and node.use_matching_indices \
and ma.pass_index == node.index \
and ma.pass_index != 0:
matching_ids = True
row.label(text="%s" % ma.name, icon=icon)
row.label(text="%s" % ma.pass_index)
row = layout.row()
elif ma and not node.use_matching_indices \
and ma.pass_index > 0:
matching_ids = True
row.label(text="%s" % ma.name, icon=icon)
row.label(text="%s" % ma.pass_index)
row = layout.row()
if node.use_matching_indices and not matching_ids:
row.label(text="No materials with ID %s" % node.index, icon="INFO")
# // FEATURE: OB/MA ID panel in Node Editor
# FEATURE: Unsimplify on render
@persistent
def unsimplify_render_pre(scene):
render = scene.render
scene.simplify_status = render.use_simplify
if scene.use_unsimplify_render:
render.use_simplify = False
@persistent
def unsimplify_render_post(scene):
render = scene.render
render.use_simplify = scene.simplify_status
def unsimplify_ui(self,context):
scene = bpy.context.scene
self.layout.prop(scene, 'use_unsimplify_render')
# //FEATURE: Unsimplify on render
# FEATURE: Extra Info Stats
def stats_scene(self, context):
preferences = context.user_preferences.addons[__name__].preferences
if preferences.use_scene_stats:
scenes_count = str(len(bpy.data.scenes))
cameras_count = str(len(bpy.data.cameras))
cameras_selected = 0
meshlights = 0
meshlights_visible = 0
Pablo Vazquez
committed
for ob in context.scene.objects:
if cycles_is_emission(context, ob):
meshlights += 1
if ob in context.visible_objects:
meshlights_visible += 1
Pablo Vazquez
committed
if ob in context.selected_objects:
if ob.type == 'CAMERA':
Pablo Vazquez
committed
meshlights_string = '| Meshlights:{}/{}'.format(meshlights_visible, meshlights)
Pablo Vazquez
committed
row = self.layout.row(align=True)
row.label(text="Scenes:{} | Cameras:{}/{} {}".format(
scenes_count, cameras_selected, cameras_count,
meshlights_string if context.scene.render.engine == 'CYCLES' else ''))
# //FEATURE: Extra Info Stats
# FEATURE: Camera Bounds as Render Border
class AMTH_VIEW3D_OT_render_border_camera(Operator):
Pablo Vazquez
committed
"""Set camera bounds as render border"""
bl_idname = "view3d.render_border_camera"
bl_label = "Camera as Render Border"
@classmethod
def poll(cls, context):
return context.space_data.region_3d.view_perspective == 'CAMERA'
def execute(self, context):
render = context.scene.render
render.use_border = True
render.border_min_x = 0
render.border_min_y = 0
render.border_max_x = 1
render.border_max_y = 1
return {'FINISHED'}
def button_render_border_camera(self, context):
view3d = context.space_data.region_3d
Pablo Vazquez
committed
if view3d.view_perspective == 'CAMERA':
layout = self.layout
layout.separator()
layout.operator(AMTH_VIEW3D_OT_render_border_camera.bl_idname,
Pablo Vazquez
committed
text="Camera as Render Border", icon="FULLSCREEN_ENTER")
# //FEATURE: Camera Bounds as Render Border
# FEATURE: Passepartout options on W menu
def button_camera_passepartout(self, context):
view3d = context.space_data.region_3d
cam = context.scene.camera.data
Pablo Vazquez
committed
if view3d.view_perspective == 'CAMERA':
layout = self.layout
if cam.show_passepartout:
layout.prop(cam, "passepartout_alpha", text="Passepartout")
else:
layout.prop(cam, "show_passepartout")
# FEATURE: Show Only Render with Alt+Shift+Z
Pablo Vazquez
committed
bl_idname = "view3d.show_only_render"
bl_label = "Show Only Render"
def execute(self, context):
space = bpy.context.space_data
Pablo Vazquez
committed
if space.show_only_render:
space.show_only_render = False