def lineset_post(cls, scene, layer, lineset): if not cls.poll(scene, lineset.linestyle): return # reset the stroke selection (but don't delete the already generated strokes) Operators.reset(delete_strokes=False) # Unary Predicates: visible and correct edge nature upred = AndUP1D( QuantitativeInvisibilityUP1D(0), OrUP1D(ExternalContourUP1D(), pyNatureUP1D(Nature.BORDER)), ) # select the new edges Operators.select(upred) # Binary Predicates bpred = AndBP1D( MaterialBP1D(), NotBP1D(pyZDiscontinuityBP1D()), ) bpred = OrBP1D(bpred, AndBP1D(NotBP1D(bpred), AndBP1D(SameShapeIdBP1D(), MaterialBP1D()))) # chain the edges Operators.bidirectional_chain(ChainPredicateIterator(upred, bpred)) # export SVG collector = StrokeCollector() Operators.create(TrueUP1D(), [collector]) builder = SVGFillBuilder(create_path(scene), render_height(scene), layer.name + '_' + lineset.name) builder.write(collector.strokes) # make strokes used for filling invisible for stroke in collector.strokes: for svert in stroke: svert.attribute.visible = False
def lineset_post(scene, layer, lineset): if not (scene.render.use_freestyle and scene.svg_export.use_svg_export and scene.svg_export.object_fill): return if RenderState.is_fill_written: return # reset the stroke selection (but don't delete the already generated strokes) Operators.reset(delete_strokes=False) # shape detection upred = AndUP1D(QuantitativeInvisibilityUP1D(0), ContourUP1D()) Operators.select(upred) # chain when the same shape and visible bpred = SameShapeIdBP1D() Operators.bidirectional_chain(ChainPredicateIterator(upred, bpred), NotUP1D(QuantitativeInvisibilityUP1D(0))) # sort according to the distance from camera Operators.sort(pyZBP1D()) # render and write fills shader = SVGFillShader(create_path(scene), render_height(scene), lineset.name) Operators.create(TrueUP1D(), [ shader, ]) shader.write() RenderState.is_fill_written = True
def render_external_contour(): """Renders the scene, selects visible strokes of the Contour nature and returns them as a tuple""" upred = AndUP1D(QuantitativeInvisibilityUP1D(0), ContourUP1D()) Operators.select(upred) # chain when the same shape and visible bpred = SameShapeIdBP1D() Operators.bidirectional_chain(ChainPredicateIterator(upred, bpred), NotUP1D(upred)) Operators.create(TrueUP1D(), []) return get_strokes()
# Filename : external_contour.py # Author : Stephane Grabli # Date : 04/08/2005 # Purpose : Draws the external contour of the scene from freestyle.chainingiterators import ChainPredicateIterator from freestyle.predicates import ( AndUP1D, ExternalContourUP1D, NotUP1D, QuantitativeInvisibilityUP1D, TrueBP1D, TrueUP1D, ) from freestyle.shaders import ( ConstantColorShader, ConstantThicknessShader, ) from freestyle.types import Operators upred = AndUP1D(QuantitativeInvisibilityUP1D(0), ExternalContourUP1D()) Operators.select(upred) bpred = TrueBP1D() Operators.bidirectional_chain(ChainPredicateIterator(upred, bpred), NotUP1D(upred)) shaders_list = [ ConstantThicknessShader(3), ConstantColorShader(0.0, 0.0, 0.0, 1), ] Operators.create(TrueUP1D(), shaders_list)
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)
# Filename : contour.py # Author : Stephane Grabli # Date : 04/08/2005 # Purpose : Draws each object's visible contour from freestyle.chainingiterators import ChainPredicateIterator from freestyle.predicates import ( AndUP1D, ContourUP1D, NotUP1D, QuantitativeInvisibilityUP1D, SameShapeIdBP1D, TrueUP1D, ) from freestyle.shaders import ( ConstantThicknessShader, IncreasingColorShader, ) from freestyle.types import Operators Operators.select(AndUP1D(QuantitativeInvisibilityUP1D(0), ContourUP1D())) bpred = SameShapeIdBP1D() upred = AndUP1D(QuantitativeInvisibilityUP1D(0), ContourUP1D()) Operators.bidirectional_chain(ChainPredicateIterator(upred, bpred), NotUP1D(QuantitativeInvisibilityUP1D(0))) shaders_list = [ ConstantThicknessShader(5.0), IncreasingColorShader(0.8, 0, 0, 1, 0.1, 0, 0, 1), ] Operators.create(TrueUP1D(), shaders_list)