ABX/abx/std_lunatics_ink.py
Film Freedom Project 2b3f66baf4
Add files via upload
Initial commit of ABX development sources. The abx package itself is in the abx folder. The MakeAddOnZip.py script creates the archive to install into Blender in the pkg folder. The tests folder contains unit tests which require the contents of testdata as fixtures.
2021-05-17 14:24:14 -05:00

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()