ABX/abx/std_lunatics_ink.py

678 lines
27 KiB
Python

# std_lunatics_ink.py
"""
Functions to set up the standard ink and paint compositing arrangement
for "Lunatics"
"""
import os
import bpy, bpy.props, bpy.utils
# Hard-coded default parameters:
INK_THICKNESS = 3
INK_COLOR = (0,0,0)
THRU_INK_THICKNESS = 2
THRU_INK_COLOR = (20,100,50)
# TODO: probably should have a dialog somewhere that can change these through the UI?
class LunaticsShot(object):
"""
General class for Lunatics Blender Scene data.
"""
colorcode = {
'paint': (1.00, 1.00, 1.00),
'ink': (0.75, 0.50, 0.35),
'thru': (0.35, 0.50, 0.75),
'bb': (0.35, 0.75, 0.50),
'bbthru': (0.35, 0.75, 0.75),
'sky': (0.50, 0.25, 0.75),
'compos': (0.75, 0.75, 0.75),
'output': (0.35, 0.35, 0.35)
}
def __init__(self, scene, inkthru=False, billboards=False, sepsky=False):
self.scene = scene
self.inkthru = bool(inkthru)
self.billboards = bool(billboards)
self.sepsky = bool(sepsky)
self.series_id = scene.lunaprops.series_id
self.episode_id = scene.lunaprops.episode_id
self.seq_id = scene.lunaprops.seq_id
self.block_id = scene.lunaprops.block_id
self.shot_id = scene.lunaprops.shot_id
self.cam_id = scene.lunaprops.cam_id
self.shot_name = scene.lunaprops.shot_name
self.render_root = '//../../Renders/'
@property
def fullname(self):
return self.designation + '-' + self.name
@property
def designation(self):
episode_code = "%2.2sE%2.2d" % (self.series_id, self.episode_id)
return episode_code + '-' + self.shortname
@property
def shortname(self):
desig = str(self.seq_id) + '-' + str(self.block_id)
if self.cam_id:
desig = desig + '-Cam' + str(self.cam_id)
if self.shot_id:
desig = desig + '-' + str(self.shot_id)
return desig
@property
def scene_name(self):
if self.shot_name:
return self.shortname + ' ' + self.shot_name
else:
return self.shortname
def render_path(self, suffix='', framedigits=5, ext='png', rdr_fmt='PNG'):
if suffix:
suffix = '-' + suffix
if rdr_fmt in ('AVI', 'MKV'):
path = os.path.join(self.render_root, suffix,
self.designation + suffix + '.' + ext)
else:
path = os.path.join(self.render_root, suffix, self.designation,
self.designation + suffix + '-f' + '#'*framedigits + '.' + ext)
return path
def cfg_scene(self, scene=None, thru=True, exr=True, multicam=False, role='shot'):
if not scene:
scene = self.scene
scene.name = self.scene_name
scene.render.filepath = self.render_path()
#os.path.join(self.render_root, 'PNG', self.designation, self.designation + '-f#####.png')
scene.render.image_settings.file_format='PNG'
scene.render.image_settings.compression = 50
scene.render.image_settings.color_mode = 'RGB'
scene.render.use_freestyle = True
# Create Paint & Ink Render Layers
for rlayer in scene.render.layers:
rlayer.name = '~' + rlayer.name
rlayer.use = False
# Rename & turn off existing layers (but don't delete, in case they were wanted)
scene.render.layers.new('Paint')
self.cfg_paint(scene.render.layers['Paint'])
scene.render.layers.new('Ink')
self.cfg_ink(scene.render.layers['Ink'],
thickness=INK_THICKNESS, color=INK_COLOR)
if self.inkthru:
scene.render.layers.new('Ink-Thru')
self.cfg_ink(scene.render.layers['Ink-Thru'],
thickness=THRU_INK_THICKNESS, color=THRU_INK_COLOR)
if self.billboards:
scene.render.layers.new('BB-Alpha')
self.cfg_bbalpha(scene.render.layers['BB-Alpha'])
scene.render.layers.new('BB-Mat')
self.cfg_bbmat(scene.render.layers['BB-Mat'], thru=False)
if self.billboards and self.inkthru:
scene.render.layers.new('BB-Mat-Thru')
self.cfg_bbmat(scene.render.layers['BB-Mat-Thru'], thru=True)
if self.sepsky:
scene.render.layers.new('Sky')
self.cfg_sky(scene.render.layers['Sky'])
self.cfg_nodes(scene)
def _new_rlayer_in(self, name, scene, rlayer, location, color):
tree = scene.node_tree
rlayer_in = tree.nodes.new('CompositorNodeRLayers')
rlayer_in.name = '_'.join([n.lower() for n in name.split('-')])+'_in'
rlayer_in.label = name+'-In'
rlayer_in.scene = scene
rlayer_in.layer = rlayer
rlayer_in.color = color
rlayer_in.use_custom_color = True
rlayer_in.location = location
return rlayer_in
def cfg_nodes(self, scene):
# Create Compositing Node Tree
scene.use_nodes = True
tree = scene.node_tree
# clear default nodes
for node in tree.nodes:
tree.nodes.remove(node)
# Paint RenderLayer Nodes
paint_in = self._new_rlayer_in('Paint', scene, 'Paint',
(0,1720), self.colorcode['paint'])
if self.sepsky:
sky_in = self._new_rlayer_in('Sky', scene, 'Sky',
(0, 1200), self.colorcode['sky'])
# Configure EXR format
exr_paint = tree.nodes.new('CompositorNodeOutputFile')
exr_paint.name = 'exr_paint'
exr_paint.label = 'Paint EXR'
exr_paint.location = (300,1215)
exr_paint.color = self.colorcode['paint']
exr_paint.use_custom_color = True
exr_paint.format.file_format = 'OPEN_EXR_MULTILAYER'
exr_paint.format.color_mode = 'RGBA'
exr_paint.format.color_depth = '16'
exr_paint.format.exr_codec = 'ZIP'
exr_paint.base_path = os.path.join(self.render_root, 'EXR',
self.designation, self.designation + '-Paint-f#####' + '.exr')
if 'Image' in exr_paint.layer_slots:
exr_paint.layer_slots.remove(exr_paint.inputs['Image'])
# Create EXR layers and connect to render passes
rpasses = ['Image', 'Depth', 'Normal', 'Vector',
'Spec', 'Shadow','Reflect','Emit']
for rpass in rpasses:
exr_paint.layer_slots.new(rpass)
tree.links.new(paint_in.outputs[rpass], exr_paint.inputs[rpass])
if self.sepsky:
exr_paint.layer_slots.new('Sky')
tree.links.new(sky_in.outputs['Image'], exr_paint.inputs['Sky'])
# Ink RenderLayer Nodes
ink_in = self._new_rlayer_in('Ink', scene, 'Ink',
(590, 1275), self.colorcode['ink'])
if self.inkthru:
thru_in = self._new_rlayer_in('Thru', scene, 'Ink-Thru',
(590, 990), self.colorcode['thru'])
if self.billboards:
bb_in = self._new_rlayer_in('BB', scene, 'BB-Alpha',
(0, 870), self.colorcode['bb'])
bb_mat = self._new_rlayer_in('BB-Mat', scene, 'BB-Mat',
(0, 590), self.colorcode['bb'])
if self.inkthru and self.billboards:
bb_mat_thru = self._new_rlayer_in('BB-Mat-Thru', scene, 'BB-Mat-Thru',
(0, 280), self.colorcode['bbthru'])
# Ink EXR
exr_ink = tree.nodes.new('CompositorNodeOutputFile')
exr_ink.name = 'exr_ink'
exr_ink.label = 'Ink EXR'
exr_ink.location = (1150,700)
exr_ink.color = self.colorcode['ink']
exr_ink.use_custom_color = True
exr_ink.format.file_format = 'OPEN_EXR_MULTILAYER'
exr_ink.format.color_mode = 'RGBA'
exr_ink.format.color_depth = '16'
exr_ink.format.exr_codec = 'ZIP'
exr_ink.base_path = os.path.join(self.render_root, 'EXR',
self.designation, self.designation + '-Ink-f#####' + '.exr')
# Create EXR Ink layers and connect
if 'Image' in exr_ink.layer_slots:
exr_ink.layer_slots.remove(exr_ink.inputs['Image'])
exr_ink.layer_slots.new('Ink')
tree.links.new(ink_in.outputs['Image'], exr_ink.inputs['Ink'])
if self.inkthru:
exr_ink.layer_slots.new('Ink-Thru')
tree.links.new(thru_in.outputs['Image'], exr_ink.inputs['Ink-Thru'])
if self.billboards:
exr_ink.layer_slots.new('BB-Alpha')
tree.links.new(bb_in.outputs['Alpha'], exr_ink.inputs['BB-Alpha'])
exr_ink.layer_slots.new('BB-Mat')
tree.links.new(bb_mat.outputs['IndexMA'], exr_ink.inputs['BB-Mat'])
if self.inkthru and self.billboards:
exr_ink.layer_slots.new('BB-Mat-Thru')
tree.links.new(bb_mat_thru.outputs['IndexMA'], exr_ink.inputs['BB-Mat-Thru'])
# Preview Compositing
mix_shadow = tree.nodes.new('CompositorNodeMixRGB')
mix_shadow.name = 'mix_shadow'
mix_shadow.label = 'Mix-Shadow'
mix_shadow.location = (510,1820)
mix_shadow.color = self.colorcode['compos']
mix_shadow.use_custom_color = True
mix_shadow.blend_type = 'MULTIPLY'
mix_shadow.inputs['Fac'].default_value = 0.6
mix_shadow.use_clamp = True
tree.links.new(paint_in.outputs['Image'], mix_shadow.inputs[1])
tree.links.new(paint_in.outputs['Shadow'], mix_shadow.inputs[2])
mix_reflect = tree.nodes.new('CompositorNodeMixRGB')
mix_reflect.name = 'mix_reflect'
mix_reflect.label = 'Mix-Reflect'
mix_reflect.location = (910, 1620)
mix_reflect.color = self.colorcode['compos']
mix_reflect.use_custom_color = True
mix_reflect.blend_type = 'ADD'
mix_reflect.inputs['Fac'].default_value = 1.1
mix_reflect.use_clamp = True
tree.links.new(paint_in.outputs['Reflect'], mix_reflect.inputs[2])
mix_emit = tree.nodes.new('CompositorNodeMixRGB')
mix_emit.name = 'mix_emit'
mix_emit.label = 'Mix-Emit'
mix_emit.location = (1110, 1520)
mix_emit.blend_type = 'ADD'
mix_emit.inputs['Fac'].default_value = 1.1
mix_emit.use_clamp = True
tree.links.new(mix_reflect.outputs['Image'], mix_emit.inputs[1])
tree.links.new(paint_in.outputs['Emit'], mix_emit.inputs[2])
if self.sepsky:
sky_mix = tree.nodes.new('CompositorNodeMixRGB')
sky_mix.name = 'sky_mix'
sky_mix.label = 'Sky Mix'
sky_mix.location = (710,1720)
sky_mix.color = self.colorcode['sky']
sky_mix.use_custom_color = True
sky_mix.blend_type = 'MIX'
sky_mix.use_clamp = True
tree.links.new(sky_in.outputs['Image'], sky_mix.inputs[1])
tree.links.new(paint_in.outputs['Alpha'], sky_mix.inputs['Fac'])
tree.links.new(mix_shadow.outputs['Image'], sky_mix.inputs[2])
tree.links.new(sky_mix.outputs['Image'], mix_reflect.inputs[1])
else:
tree.links.new(mix_shadow.outputs['Image'], mix_reflect.inputs[1])
if self.billboards:
mat_idx = tree.nodes.new('CompositorNodeIDMask')
mat_idx.name = "mat_idx"
mat_idx.label = "BB-ID"
mat_idx.location = (260, 670)
mat_idx.index = 1
mat_idx.use_antialiasing = True
mat_idx.color = self.colorcode['bb']
mat_idx.use_custom_color = True
tree.links.new(bb_mat.outputs['IndexMA'], mat_idx.inputs['ID value'])
combine_bb_ma = tree.nodes.new('CompositorNodeMath')
combine_bb_ma.name = 'combine_bb_ma'
combine_bb_ma.label = 'Material x BB'
combine_bb_ma.location = (440,670)
combine_bb_ma.color = self.colorcode['bb']
combine_bb_ma.use_custom_color = True
combine_bb_ma.operation = 'MULTIPLY'
combine_bb_ma.use_clamp = True
tree.links.new(mat_idx.outputs['Alpha'], combine_bb_ma.inputs[0])
tree.links.new(bb_in.outputs['Alpha'], combine_bb_ma.inputs[1])
invert_bb_mask = tree.nodes.new('CompositorNodeInvert')
invert_bb_mask.name = 'invert_bb_mask'
invert_bb_mask.label = 'Invert Mask'
invert_bb_mask.location = (650,670)
invert_bb_mask.color = self.colorcode['bb']
invert_bb_mask.use_custom_color = True
invert_bb_mask.invert_rgb = True
tree.links.new(combine_bb_ma.outputs['Value'], invert_bb_mask.inputs['Color'])
bb_ink_mask = tree.nodes.new('CompositorNodeMath')
bb_ink_mask.name = 'bb_ink_mask'
bb_ink_mask.label = 'BB Ink Mask'
bb_ink_mask.location = (1150,1315)
bb_ink_mask.color = self.colorcode['bb']
bb_ink_mask.use_custom_color = True
bb_ink_mask.operation = 'MULTIPLY'
bb_ink_mask.use_clamp = True
tree.links.new(invert_bb_mask.outputs['Color'], bb_ink_mask.inputs[0])
blur_ink = tree.nodes.new('CompositorNodeBlur')
blur_ink.name = 'blur_ink'
blur_ink.label = 'Blur-Ink'
blur_ink.location = (1620, 1110)
blur_ink.color = self.colorcode['ink']
blur_ink.use_custom_color = True
blur_ink.filter_type = 'FAST_GAUSS'
blur_ink.size_x = 1.0
blur_ink.size_y = 1.0
blur_ink.use_extended_bounds = False
blur_ink.inputs['Size'].default_value = 1.0
if self.inkthru:
merge_ink_ao = tree.nodes.new('CompositorNodeAlphaOver')
merge_ink_ao.name = 'merge_ink'
merge_ink_ao.label = 'Merge-Ink'
merge_ink_ao.location = (1150,910)
merge_ink_ao.color = self.colorcode['thru']
merge_ink_ao.use_custom_color = True
merge_ink_ao.use_premultiply = False
merge_ink_ao.premul = 0.0
merge_ink_ao.inputs['Fac'].default_value = 1.0
tree.links.new(ink_in.outputs['Image'], merge_ink_ao.inputs[1])
tree.links.new(thru_in.outputs['Image'], merge_ink_ao.inputs[2])
tree.links.new(merge_ink_ao.outputs['Image'], blur_ink.inputs['Image'])
else:
tree.links.new(ink_in.outputs['Image'], blur_ink.inputs['Image'])
overlay_ink = tree.nodes.new('CompositorNodeAlphaOver')
overlay_ink.name = 'Overlay Ink'
overlay_ink.label = 'Overlay Ink'
overlay_ink.location = (1820,1315)
overlay_ink.color = self.colorcode['compos']
overlay_ink.use_custom_color = True
overlay_ink.use_premultiply = False
overlay_ink.premul = 0.0
overlay_ink.inputs['Fac'].default_value = 1.0
tree.links.new(mix_emit.outputs['Image'], overlay_ink.inputs[1])
tree.links.new(blur_ink.outputs['Image'], overlay_ink.inputs[2])
if self.billboards:
tree.links.new(ink_in.outputs['Alpha'], bb_ink_mask.inputs[1])
tree.links.new(bb_ink_mask.outputs['Value'], overlay_ink.inputs['Fac'])
if self.inkthru and self.billboards:
mat_idx_thru = tree.nodes.new('CompositorNodeIDMask')
mat_idx_thru.name = "mat_idx_thru"
mat_idx_thru.label = "BB-ID-Thru"
mat_idx_thru.location = (260, 425)
mat_idx_thru.index = 1
mat_idx_thru.use_antialiasing = True
mat_idx_thru.color = self.colorcode['bbthru']
mat_idx_thru.use_custom_color = True
tree.links.new(bb_mat_thru.outputs['IndexMA'], mat_idx_thru.inputs['ID value'])
combine_bbthru_ma = tree.nodes.new('CompositorNodeMath')
combine_bbthru_ma.name = 'combine_bbthru_ma'
combine_bbthru_ma.label = 'Material x BB-Thru'
combine_bbthru_ma.location = (440,425)
combine_bbthru_ma.color = self.colorcode['bbthru']
combine_bbthru_ma.use_custom_color = True
combine_bbthru_ma.operation = 'MULTIPLY'
combine_bbthru_ma.use_clamp = True
tree.links.new(mat_idx_thru.outputs['Alpha'], combine_bbthru_ma.inputs[0])
tree.links.new(bb_in.outputs['Alpha'], combine_bbthru_ma.inputs[1])
invert_bbthru_mask = tree.nodes.new('CompositorNodeInvert')
invert_bbthru_mask.name = 'invert_bbthru_mask'
invert_bbthru_mask.label = 'Invert Mask'
invert_bbthru_mask.location = (650,425)
invert_bbthru_mask.color = self.colorcode['bbthru']
invert_bbthru_mask.use_custom_color = True
invert_bbthru_mask.invert_rgb = True
tree.links.new(combine_bbthru_ma.outputs['Value'], invert_bbthru_mask.inputs['Color'])
bb_thru_mask = tree.nodes.new('CompositorNodeMath')
bb_thru_mask.name = 'bb_thru_mask'
bb_thru_mask.label = 'BB Ink Thru Mask'
bb_thru_mask.location = (1150,1115)
bb_thru_mask.color = self.colorcode['bbthru']
bb_thru_mask.use_custom_color = True
bb_thru_mask.operation = 'MULTIPLY'
bb_thru_mask.use_clamp = True
tree.links.new(thru_in.outputs['Alpha'], bb_thru_mask.inputs[0])
tree.links.new(invert_bbthru_mask.outputs['Color'], bb_thru_mask.inputs[1])
merge_bb_ink_masks = tree.nodes.new('CompositorNodeMath')
merge_bb_ink_masks.name = 'merge_bb_ink_masks'
merge_bb_ink_masks.label = 'Merge BB Ink Masks'
merge_bb_ink_masks.location = (1415, 1215)
merge_bb_ink_masks.color = self.colorcode['bbthru']
merge_bb_ink_masks.use_custom_color = True
merge_bb_ink_masks.operation = 'ADD'
merge_bb_ink_masks.use_clamp = True
tree.links.new(bb_ink_mask.outputs['Value'], merge_bb_ink_masks.inputs[0])
tree.links.new(bb_thru_mask.outputs['Value'], merge_bb_ink_masks.inputs[1])
tree.links.new(merge_bb_ink_masks.outputs['Value'], overlay_ink.inputs['Fac'])
composite = tree.nodes.new('CompositorNodeComposite')
composite.name = 'Composite'
composite.label = 'Preview Render'
composite.location = (2050,1215)
composite.color = self.colorcode['output']
composite.use_custom_color = True
composite.use_alpha = True
composite.inputs['Alpha'].default_value = 1.0
composite.inputs['Z'].default_value = 1.0
tree.links.new(overlay_ink.outputs['Image'], composite.inputs['Image'])
def _cfg_renderlayer(self, rlayer,
includes=False, passes=False, excludes=False,
layers=range(20)):
# Utility to set all the includes and passes on or off, initially
# Weird Includes (we never use these -- always have to turn these on explicitly)
rlayer.use_zmask = False
rlayer.invert_zmask = False
rlayer.use_all_z = False
# Includes
rlayer.use_solid = includes
rlayer.use_halo = includes
rlayer.use_ztransp = includes
rlayer.use_sky = includes
rlayer.use_edge_enhance = includes
rlayer.use_strand = includes
rlayer.use_freestyle = includes
# Passes
rlayer.use_pass_combined = passes
rlayer.use_pass_z = passes
rlayer.use_pass_vector = passes
rlayer.use_pass_normal = passes
rlayer.use_pass_uv = passes
rlayer.use_pass_mist = passes
rlayer.use_pass_object_index = passes
rlayer.use_pass_material_index = passes
rlayer.use_pass_color = passes
rlayer.use_pass_diffuse = passes
rlayer.use_pass_specular = passes
rlayer.use_pass_shadow = passes
rlayer.use_pass_emit = passes
rlayer.use_pass_ambient_occlusion = passes
rlayer.use_pass_environment = passes
rlayer.use_pass_indirect = passes
rlayer.use_pass_reflection = passes
rlayer.use_pass_refraction = passes
# Exclusions
rlayer.exclude_specular = excludes
rlayer.exclude_shadow = excludes
rlayer.exclude_emit = excludes
rlayer.exclude_ambient_occlusion = excludes
rlayer.exclude_environment = excludes
rlayer.exclude_indirect = excludes
rlayer.exclude_reflection = excludes
rlayer.exclude_refraction = excludes
for i in range(20):
if i in layers:
rlayer.layers[i] = True
else:
rlayer.layers[i] = False
def cfg_paint(self, paint_layer, name="Paint"):
self._cfg_renderlayer(paint_layer,
includes=True, passes=False, excludes=False,
layers = (0,1,2,3,4, 5,6,7, 10,11,12,13,14))
# Includes
if self.sepsky:
paint_layer.use_sky = False
paint_layer.use_freestyle = False
# Passes
paint_layer.use_pass_combined = True
paint_layer.use_pass_z = True
paint_layer.use_pass_vector = True
paint_layer.use_pass_normal = True
paint_layer.use_pass_shadow = True
paint_layer.exclude_shadow = True
paint_layer.use_pass_emit = True
paint_layer.exclude_emit = True
paint_layer.use_pass_specular = True
paint_layer.exclude_specular = True
paint_layer.use_pass_reflection = True
paint_layer.exclude_reflection = True
def cfg_bbalpha(self, bb_render_layer):
self._cfg_renderlayer(bb_render_layer,
includes=False, passes=False, excludes=False,
layers=(5,6, 14))
# Includes
bb_render_layer.use_solid = True
bb_render_layer.use_ztransp = True
# Passes
bb_render_layer.use_pass_combined = True
def cfg_bbmat(self, bb_mat_layer, thru=False):
self._cfg_renderlayer(bb_mat_layer,
includes=False, passes=False, excludes=False,
layers=(0,1,2,3, 5,6,7, 10,11,12,13,14, 15,16))
# Includes
bb_mat_layer.use_solid = True
bb_mat_layer.use_ztransp = True
# Passes
bb_mat_layer.use_pass_combined = True
bb_mat_layer.use_pass_material_index = True
if not thru:
bb_mat_layer.layers[4] = True
def cfg_sky(self, sky_render_layer):
self._cfg_renderlayer(sky_render_layer,
includes=False, passes=False, excludes=False,
layers=(0,1,2,3,4, 5,6,7, 10,11,12,13,14))
# Includes
sky_render_layer.use_sky = True
# Passes
sky_render_layer.use_pass_combined = True
def cfg_ink(self, ink_layer, name="Ink", thickness=3, color=(0,0,0)):
self._cfg_renderlayer(ink_layer,
includes=False, passes=False, excludes=False,
layers=(0,1,2,3, 5,6,7, 10,11,12,13, 15,16))
# Includes
ink_layer.use_freestyle = True
# Passes
ink_layer.use_pass_combined = True
# Freestyle
ink_layer.freestyle_settings.crease_angle = 2.617944
ink_layer.freestyle_settings.use_smoothness = True
ink_layer.freestyle_settings.use_culling = True
if len(ink_layer.freestyle_settings.linesets)>0:
ink_layer.freestyle_settings.linesets[0].name = name
else:
ink_layer.freestyle_settings.linesets.new(name)
lineset = ink_layer.freestyle_settings.linesets[name]
self.cfg_lineset(lineset, thickness, color)
# Turn on the transparency layer for the regular ink:
if ink_layer.name!='Ink-Thru':
ink_layer.layers[4] = True
def cfg_lineset(self, lineset, thickness=3, color=(0,0,0)):
"""
Configure the lineset.
"""
#lineset.name = 'NormalInk'
# Selection options
lineset.select_by_visibility = True
lineset.select_by_edge_types = True
lineset.select_by_image_border = True
lineset.select_by_face_marks = False
lineset.select_by_group = True
# Visibility Option
lineset.visibility = 'VISIBLE'
# Edge Type Options
lineset.edge_type_negation = 'INCLUSIVE'
lineset.edge_type_combination = 'OR'
lineset.select_silhouette = True
lineset.select_border = True
lineset.select_contour = True
lineset.select_crease = True
lineset.select_edge_mark = True
lineset.select_external_contour = True
# No Freestyle Group (If it exists)
if 'No Freestyle' in bpy.data.groups:
lineset.select_by_group = True
lineset.group = bpy.data.groups['No Freestyle']
lineset.group_negation = 'EXCLUSIVE'
else:
lineset.select_by_group = False
# Basic Ink linestyle:
if 'Ink' in bpy.data.linestyles:
lineset.linestyle = bpy.data.linestyles['Ink']
else:
lineset.linestyle.name = 'Ink'
self.cfg_linestyle(lineset.linestyle, thickness, color)
def cfg_linestyle(self, linestyle, thickness=INK_THICKNESS, color=INK_COLOR):
# These are the only changeable parameters:
linestyle.color = color
linestyle.thickness = thickness
# The rest of this function just sets a common fixed style for "Lunatics!"
linestyle.alpha = 1.0
linestyle.thickness_position = 'CENTER'
linestyle.use_chaining = True
linestyle.chaining = 'PLAIN'
linestyle.use_same_object = True
linestyle.caps = 'ROUND'
# ADD THE ALONG-STROKE MODIFIER CURVE
# TODO: try using the .new(type=...) idiom to see if it works?
# This probably needs the scene context set?
# bpy.ops.scene.freestyle_thickness_modifier_add(type='ALONG_STROKE')
linestyle.thickness_modifiers.new(type='ALONG_STROKE', name='taper')
linestyle.thickness_modifiers['taper'].blend = 'MULTIPLY'
linestyle.thickness_modifiers['taper'].mapping = 'CURVE'
# These are defaults, so maybe unnecessary?
linestyle.thickness_modifiers['taper'].influence = 1.0
linestyle.thickness_modifiers['taper'].invert = False
linestyle.thickness_modifiers['taper'].value_min = 0.0
linestyle.thickness_modifiers['taper'].value_max = 1.0
# This API is awful, but what it has to do is to change the location of the first two
# points (which can't be removed), then add a third point. Then update to pick up the
# changes:
linestyle.thickness_modifiers['taper'].curve.curves[0].points[0].location = (0.0,0.0)
linestyle.thickness_modifiers['taper'].curve.curves[0].points[1].location = (0.5,1.0)
linestyle.thickness_modifiers['taper'].curve.curves[0].points.new(1.0,0.0)
linestyle.thickness_modifiers['taper'].curve.update()