def from_lineset(cls, lineset, filepath, res_y, split_at_invisible, use_stroke_color, frame_current, *, name=""): """Builds a SVGPathShader using data from the given lineset""" name = name or lineset.name linestyle = lineset.linestyle # extract style attributes from the linestyle and scene svg = getCurrentScene().svg_export style = { 'fill': 'none', 'stroke-width': linestyle.thickness, 'stroke-linecap': linestyle.caps.lower(), 'stroke-opacity': linestyle.alpha, 'stroke': format_rgb(linestyle.color), 'stroke-linejoin': svg.line_join_type.lower(), } # get dashed line pattern (if specified) if linestyle.use_dashed_line: style['stroke-dasharray'] = ",".join( str(elem) for elem in get_dashed_pattern(linestyle)) # return instance return cls(name, style, filepath, res_y, split_at_invisible, use_stroke_color, frame_current)
def __init__(self, blend, influence, mapping, invert, curve, target, range_min, range_max): CurveMappingModifier.__init__(self, blend, influence, mapping, invert, curve) if target is None: raise ValueError("AlphaDistanceFromObjectShader: target can't be None ") self.range = BoundedProperty(range_min, range_max, range_max - range_min) # construct a model-view matrix matrix = getCurrentScene().camera.matrix_world.inverted() # get the object location in the camera coordinate self.loc = matrix * target.location
def __init__(self, blend, influence, ramp, target, range_min, range_max): ColorRampModifier.__init__(self, blend, influence, ramp) if target is None: raise ValueError("ColorDistanceFromObjectShader: target can't be None ") self.range = Range(range_min, range_max, range_max - range_min) # construct a model-view matrix matrix = getCurrentScene().camera.matrix_world.inverted() # get the object location in the camera coordinate self.loc = matrix * target.location
def __init__(self, thickness_position, thickness_ratio, blend, influence, mapping, invert, curve, target, range_min, range_max, value_min, value_max): ThicknessBlenderMixIn.__init__(self, thickness_position, thickness_ratio) CurveMappingModifier.__init__(self, blend, influence, mapping, invert, curve) if target is None: raise ValueError("ThicknessDistanceFromObjectShader: target can't be None ") self.range = Range(range_min, range_max, range_max - range_min) self.value = Value(value_min, value_max, value_max - value_min) # construct a model-view matrix matrix = getCurrentScene().camera.matrix_world.inverted() # get the object location in the camera coordinate self.loc = matrix * target.location
def from_lineset(cls, lineset, filepath, res_y, split_at_invisible, frame_current, *, name=""): """Builds a SVGPathShader using data from the given lineset""" name = name or lineset.name linestyle = lineset.linestyle # extract style attributes from the linestyle and scene svg = getCurrentScene().svg_export style = { 'fill': 'none', 'stroke-width': linestyle.thickness, 'stroke-linecap': linestyle.caps.lower(), 'stroke-opacity': linestyle.alpha, 'stroke': 'rgb({}, {}, {})'.format(*(int(c * 255) for c in linestyle.color)), 'stroke-linejoin': svg.line_join_type.lower(), } # get dashed line pattern (if specified) if linestyle.use_dashed_line: style['stroke-dasharray'] = ",".join(str(elem) for elem in get_dashed_pattern(linestyle)) # return instance return cls(name, style, filepath, res_y, split_at_invisible, frame_current)
def postprocess(frame_start=None, frame_end=None, interval=0): """ frame_start: the start frame (default Scene.frame_start) frame_end: the end frame (default: Scene.frame_end) interval: the number of frames inserted as interval between two strokes """ totlen = 0.0 nstrokes = Operators.get_strokes_size() #print('#strokes', nstrokes) for i in range(nstrokes): stroke = Operators.get_stroke_from_index(i) totlen += stroke.length_2d #print('totlen', totlen) scene = getCurrentScene() sta = scene.frame_start if frame_start is None else frame_start end = scene.frame_end if frame_end is None else frame_end cur = scene.frame_current fac = (cur - sta) / (end - sta) #print('fac', fac) totDrawingFrames = (end - sta + 1) - interval * (nstrokes - 1) if totDrawingFrames < 0: raise RuntimeError('The number of frames is too small') lengthPerFrame = totlen / totDrawingFrames #print('lengthPerFrame', lengthPerFrame) thresh = (cur - sta + 1) * lengthPerFrame + 1e-6 #print('thresh', thresh) curlen = 0.0 for i in range(nstrokes): stroke = Operators.get_stroke_from_index(i) for svert in stroke: svert.attribute.visible = curlen + svert.curvilinear_abscissa < thresh curlen += stroke.length_2d + lengthPerFrame * interval #print('done')
def postprocess(frame_start=None, frame_end=None, interval=0): """ frame_start: the start frame (default Scene.frame_start) frame_end: the end frame (default: Scene.frame_end) interval: the number of frames inserted as interval between two strokes """ totlen = 0.0 nstrokes = Operators.get_strokes_size() #print('#strokes', nstrokes) for i in range(nstrokes): stroke = Operators.get_stroke_from_index(i) totlen += stroke.length_2d #print('totlen', totlen) scene = getCurrentScene() sta = scene.frame_start if frame_start is None else frame_start end = scene.frame_end if frame_end is None else frame_end cur = scene.frame_current fac = (cur - sta) / (end - sta) #print('fac', fac) totDrawingFrames = (end - sta + 1) - interval * (nstrokes - 1) if totDrawingFrames < 0: raise RuntimeError('The number of frames is too small') lengthPerFrame = totlen / totDrawingFrames #print('lengthPerFrame', lengthPerFrame) thresh = (cur - sta + 1) * lengthPerFrame + 1e-6 #print('thresh', thresh) curlen = 0.0 for i in range(nstrokes): stroke = Operators.get_stroke_from_index(i) for svert in stroke: svert.attribute.visible = curlen + svert.curvilinear_abscissa < thresh curlen += stroke.length_2d + lengthPerFrame * interval
def process(layer_name, lineset_name): scene = getCurrentScene() layer = scene.render.layers[layer_name] lineset = layer.freestyle_settings.linesets[lineset_name] linestyle = lineset.linestyle selection_criteria = [] # prepare selection criteria by visibility if lineset.select_by_visibility: if lineset.visibility == 'VISIBLE': selection_criteria.append( QuantitativeInvisibilityUP1D(0)) elif lineset.visibility == 'HIDDEN': selection_criteria.append( NotUP1D(QuantitativeInvisibilityUP1D(0))) elif lineset.visibility == 'RANGE': selection_criteria.append( QuantitativeInvisibilityRangeUP1D(lineset.qi_start, lineset.qi_end)) # prepare selection criteria by edge types if lineset.select_by_edge_types: edge_type_criteria = [] if lineset.select_silhouette: upred = pyNatureUP1D(Nature.SILHOUETTE) edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_silhouette else upred) if lineset.select_border: upred = pyNatureUP1D(Nature.BORDER) edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_border else upred) if lineset.select_crease: upred = pyNatureUP1D(Nature.CREASE) edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_crease else upred) if lineset.select_ridge_valley: upred = pyNatureUP1D(Nature.RIDGE) edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_ridge_valley else upred) if lineset.select_suggestive_contour: upred = pyNatureUP1D(Nature.SUGGESTIVE_CONTOUR) edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_suggestive_contour else upred) if lineset.select_material_boundary: upred = pyNatureUP1D(Nature.MATERIAL_BOUNDARY) edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_material_boundary else upred) if lineset.select_edge_mark: upred = pyNatureUP1D(Nature.EDGE_MARK) edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_edge_mark else upred) if lineset.select_contour: upred = ContourUP1D() edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_contour else upred) if lineset.select_external_contour: upred = ExternalContourUP1D() edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_external_contour else upred) if lineset.edge_type_combination == 'OR': upred = OrUP1D(*edge_type_criteria) else: upred = AndUP1D(*edge_type_criteria) if upred is not None: if lineset.edge_type_negation == 'EXCLUSIVE': upred = NotUP1D(upred) selection_criteria.append(upred) # prepare selection criteria by face marks if lineset.select_by_face_marks: if lineset.face_mark_condition == 'BOTH': upred = FaceMarkBothUP1D() else: upred = FaceMarkOneUP1D() if lineset.face_mark_negation == 'EXCLUSIVE': upred = NotUP1D(upred) selection_criteria.append(upred) # prepare selection criteria by group of objects if lineset.select_by_group: if lineset.group is not None: names = {ob.name: True for ob in lineset.group.objects} upred = ObjectNamesUP1D(names, lineset.group_negation == 'EXCLUSIVE') selection_criteria.append(upred) # prepare selection criteria by image border if lineset.select_by_image_border: upred = WithinImageBoundaryUP1D(*ContextFunctions.get_border()) selection_criteria.append(upred) # select feature edges upred = AndUP1D(*selection_criteria) if upred is None: upred = TrueUP1D() Operators.select(upred) # join feature edges to form chains if linestyle.use_chaining: if linestyle.chaining == 'PLAIN': if linestyle.use_same_object: Operators.bidirectional_chain(ChainSilhouetteIterator(), NotUP1D(upred)) else: Operators.bidirectional_chain(ChainPredicateIterator(upred, TrueBP1D()), NotUP1D(upred)) elif linestyle.chaining == 'SKETCHY': if linestyle.use_same_object: Operators.bidirectional_chain(pySketchyChainSilhouetteIterator(linestyle.rounds)) else: Operators.bidirectional_chain(pySketchyChainingIterator(linestyle.rounds)) else: Operators.chain(ChainPredicateIterator(FalseUP1D(), FalseBP1D()), NotUP1D(upred)) # split chains if linestyle.material_boundary: Operators.sequential_split(MaterialBoundaryUP0D()) if linestyle.use_angle_min or linestyle.use_angle_max: angle_min = linestyle.angle_min if linestyle.use_angle_min else None angle_max = linestyle.angle_max if linestyle.use_angle_max else None Operators.sequential_split(Curvature2DAngleThresholdUP0D(angle_min, angle_max)) if linestyle.use_split_length: Operators.sequential_split(Length2DThresholdUP0D(linestyle.split_length), 1.0) if linestyle.use_split_pattern: pattern = [] if linestyle.split_dash1 > 0 and linestyle.split_gap1 > 0: pattern.append(linestyle.split_dash1) pattern.append(linestyle.split_gap1) if linestyle.split_dash2 > 0 and linestyle.split_gap2 > 0: pattern.append(linestyle.split_dash2) pattern.append(linestyle.split_gap2) if linestyle.split_dash3 > 0 and linestyle.split_gap3 > 0: pattern.append(linestyle.split_dash3) pattern.append(linestyle.split_gap3) if len(pattern) > 0: sampling = 1.0 controller = SplitPatternController(pattern, sampling) Operators.sequential_split(SplitPatternStartingUP0D(controller), SplitPatternStoppingUP0D(controller), sampling) # sort selected chains if linestyle.use_sorting: integration = integration_types.get(linestyle.integration_type, IntegrationType.MEAN) if linestyle.sort_key == 'DISTANCE_FROM_CAMERA': bpred = pyZBP1D(integration) elif linestyle.sort_key == '2D_LENGTH': bpred = Length2DBP1D() elif linestyle.sort_key == 'PROJECTED_X': bpred = pyProjectedXBP1D(integration) elif linestyle.sort_key == 'PROJECTED_Y': bpred = pyProjectedYBP1D(integration) if linestyle.sort_order == 'REVERSE': bpred = NotBP1D(bpred) Operators.sort(bpred) # select chains if linestyle.use_length_min or linestyle.use_length_max: length_min = linestyle.length_min if linestyle.use_length_min else None length_max = linestyle.length_max if linestyle.use_length_max else None Operators.select(LengthThresholdUP1D(length_min, length_max)) if linestyle.use_chain_count: Operators.select(pyNFirstUP1D(linestyle.chain_count)) # prepare a list of stroke shaders shaders_list = [] for m in linestyle.geometry_modifiers: if not m.use: continue if m.type == 'SAMPLING': shaders_list.append(SamplingShader( m.sampling)) elif m.type == 'BEZIER_CURVE': shaders_list.append(BezierCurveShader( m.error)) elif m.type == 'SINUS_DISPLACEMENT': shaders_list.append(SinusDisplacementShader( m.wavelength, m.amplitude, m.phase)) elif m.type == 'SPATIAL_NOISE': shaders_list.append(SpatialNoiseShader( m.amplitude, m.scale, m.octaves, m.smooth, m.use_pure_random)) elif m.type == 'PERLIN_NOISE_1D': shaders_list.append(PerlinNoise1DShader( m.frequency, m.amplitude, m.octaves, m.angle, _seed.get(m.seed))) elif m.type == 'PERLIN_NOISE_2D': shaders_list.append(PerlinNoise2DShader( m.frequency, m.amplitude, m.octaves, m.angle, _seed.get(m.seed))) elif m.type == 'BACKBONE_STRETCHER': shaders_list.append(BackboneStretcherShader( m.backbone_length)) elif m.type == 'TIP_REMOVER': shaders_list.append(TipRemoverShader( m.tip_length)) elif m.type == 'POLYGONIZATION': shaders_list.append(PolygonalizationShader( m.error)) elif m.type == 'GUIDING_LINES': shaders_list.append(GuidingLinesShader( m.offset)) elif m.type == 'BLUEPRINT': if m.shape == 'CIRCLES': shaders_list.append(pyBluePrintCirclesShader( m.rounds, m.random_radius, m.random_center)) elif m.shape == 'ELLIPSES': shaders_list.append(pyBluePrintEllipsesShader( m.rounds, m.random_radius, m.random_center)) elif m.shape == 'SQUARES': shaders_list.append(pyBluePrintSquaresShader( m.rounds, m.backbone_length, m.random_backbone)) elif m.type == '2D_OFFSET': shaders_list.append(Offset2DShader( m.start, m.end, m.x, m.y)) elif m.type == '2D_TRANSFORM': shaders_list.append(Transform2DShader( m.pivot, m.scale_x, m.scale_y, m.angle, m.pivot_u, m.pivot_x, m.pivot_y)) # -- Base color, alpha and thickness -- # if (not linestyle.use_chaining) or (linestyle.chaining == 'PLAIN' and linestyle.use_same_object): thickness_position = linestyle.thickness_position else: thickness_position = 'CENTER' import bpy if bpy.app.debug_freestyle: print("Warning: Thickness position options are applied when chaining is disabled\n" " or the Plain chaining is used with the Same Object option enabled.") shaders_list.append(ConstantColorShader(*(linestyle.color), alpha=linestyle.alpha)) shaders_list.append(BaseThicknessShader(linestyle.thickness, thickness_position, linestyle.thickness_ratio)) # -- Modifiers -- # for m in linestyle.color_modifiers: if not m.use: continue if m.type == 'ALONG_STROKE': shaders_list.append(ColorAlongStrokeShader( m.blend, m.influence, m.color_ramp)) elif m.type == 'DISTANCE_FROM_CAMERA': shaders_list.append(ColorDistanceFromCameraShader( m.blend, m.influence, m.color_ramp, m.range_min, m.range_max)) elif m.type == 'DISTANCE_FROM_OBJECT' and m.target is not None: shaders_list.append(ColorDistanceFromObjectShader( m.blend, m.influence, m.color_ramp, m.target, m.range_min, m.range_max)) elif m.type == 'MATERIAL': shaders_list.append(ColorMaterialShader( m.blend, m.influence, m.color_ramp, m.material_attribute, m.use_ramp)) for m in linestyle.alpha_modifiers: if not m.use: continue if m.type == 'ALONG_STROKE': shaders_list.append(AlphaAlongStrokeShader( m.blend, m.influence, m.mapping, m.invert, m.curve)) elif m.type == 'DISTANCE_FROM_CAMERA': shaders_list.append(AlphaDistanceFromCameraShader( m.blend, m.influence, m.mapping, m.invert, m.curve, m.range_min, m.range_max)) elif m.type == 'DISTANCE_FROM_OBJECT' and m.target is not None: shaders_list.append(AlphaDistanceFromObjectShader( m.blend, m.influence, m.mapping, m.invert, m.curve, m.target, m.range_min, m.range_max)) elif m.type == 'MATERIAL': shaders_list.append(AlphaMaterialShader( m.blend, m.influence, m.mapping, m.invert, m.curve, m.material_attribute)) for m in linestyle.thickness_modifiers: if not m.use: continue if m.type == 'ALONG_STROKE': shaders_list.append(ThicknessAlongStrokeShader( thickness_position, linestyle.thickness_ratio, m.blend, m.influence, m.mapping, m.invert, m.curve, m.value_min, m.value_max)) elif m.type == 'DISTANCE_FROM_CAMERA': shaders_list.append(ThicknessDistanceFromCameraShader( thickness_position, linestyle.thickness_ratio, m.blend, m.influence, m.mapping, m.invert, m.curve, m.range_min, m.range_max, m.value_min, m.value_max)) elif m.type == 'DISTANCE_FROM_OBJECT' and m.target is not None: shaders_list.append(ThicknessDistanceFromObjectShader( thickness_position, linestyle.thickness_ratio, m.blend, m.influence, m.mapping, m.invert, m.curve, m.target, m.range_min, m.range_max, m.value_min, m.value_max)) elif m.type == 'MATERIAL': shaders_list.append(ThicknessMaterialShader( thickness_position, linestyle.thickness_ratio, m.blend, m.influence, m.mapping, m.invert, m.curve, m.material_attribute, m.value_min, m.value_max)) elif m.type == 'CALLIGRAPHY': shaders_list.append(CalligraphicThicknessShader( thickness_position, linestyle.thickness_ratio, m.blend, m.influence, m.orientation, m.thickness_min, m.thickness_max)) # -- Textures -- # has_tex = False if scene.render.use_shading_nodes: if linestyle.use_nodes and linestyle.node_tree: shaders_list.append(BlenderTextureShader(linestyle.node_tree)) has_tex = True else: if linestyle.use_texture: textures = tuple(BlenderTextureShader(slot) for slot in linestyle.texture_slots if slot is not None) if textures: shaders_list.extend(textures) has_tex = True if has_tex: shaders_list.append(StrokeTextureStepShader(linestyle.texture_spacing)) # -- Stroke caps -- # if linestyle.caps == 'ROUND': shaders_list.append(RoundCapShader()) elif linestyle.caps == 'SQUARE': shaders_list.append(SquareCapShader()) # -- Dashed line -- # if linestyle.use_dashed_line: pattern = [] if linestyle.dash1 > 0 and linestyle.gap1 > 0: pattern.append(linestyle.dash1) pattern.append(linestyle.gap1) if linestyle.dash2 > 0 and linestyle.gap2 > 0: pattern.append(linestyle.dash2) pattern.append(linestyle.gap2) if linestyle.dash3 > 0 and linestyle.gap3 > 0: pattern.append(linestyle.dash3) pattern.append(linestyle.gap3) if len(pattern) > 0: shaders_list.append(DashedLineShader(pattern)) # create strokes using the shaders list Operators.create(TrueUP1D(), shaders_list)
def __init__(self): scene = getCurrentScene() self.persp_camera = (scene.camera.data.type == 'PERSP')
def process(layer_name, lineset_name): scene = getCurrentScene() layer = scene.render.layers[layer_name] lineset = layer.freestyle_settings.linesets[lineset_name] linestyle = lineset.linestyle selection_criteria = [] # prepare selection criteria by visibility if lineset.select_by_visibility: if lineset.visibility == 'VISIBLE': selection_criteria.append(QuantitativeInvisibilityUP1D(0)) elif lineset.visibility == 'HIDDEN': selection_criteria.append(NotUP1D(QuantitativeInvisibilityUP1D(0))) elif lineset.visibility == 'RANGE': selection_criteria.append( QuantitativeInvisibilityRangeUP1D(lineset.qi_start, lineset.qi_end)) # prepare selection criteria by edge types if lineset.select_by_edge_types: edge_type_criteria = [] if lineset.select_silhouette: upred = pyNatureUP1D(Nature.SILHOUETTE) edge_type_criteria.append( NotUP1D(upred) if lineset.exclude_silhouette else upred) if lineset.select_border: upred = pyNatureUP1D(Nature.BORDER) edge_type_criteria.append( NotUP1D(upred) if lineset.exclude_border else upred) if lineset.select_crease: upred = pyNatureUP1D(Nature.CREASE) edge_type_criteria.append( NotUP1D(upred) if lineset.exclude_crease else upred) if lineset.select_ridge_valley: upred = pyNatureUP1D(Nature.RIDGE) edge_type_criteria.append( NotUP1D(upred) if lineset.exclude_ridge_valley else upred) if lineset.select_suggestive_contour: upred = pyNatureUP1D(Nature.SUGGESTIVE_CONTOUR) edge_type_criteria.append( NotUP1D(upred) if lineset.exclude_suggestive_contour else upred ) if lineset.select_material_boundary: upred = pyNatureUP1D(Nature.MATERIAL_BOUNDARY) edge_type_criteria.append( NotUP1D(upred) if lineset.exclude_material_boundary else upred) if lineset.select_edge_mark: upred = pyNatureUP1D(Nature.EDGE_MARK) edge_type_criteria.append( NotUP1D(upred) if lineset.exclude_edge_mark else upred) if lineset.select_contour: upred = ContourUP1D() edge_type_criteria.append( NotUP1D(upred) if lineset.exclude_contour else upred) if lineset.select_external_contour: upred = ExternalContourUP1D() edge_type_criteria.append( NotUP1D(upred) if lineset.exclude_external_contour else upred) if lineset.edge_type_combination == 'OR': upred = OrUP1D(*edge_type_criteria) else: upred = AndUP1D(*edge_type_criteria) if upred is not None: if lineset.edge_type_negation == 'EXCLUSIVE': upred = NotUP1D(upred) selection_criteria.append(upred) # prepare selection criteria by face marks if lineset.select_by_face_marks: if lineset.face_mark_condition == 'BOTH': upred = FaceMarkBothUP1D() else: upred = FaceMarkOneUP1D() if lineset.face_mark_negation == 'EXCLUSIVE': upred = NotUP1D(upred) selection_criteria.append(upred) # prepare selection criteria by group of objects if lineset.select_by_group: if lineset.group is not None: names = {ob.name: True for ob in lineset.group.objects} upred = ObjectNamesUP1D(names, lineset.group_negation == 'EXCLUSIVE') selection_criteria.append(upred) # prepare selection criteria by image border if lineset.select_by_image_border: upred = WithinImageBoundaryUP1D(*ContextFunctions.get_border()) selection_criteria.append(upred) # select feature edges upred = AndUP1D(*selection_criteria) if upred is None: upred = TrueUP1D() Operators.select(upred) # join feature edges to form chains if linestyle.use_chaining: if linestyle.chaining == 'PLAIN': if linestyle.use_same_object: Operators.bidirectional_chain(ChainSilhouetteIterator(), NotUP1D(upred)) else: Operators.bidirectional_chain( ChainPredicateIterator(upred, TrueBP1D()), NotUP1D(upred)) elif linestyle.chaining == 'SKETCHY': if linestyle.use_same_object: Operators.bidirectional_chain( pySketchyChainSilhouetteIterator(linestyle.rounds)) else: Operators.bidirectional_chain( pySketchyChainingIterator(linestyle.rounds)) else: Operators.chain(ChainPredicateIterator(FalseUP1D(), FalseBP1D()), NotUP1D(upred)) # split chains if linestyle.material_boundary: Operators.sequential_split(MaterialBoundaryUP0D()) if linestyle.use_angle_min or linestyle.use_angle_max: angle_min = linestyle.angle_min if linestyle.use_angle_min else None angle_max = linestyle.angle_max if linestyle.use_angle_max else None Operators.sequential_split( Curvature2DAngleThresholdUP0D(angle_min, angle_max)) if linestyle.use_split_length: Operators.sequential_split( Length2DThresholdUP0D(linestyle.split_length), 1.0) if linestyle.use_split_pattern: pattern = [] if linestyle.split_dash1 > 0 and linestyle.split_gap1 > 0: pattern.append(linestyle.split_dash1) pattern.append(linestyle.split_gap1) if linestyle.split_dash2 > 0 and linestyle.split_gap2 > 0: pattern.append(linestyle.split_dash2) pattern.append(linestyle.split_gap2) if linestyle.split_dash3 > 0 and linestyle.split_gap3 > 0: pattern.append(linestyle.split_dash3) pattern.append(linestyle.split_gap3) if len(pattern) > 0: sampling = 1.0 controller = SplitPatternController(pattern, sampling) Operators.sequential_split(SplitPatternStartingUP0D(controller), SplitPatternStoppingUP0D(controller), sampling) # sort selected chains if linestyle.use_sorting: integration = integration_types.get(linestyle.integration_type, IntegrationType.MEAN) if linestyle.sort_key == 'DISTANCE_FROM_CAMERA': bpred = pyZBP1D(integration) elif linestyle.sort_key == '2D_LENGTH': bpred = Length2DBP1D() elif linestyle.sort_key == 'PROJECTED_X': bpred = pyProjectedXBP1D(integration) elif linestyle.sort_key == 'PROJECTED_Y': bpred = pyProjectedYBP1D(integration) if linestyle.sort_order == 'REVERSE': bpred = NotBP1D(bpred) Operators.sort(bpred) # select chains if linestyle.use_length_min or linestyle.use_length_max: length_min = linestyle.length_min if linestyle.use_length_min else None length_max = linestyle.length_max if linestyle.use_length_max else None Operators.select(LengthThresholdUP1D(length_min, length_max)) if linestyle.use_chain_count: Operators.select(pyNFirstUP1D(linestyle.chain_count)) # prepare a list of stroke shaders shaders_list = [] for m in linestyle.geometry_modifiers: if not m.use: continue if m.type == 'SAMPLING': shaders_list.append(SamplingShader(m.sampling)) elif m.type == 'BEZIER_CURVE': shaders_list.append(BezierCurveShader(m.error)) elif m.type == 'SINUS_DISPLACEMENT': shaders_list.append( SinusDisplacementShader(m.wavelength, m.amplitude, m.phase)) elif m.type == 'SPATIAL_NOISE': shaders_list.append( SpatialNoiseShader(m.amplitude, m.scale, m.octaves, m.smooth, m.use_pure_random)) elif m.type == 'PERLIN_NOISE_1D': shaders_list.append( PerlinNoise1DShader(m.frequency, m.amplitude, m.octaves, m.angle, _seed.get(m.seed))) elif m.type == 'PERLIN_NOISE_2D': shaders_list.append( PerlinNoise2DShader(m.frequency, m.amplitude, m.octaves, m.angle, _seed.get(m.seed))) elif m.type == 'BACKBONE_STRETCHER': shaders_list.append(BackboneStretcherShader(m.backbone_length)) elif m.type == 'TIP_REMOVER': shaders_list.append(TipRemoverShader(m.tip_length)) elif m.type == 'POLYGONIZATION': shaders_list.append(PolygonalizationShader(m.error)) elif m.type == 'GUIDING_LINES': shaders_list.append(GuidingLinesShader(m.offset)) elif m.type == 'BLUEPRINT': if m.shape == 'CIRCLES': shaders_list.append( pyBluePrintCirclesShader(m.rounds, m.random_radius, m.random_center)) elif m.shape == 'ELLIPSES': shaders_list.append( pyBluePrintEllipsesShader(m.rounds, m.random_radius, m.random_center)) elif m.shape == 'SQUARES': shaders_list.append( pyBluePrintSquaresShader(m.rounds, m.backbone_length, m.random_backbone)) elif m.type == '2D_OFFSET': shaders_list.append(Offset2DShader(m.start, m.end, m.x, m.y)) elif m.type == '2D_TRANSFORM': shaders_list.append( Transform2DShader(m.pivot, m.scale_x, m.scale_y, m.angle, m.pivot_u, m.pivot_x, m.pivot_y)) # -- Base color, alpha and thickness -- # if (not linestyle.use_chaining) or (linestyle.chaining == 'PLAIN' and linestyle.use_same_object): thickness_position = linestyle.thickness_position else: thickness_position = 'CENTER' import bpy if bpy.app.debug_freestyle: print( "Warning: Thickness position options are applied when chaining is disabled\n" " or the Plain chaining is used with the Same Object option enabled." ) shaders_list.append( ConstantColorShader(*(linestyle.color), alpha=linestyle.alpha)) shaders_list.append( BaseThicknessShader(linestyle.thickness, thickness_position, linestyle.thickness_ratio)) # -- Modifiers -- # for m in linestyle.color_modifiers: if not m.use: continue if m.type == 'ALONG_STROKE': shaders_list.append( ColorAlongStrokeShader(m.blend, m.influence, m.color_ramp)) elif m.type == 'DISTANCE_FROM_CAMERA': shaders_list.append( ColorDistanceFromCameraShader(m.blend, m.influence, m.color_ramp, m.range_min, m.range_max)) elif m.type == 'DISTANCE_FROM_OBJECT' and m.target is not None: shaders_list.append( ColorDistanceFromObjectShader(m.blend, m.influence, m.color_ramp, m.target, m.range_min, m.range_max)) elif m.type == 'MATERIAL': shaders_list.append( ColorMaterialShader(m.blend, m.influence, m.color_ramp, m.material_attribute, m.use_ramp)) for m in linestyle.alpha_modifiers: if not m.use: continue if m.type == 'ALONG_STROKE': shaders_list.append( AlphaAlongStrokeShader(m.blend, m.influence, m.mapping, m.invert, m.curve)) elif m.type == 'DISTANCE_FROM_CAMERA': shaders_list.append( AlphaDistanceFromCameraShader(m.blend, m.influence, m.mapping, m.invert, m.curve, m.range_min, m.range_max)) elif m.type == 'DISTANCE_FROM_OBJECT' and m.target is not None: shaders_list.append( AlphaDistanceFromObjectShader(m.blend, m.influence, m.mapping, m.invert, m.curve, m.target, m.range_min, m.range_max)) elif m.type == 'MATERIAL': shaders_list.append( AlphaMaterialShader(m.blend, m.influence, m.mapping, m.invert, m.curve, m.material_attribute)) for m in linestyle.thickness_modifiers: if not m.use: continue if m.type == 'ALONG_STROKE': shaders_list.append( ThicknessAlongStrokeShader(thickness_position, linestyle.thickness_ratio, m.blend, m.influence, m.mapping, m.invert, m.curve, m.value_min, m.value_max)) elif m.type == 'DISTANCE_FROM_CAMERA': shaders_list.append( ThicknessDistanceFromCameraShader(thickness_position, linestyle.thickness_ratio, m.blend, m.influence, m.mapping, m.invert, m.curve, m.range_min, m.range_max, m.value_min, m.value_max)) elif m.type == 'DISTANCE_FROM_OBJECT' and m.target is not None: shaders_list.append( ThicknessDistanceFromObjectShader( thickness_position, linestyle.thickness_ratio, m.blend, m.influence, m.mapping, m.invert, m.curve, m.target, m.range_min, m.range_max, m.value_min, m.value_max)) elif m.type == 'MATERIAL': shaders_list.append( ThicknessMaterialShader(thickness_position, linestyle.thickness_ratio, m.blend, m.influence, m.mapping, m.invert, m.curve, m.material_attribute, m.value_min, m.value_max)) elif m.type == 'CALLIGRAPHY': shaders_list.append( CalligraphicThicknessShader(thickness_position, linestyle.thickness_ratio, m.blend, m.influence, m.orientation, m.thickness_min, m.thickness_max)) # -- Textures -- # has_tex = False if scene.render.use_shading_nodes: if linestyle.use_nodes and linestyle.node_tree: shaders_list.append(BlenderTextureShader(linestyle.node_tree)) has_tex = True else: if linestyle.use_texture: textures = tuple( BlenderTextureShader(slot) for slot in linestyle.texture_slots if slot is not None) if textures: shaders_list.extend(textures) has_tex = True if has_tex: shaders_list.append(StrokeTextureStepShader(linestyle.texture_spacing)) # -- Stroke caps -- # if linestyle.caps == 'ROUND': shaders_list.append(RoundCapShader()) elif linestyle.caps == 'SQUARE': shaders_list.append(SquareCapShader()) # -- Dashed line -- # if linestyle.use_dashed_line: pattern = [] if linestyle.dash1 > 0 and linestyle.gap1 > 0: pattern.append(linestyle.dash1) pattern.append(linestyle.gap1) if linestyle.dash2 > 0 and linestyle.gap2 > 0: pattern.append(linestyle.dash2) pattern.append(linestyle.gap2) if linestyle.dash3 > 0 and linestyle.gap3 > 0: pattern.append(linestyle.dash3) pattern.append(linestyle.gap3) if len(pattern) > 0: shaders_list.append(DashedLineShader(pattern)) # create strokes using the shaders list Operators.create(TrueUP1D(), shaders_list)