Relative imports are intentionally avoided in UI code (`scripts/startup/bl_ui`) because it makes it impossible to run individual files in isolation. Common workflow for making mock-ups and quick UI edits is to load the UI file in Blender's text editor with "Edit Source" operator, make changes, and run the script to see the changes. But in the current version it's impossible because files include relative imports, which don't allow Python to run scripts individually. Pull Request: https://projects.blender.org/blender/blender/pulls/138246
1349 lines
46 KiB
Python
1349 lines
46 KiB
Python
# SPDX-FileCopyrightText: 2012-2023 Blender Authors
|
|
#
|
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
import bpy
|
|
from bpy.types import Menu, Panel, UIList
|
|
from bl_ui.space_properties import PropertiesAnimationMixin
|
|
|
|
|
|
# Render properties
|
|
class RenderFreestyleButtonsPanel:
|
|
bl_space_type = 'PROPERTIES'
|
|
bl_region_type = 'WINDOW'
|
|
bl_context = "render"
|
|
# COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
scene = context.scene
|
|
with_freestyle = bpy.app.build_options.freestyle
|
|
return scene and with_freestyle and (context.engine in cls.COMPAT_ENGINES)
|
|
|
|
|
|
class RENDER_PT_freestyle(RenderFreestyleButtonsPanel, Panel):
|
|
bl_label = "Freestyle"
|
|
bl_options = {'DEFAULT_CLOSED'}
|
|
bl_order = 10
|
|
COMPAT_ENGINES = {
|
|
'BLENDER_RENDER',
|
|
'BLENDER_EEVEE_NEXT',
|
|
'BLENDER_WORKBENCH',
|
|
}
|
|
|
|
def draw_header(self, context):
|
|
rd = context.scene.render
|
|
self.layout.prop(rd, "use_freestyle", text="")
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = False
|
|
rd = context.scene.render
|
|
layout.active = rd.use_freestyle
|
|
layout.row().prop(rd, "line_thickness_mode", expand=True, text="Line Thickness Mode")
|
|
if rd.line_thickness_mode == 'ABSOLUTE':
|
|
layout.prop(rd, "line_thickness")
|
|
|
|
|
|
# Render layer properties
|
|
|
|
|
|
class ViewLayerFreestyleButtonsPanel:
|
|
bl_space_type = 'PROPERTIES'
|
|
bl_region_type = 'WINDOW'
|
|
bl_context = "view_layer"
|
|
bl_order = 10
|
|
# COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
scene = context.scene
|
|
rd = scene.render
|
|
with_freestyle = bpy.app.build_options.freestyle
|
|
|
|
return (
|
|
scene and
|
|
with_freestyle and
|
|
rd.use_freestyle and
|
|
(context.engine in cls.COMPAT_ENGINES)
|
|
)
|
|
|
|
|
|
class ViewLayerFreestyleEditorButtonsPanel(ViewLayerFreestyleButtonsPanel):
|
|
# COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
if not super().poll(context):
|
|
return False
|
|
view_layer = context.view_layer
|
|
return (
|
|
view_layer and
|
|
view_layer.use_freestyle and
|
|
view_layer.freestyle_settings.mode == 'EDITOR'
|
|
)
|
|
|
|
|
|
class ViewLayerFreestyleLineStyle(ViewLayerFreestyleEditorButtonsPanel):
|
|
# Freestyle Linestyle Panels
|
|
COMPAT_ENGINES = {
|
|
'BLENDER_RENDER',
|
|
'BLENDER_EEVEE_NEXT',
|
|
'BLENDER_WORKBENCH',
|
|
}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
if not super().poll(context):
|
|
return False
|
|
view_layer = context.view_layer
|
|
lineset = view_layer.freestyle_settings.linesets.active
|
|
if lineset is None:
|
|
return False
|
|
linestyle = lineset.linestyle
|
|
if linestyle is None:
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
class ViewLayerFreestyleLinestyleStrokesSubPanel(ViewLayerFreestyleLineStyle):
|
|
# Freestyle Linestyle Strokes sub panels
|
|
bl_parent_id = "VIEWLAYER_PT_freestyle_linestyle_strokes"
|
|
|
|
|
|
class VIEWLAYER_UL_linesets(UIList):
|
|
def draw_item(self, _context, layout, _data, item, icon, _active_data, _active_propname, index):
|
|
lineset = item
|
|
if self.layout_type in {'DEFAULT', 'COMPACT'}:
|
|
layout.prop(lineset, "name", text="", emboss=False, icon_value=icon)
|
|
layout.prop(lineset, "show_render", text="", index=index)
|
|
elif self.layout_type == 'GRID':
|
|
layout.alignment = 'CENTER'
|
|
layout.label(text="", icon_value=icon)
|
|
|
|
|
|
class RENDER_MT_lineset_context_menu(Menu):
|
|
bl_label = "Lineset Specials"
|
|
|
|
def draw(self, _context):
|
|
layout = self.layout
|
|
layout.operator("scene.freestyle_lineset_copy", icon='COPYDOWN')
|
|
layout.operator("scene.freestyle_lineset_paste", icon='PASTEDOWN')
|
|
|
|
|
|
class VIEWLAYER_PT_freestyle(ViewLayerFreestyleButtonsPanel, Panel):
|
|
bl_label = "Freestyle"
|
|
COMPAT_ENGINES = {
|
|
'BLENDER_RENDER',
|
|
'BLENDER_EEVEE_NEXT',
|
|
'BLENDER_WORKBENCH',
|
|
}
|
|
|
|
def draw_header(self, context):
|
|
view_layer = context.view_layer
|
|
rd = context.scene.render
|
|
|
|
layout = self.layout
|
|
|
|
layout.active = rd.use_freestyle
|
|
layout.prop(view_layer, "use_freestyle", text="")
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = False
|
|
|
|
view_layer = context.view_layer
|
|
freestyle = view_layer.freestyle_settings
|
|
|
|
layout.active = view_layer.use_freestyle
|
|
|
|
col = layout.column(align=True)
|
|
col.prop(freestyle, "mode", text="Control Mode")
|
|
col.prop(freestyle, "use_view_map_cache", text="View Map Cache")
|
|
col.prop(freestyle, "as_render_pass", text="As Render Pass")
|
|
|
|
|
|
class VIEWLAYER_PT_freestyle_edge_detection(ViewLayerFreestyleButtonsPanel, Panel):
|
|
bl_label = "Edge Detection"
|
|
bl_parent_id = "VIEWLAYER_PT_freestyle"
|
|
COMPAT_ENGINES = {
|
|
'BLENDER_RENDER',
|
|
'BLENDER_EEVEE_NEXT',
|
|
'BLENDER_WORKBENCH',
|
|
}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = False
|
|
|
|
view_layer = context.view_layer
|
|
freestyle = view_layer.freestyle_settings
|
|
|
|
layout.active = view_layer.use_freestyle
|
|
|
|
col = layout.column()
|
|
col.prop(freestyle, "crease_angle")
|
|
col.prop(freestyle, "use_culling")
|
|
col.prop(freestyle, "use_smoothness")
|
|
|
|
if freestyle.mode == 'SCRIPT':
|
|
col.prop(freestyle, "use_material_boundaries")
|
|
|
|
if freestyle.mode == 'SCRIPT':
|
|
col.prop(freestyle, "use_ridges_and_valleys")
|
|
col.prop(freestyle, "use_suggestive_contours")
|
|
col.prop(freestyle, "sphere_radius")
|
|
col.prop(freestyle, "kr_derivative_epsilon")
|
|
|
|
|
|
class VIEWLAYER_PT_freestyle_style_modules(ViewLayerFreestyleButtonsPanel, Panel):
|
|
bl_label = "Style Modules"
|
|
bl_parent_id = "VIEWLAYER_PT_freestyle"
|
|
COMPAT_ENGINES = {
|
|
'BLENDER_RENDER',
|
|
'BLENDER_EEVEE_NEXT',
|
|
'BLENDER_WORKBENCH',
|
|
}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
view_layer = context.view_layer
|
|
freestyle = view_layer.freestyle_settings
|
|
return freestyle.mode == 'SCRIPT'
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = False
|
|
|
|
view_layer = context.view_layer
|
|
freestyle = view_layer.freestyle_settings
|
|
|
|
layout.active = view_layer.use_freestyle
|
|
|
|
col = layout.column()
|
|
col.use_property_split = False
|
|
row = col.row()
|
|
row.operator("scene.freestyle_module_add", text="Add")
|
|
for module in freestyle.modules:
|
|
box = col.box()
|
|
box.context_pointer_set("freestyle_module", module)
|
|
row = box.row(align=True)
|
|
row.prop(module, "use", text="")
|
|
row.prop(module, "script", text="")
|
|
row.operator("scene.freestyle_module_open", icon='FILEBROWSER', text="")
|
|
row.operator("scene.freestyle_module_remove", icon='X', text="")
|
|
row.operator("scene.freestyle_module_move", icon='TRIA_UP', text="").direction = 'UP'
|
|
row.operator("scene.freestyle_module_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
|
|
|
|
|
|
class VIEWLAYER_PT_freestyle_lineset(ViewLayerFreestyleEditorButtonsPanel, Panel):
|
|
bl_label = "Freestyle Line Set"
|
|
COMPAT_ENGINES = {
|
|
'BLENDER_RENDER',
|
|
'BLENDER_EEVEE_NEXT',
|
|
'BLENDER_WORKBENCH',
|
|
}
|
|
|
|
def draw_edge_type_buttons(self, box, lineset, edge_type):
|
|
# property names
|
|
select_edge_type = "select_" + edge_type
|
|
exclude_edge_type = "exclude_" + edge_type
|
|
# draw edge type buttons
|
|
row = box.row(align=True)
|
|
row.prop(lineset, select_edge_type)
|
|
sub = row.column(align=True)
|
|
sub.prop(lineset, exclude_edge_type, text="")
|
|
sub.active = getattr(lineset, select_edge_type)
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
|
|
view_layer = context.view_layer
|
|
freestyle = view_layer.freestyle_settings
|
|
lineset = freestyle.linesets.active
|
|
|
|
row = layout.row()
|
|
|
|
is_sortable = len(freestyle.linesets) > 1
|
|
rows = 3
|
|
if is_sortable:
|
|
rows = 5
|
|
|
|
row.template_list(
|
|
"VIEWLAYER_UL_linesets",
|
|
"",
|
|
freestyle,
|
|
"linesets",
|
|
freestyle.linesets,
|
|
"active_index",
|
|
rows=rows,
|
|
)
|
|
|
|
col = row.column(align=True)
|
|
col.operator("scene.freestyle_lineset_add", icon='ADD', text="")
|
|
col.operator("scene.freestyle_lineset_remove", icon='REMOVE', text="")
|
|
|
|
col.separator()
|
|
|
|
col.menu("RENDER_MT_lineset_context_menu", icon='DOWNARROW_HLT', text="")
|
|
|
|
if is_sortable:
|
|
col.separator()
|
|
col.operator("scene.freestyle_lineset_move", icon='TRIA_UP', text="").direction = 'UP'
|
|
col.operator("scene.freestyle_lineset_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
|
|
|
|
if lineset:
|
|
layout.template_ID(lineset, "linestyle", new="scene.freestyle_linestyle_new")
|
|
layout.separator()
|
|
col = layout.column(heading="Select by")
|
|
col.use_property_split = True
|
|
col.use_property_decorate = False
|
|
col.prop(lineset, "select_by_image_border", text="Image Border")
|
|
|
|
|
|
# Freestyle Lineset Sub Panels
|
|
class VIEWLAYER_PT_freestyle_lineset_visibilty(ViewLayerFreestyleLineStyle, Panel):
|
|
bl_label = "Visibility"
|
|
bl_parent_id = "VIEWLAYER_PT_freestyle_lineset"
|
|
COMPAT_ENGINES = {
|
|
'BLENDER_RENDER',
|
|
'BLENDER_EEVEE_NEXT',
|
|
'BLENDER_WORKBENCH',
|
|
}
|
|
|
|
def draw_header(self, context):
|
|
layout = self.layout
|
|
|
|
view_layer = context.view_layer
|
|
freestyle = view_layer.freestyle_settings
|
|
lineset = freestyle.linesets.active
|
|
|
|
layout.prop(lineset, "select_by_visibility", text="")
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = False
|
|
|
|
view_layer = context.view_layer
|
|
freestyle = view_layer.freestyle_settings
|
|
lineset = freestyle.linesets.active
|
|
|
|
layout.active = lineset.select_by_visibility
|
|
col = layout.column(align=True, heading="Type")
|
|
col.prop(lineset, "visibility", text="Type", expand=False)
|
|
|
|
if lineset.visibility == 'RANGE':
|
|
col = layout.column(align=True)
|
|
col.use_property_split = True
|
|
col.prop(lineset, "qi_start")
|
|
col.prop(lineset, "qi_end")
|
|
|
|
|
|
class VIEWLAYER_PT_freestyle_lineset_edgetype(ViewLayerFreestyleLineStyle, Panel):
|
|
bl_label = "Edge Type"
|
|
bl_parent_id = "VIEWLAYER_PT_freestyle_lineset"
|
|
COMPAT_ENGINES = {
|
|
'BLENDER_RENDER',
|
|
'BLENDER_EEVEE_NEXT',
|
|
'BLENDER_WORKBENCH',
|
|
}
|
|
|
|
def draw_header(self, context):
|
|
layout = self.layout
|
|
|
|
view_layer = context.view_layer
|
|
freestyle = view_layer.freestyle_settings
|
|
lineset = freestyle.linesets.active
|
|
|
|
layout.prop(lineset, "select_by_edge_types", text="")
|
|
|
|
def draw_edge_type_buttons(self, box, lineset, edge_type):
|
|
# property names
|
|
select_edge_type = "select_" + edge_type
|
|
exclude_edge_type = "exclude_" + edge_type
|
|
# draw edge type buttons
|
|
row = box.row(align=True)
|
|
row.prop(lineset, select_edge_type)
|
|
sub = row.column(align=True)
|
|
sub.prop(lineset, exclude_edge_type, text="")
|
|
sub.active = getattr(lineset, select_edge_type)
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = False
|
|
|
|
view_layer = context.view_layer
|
|
freestyle = view_layer.freestyle_settings
|
|
lineset = freestyle.linesets.active
|
|
|
|
layout.active = lineset.select_by_edge_types
|
|
layout.row().prop(lineset, "edge_type_negation", expand=True, text="Negation")
|
|
layout.row().prop(lineset, "edge_type_combination", expand=True, text="Combination")
|
|
|
|
col = layout.column(heading="Type")
|
|
self.draw_edge_type_buttons(col, lineset, "silhouette")
|
|
self.draw_edge_type_buttons(col, lineset, "crease")
|
|
self.draw_edge_type_buttons(col, lineset, "border")
|
|
self.draw_edge_type_buttons(col, lineset, "edge_mark")
|
|
self.draw_edge_type_buttons(col, lineset, "contour")
|
|
self.draw_edge_type_buttons(col, lineset, "external_contour")
|
|
self.draw_edge_type_buttons(col, lineset, "material_boundary")
|
|
self.draw_edge_type_buttons(col, lineset, "suggestive_contour")
|
|
self.draw_edge_type_buttons(col, lineset, "ridge_valley")
|
|
|
|
|
|
class VIEWLAYER_PT_freestyle_lineset_facemarks(ViewLayerFreestyleLineStyle, Panel):
|
|
bl_label = "Face Marks"
|
|
bl_parent_id = "VIEWLAYER_PT_freestyle_lineset"
|
|
COMPAT_ENGINES = {
|
|
'BLENDER_RENDER',
|
|
'BLENDER_EEVEE_NEXT',
|
|
'BLENDER_WORKBENCH',
|
|
}
|
|
bl_options = {'DEFAULT_CLOSED'}
|
|
|
|
def draw_header(self, context):
|
|
layout = self.layout
|
|
|
|
view_layer = context.view_layer
|
|
freestyle = view_layer.freestyle_settings
|
|
lineset = freestyle.linesets.active
|
|
|
|
layout.prop(lineset, "select_by_face_marks", text="")
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = False
|
|
|
|
view_layer = context.view_layer
|
|
freestyle = view_layer.freestyle_settings
|
|
lineset = freestyle.linesets.active
|
|
|
|
layout.active = lineset.select_by_face_marks
|
|
layout.row().prop(lineset, "face_mark_negation", expand=True, text="Negation")
|
|
layout.row().prop(lineset, "face_mark_condition", expand=True, text="Condition")
|
|
|
|
|
|
class VIEWLAYER_PT_freestyle_lineset_collection(ViewLayerFreestyleLineStyle, Panel):
|
|
bl_label = "Collection"
|
|
bl_parent_id = "VIEWLAYER_PT_freestyle_lineset"
|
|
COMPAT_ENGINES = {
|
|
'BLENDER_RENDER',
|
|
'BLENDER_EEVEE_NEXT',
|
|
'BLENDER_WORKBENCH',
|
|
}
|
|
bl_options = {'DEFAULT_CLOSED'}
|
|
|
|
def draw_header(self, context):
|
|
layout = self.layout
|
|
|
|
view_layer = context.view_layer
|
|
freestyle = view_layer.freestyle_settings
|
|
lineset = freestyle.linesets.active
|
|
|
|
layout.prop(lineset, "select_by_collection", text="")
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = False
|
|
|
|
view_layer = context.view_layer
|
|
freestyle = view_layer.freestyle_settings
|
|
lineset = freestyle.linesets.active
|
|
|
|
layout.active = lineset.select_by_collection
|
|
layout.row().prop(lineset, "collection", text="Line Set Collection")
|
|
layout.row().prop(lineset, "collection_negation", expand=True, text="Negation")
|
|
|
|
|
|
# Linestyle Modifier Drawing code
|
|
def draw_modifier_box_header(box, modifier):
|
|
row = box.row()
|
|
row.use_property_split = False
|
|
row.context_pointer_set("modifier", modifier)
|
|
if modifier.expanded:
|
|
icon = 'TRIA_DOWN'
|
|
else:
|
|
icon = 'TRIA_RIGHT'
|
|
row.prop(modifier, "expanded", text="", icon=icon, emboss=False)
|
|
|
|
sub = row.row(align=True)
|
|
sub.prop(modifier, "name", text="")
|
|
if modifier.use:
|
|
icon = 'RESTRICT_RENDER_OFF'
|
|
else:
|
|
icon = 'RESTRICT_RENDER_ON'
|
|
sub.prop(modifier, "use", text="", icon=icon)
|
|
sub.operator("scene.freestyle_modifier_copy", icon='DUPLICATE', text="")
|
|
|
|
sub = row.row(align=True)
|
|
sub.operator("scene.freestyle_modifier_move", icon='TRIA_UP', text="").direction = 'UP'
|
|
sub.operator("scene.freestyle_modifier_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
|
|
|
|
row.operator("scene.freestyle_modifier_remove", icon='X', text="", emboss=False)
|
|
|
|
|
|
def draw_modifier_box_error(box, _modifier, message):
|
|
row = box.row()
|
|
row.label(text=message, icon='ERROR')
|
|
|
|
|
|
def draw_modifier_common(box, modifier):
|
|
col = box.column()
|
|
col.prop(modifier, "blend", text="Blend Mode")
|
|
col.prop(modifier, "influence")
|
|
|
|
|
|
def draw_modifier_color_ramp_common(box, modifier, has_range):
|
|
box.template_color_ramp(modifier, "color_ramp", expand=True)
|
|
if has_range:
|
|
col = box.column(align=True)
|
|
col.prop(modifier, "range_min", text="Range Min")
|
|
col.prop(modifier, "range_max", text="Max")
|
|
|
|
|
|
def draw_modifier_curve_common(box, modifier, has_range, has_value):
|
|
row = box.row()
|
|
row.prop(modifier, "mapping", text="Mapping")
|
|
if modifier.mapping == 'LINEAR':
|
|
box.prop(modifier, "invert")
|
|
if has_range:
|
|
col = box.column(align=True)
|
|
col.prop(modifier, "range_min", text="Range Min")
|
|
col.prop(modifier, "range_max", text="Max")
|
|
if has_value:
|
|
col = box.column(align=True)
|
|
col.prop(modifier, "value_min", text="Value Min")
|
|
col.prop(modifier, "value_max", text="Max")
|
|
if modifier.mapping == 'CURVE':
|
|
box.template_curve_mapping(modifier, "curve")
|
|
|
|
|
|
class VIEWLAYER_PT_freestyle_linestyle_strokes(ViewLayerFreestyleLineStyle, Panel):
|
|
bl_label = "Freestyle Strokes"
|
|
bl_options = {'DEFAULT_CLOSED'}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = False
|
|
|
|
view_layer = context.view_layer
|
|
lineset = view_layer.freestyle_settings.linesets.active
|
|
|
|
layout.active = view_layer.use_freestyle
|
|
|
|
if lineset is None:
|
|
return
|
|
linestyle = lineset.linestyle
|
|
|
|
if linestyle is None:
|
|
return
|
|
|
|
row = layout.row(align=True)
|
|
row.alignment = 'LEFT'
|
|
row.label(text=lineset.name, icon='LINE_DATA', translate=False)
|
|
row.label(text="", icon='RIGHTARROW')
|
|
row.label(text=linestyle.name, translate=False)
|
|
|
|
col = layout.column(align=True)
|
|
col.prop(linestyle, "caps", expand=False)
|
|
|
|
|
|
class VIEWLAYER_PT_freestyle_linestyle_strokes_chaining(ViewLayerFreestyleLinestyleStrokesSubPanel, Panel):
|
|
bl_label = "Chaining"
|
|
|
|
def draw_header(self, context):
|
|
layout = self.layout
|
|
|
|
view_layer = context.view_layer
|
|
freestyle = view_layer.freestyle_settings
|
|
lineset = freestyle.linesets.active
|
|
|
|
linestyle = lineset.linestyle
|
|
layout.prop(linestyle, "use_chaining", text="")
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = False
|
|
|
|
view_layer = context.view_layer
|
|
lineset = view_layer.freestyle_settings.linesets.active
|
|
linestyle = lineset.linestyle
|
|
|
|
layout.active = linestyle.use_chaining
|
|
layout.row().prop(linestyle, "chaining", expand=True, text="Method")
|
|
if linestyle.chaining == 'SKETCHY':
|
|
layout.prop(linestyle, "rounds")
|
|
layout.prop(linestyle, "use_same_object")
|
|
|
|
|
|
class VIEWLAYER_PT_freestyle_linestyle_strokes_splitting(ViewLayerFreestyleLinestyleStrokesSubPanel, Panel):
|
|
bl_label = "Splitting"
|
|
bl_options = {'DEFAULT_CLOSED'}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = False
|
|
|
|
view_layer = context.view_layer
|
|
lineset = view_layer.freestyle_settings.linesets.active
|
|
linestyle = lineset.linestyle
|
|
|
|
row = layout.row(align=False, heading="Min 2D Angle")
|
|
row.prop(linestyle, "use_angle_min", text="")
|
|
sub = row.row()
|
|
sub.active = linestyle.use_angle_min
|
|
sub.prop(linestyle, "angle_min", text="")
|
|
|
|
row = layout.row(align=False, heading="Max 2D Angle")
|
|
row.prop(linestyle, "use_angle_max", text="")
|
|
sub = row.row()
|
|
sub.active = linestyle.use_angle_max
|
|
sub.prop(linestyle, "angle_max", text="")
|
|
|
|
row = layout.row(align=False, heading="2D Length")
|
|
row.prop(linestyle, "use_split_length", text="")
|
|
sub = row.row()
|
|
sub.active = linestyle.use_split_length
|
|
sub.prop(linestyle, "split_length", text="")
|
|
|
|
layout.prop(linestyle, "material_boundary")
|
|
|
|
|
|
class VIEWLAYER_PT_freestyle_linestyle_strokes_splitting_pattern(ViewLayerFreestyleLinestyleStrokesSubPanel, Panel):
|
|
bl_label = "Split Pattern"
|
|
bl_parent_id = "VIEWLAYER_PT_freestyle_linestyle_strokes_splitting"
|
|
bl_options = {'DEFAULT_CLOSED'}
|
|
|
|
def draw_header(self, context):
|
|
layout = self.layout
|
|
|
|
view_layer = context.view_layer
|
|
freestyle = view_layer.freestyle_settings
|
|
lineset = freestyle.linesets.active
|
|
|
|
linestyle = lineset.linestyle
|
|
layout.prop(linestyle, "use_split_pattern", text="")
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = False
|
|
|
|
view_layer = context.view_layer
|
|
lineset = view_layer.freestyle_settings.linesets.active
|
|
linestyle = lineset.linestyle
|
|
|
|
layout.active = linestyle.use_split_pattern
|
|
|
|
col = layout.column(align=True)
|
|
col.prop(linestyle, "split_dash1", text="Dash 1")
|
|
col.prop(linestyle, "split_dash2", text="2")
|
|
col.prop(linestyle, "split_dash3", text="3")
|
|
col = layout.column(align=True)
|
|
col.prop(linestyle, "split_gap1", text="Gap 1")
|
|
col.prop(linestyle, "split_gap2", text="2")
|
|
col.prop(linestyle, "split_gap3", text="3")
|
|
|
|
|
|
class VIEWLAYER_PT_freestyle_linestyle_strokes_sorting(ViewLayerFreestyleLinestyleStrokesSubPanel, Panel):
|
|
bl_label = "Sorting"
|
|
bl_options = {'DEFAULT_CLOSED'}
|
|
|
|
def draw_header(self, context):
|
|
layout = self.layout
|
|
|
|
view_layer = context.view_layer
|
|
freestyle = view_layer.freestyle_settings
|
|
lineset = freestyle.linesets.active
|
|
|
|
linestyle = lineset.linestyle
|
|
layout.prop(linestyle, "use_sorting", text="")
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = False
|
|
|
|
view_layer = context.view_layer
|
|
freestyle = view_layer.freestyle_settings
|
|
lineset = freestyle.linesets.active
|
|
|
|
linestyle = lineset.linestyle
|
|
|
|
layout.active = linestyle.use_sorting
|
|
|
|
layout.prop(linestyle, "sort_key")
|
|
|
|
row = layout.row()
|
|
row.active = linestyle.sort_key in {
|
|
'DISTANCE_FROM_CAMERA',
|
|
'PROJECTED_X',
|
|
'PROJECTED_Y',
|
|
}
|
|
row.prop(linestyle, "integration_type")
|
|
layout.row().prop(linestyle, "sort_order", expand=True, text="Sort Order")
|
|
|
|
|
|
class VIEWLAYER_PT_freestyle_linestyle_strokes_selection(ViewLayerFreestyleLinestyleStrokesSubPanel, Panel):
|
|
bl_label = "Selection"
|
|
bl_options = {'DEFAULT_CLOSED'}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = False
|
|
|
|
view_layer = context.view_layer
|
|
lineset = view_layer.freestyle_settings.linesets.active
|
|
linestyle = lineset.linestyle
|
|
|
|
row = layout.row(align=False, heading="Min 2D Length")
|
|
row.prop(linestyle, "use_length_min", text="")
|
|
sub = row.row()
|
|
sub.active = linestyle.use_length_min
|
|
sub.prop(linestyle, "length_min", text="")
|
|
|
|
row = layout.row(align=False, heading="Max 2D Length")
|
|
row.prop(linestyle, "use_length_max", text="")
|
|
sub = row.row()
|
|
sub.active = linestyle.use_length_max
|
|
sub.prop(linestyle, "length_max", text="")
|
|
|
|
row = layout.row(align=False, heading="Chain Count")
|
|
row.prop(linestyle, "use_chain_count", text="")
|
|
sub = row.row()
|
|
sub.active = linestyle.use_chain_count
|
|
sub.prop(linestyle, "chain_count", text="")
|
|
|
|
|
|
class VIEWLAYER_PT_freestyle_linestyle_strokes_dashedline(ViewLayerFreestyleLinestyleStrokesSubPanel, Panel):
|
|
bl_label = "Dashed Line"
|
|
bl_options = {'DEFAULT_CLOSED'}
|
|
|
|
def draw_header(self, context):
|
|
layout = self.layout
|
|
|
|
view_layer = context.view_layer
|
|
freestyle = view_layer.freestyle_settings
|
|
lineset = freestyle.linesets.active
|
|
|
|
linestyle = lineset.linestyle
|
|
layout.prop(linestyle, "use_dashed_line", text="")
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = False
|
|
|
|
view_layer = context.view_layer
|
|
lineset = view_layer.freestyle_settings.linesets.active
|
|
linestyle = lineset.linestyle
|
|
|
|
layout.active = linestyle.use_dashed_line
|
|
|
|
col = layout.column(align=True)
|
|
col.prop(linestyle, "dash1", text="Dash 1")
|
|
col.prop(linestyle, "dash2", text="2")
|
|
col.prop(linestyle, "dash3", text="3")
|
|
col = layout.column(align=True)
|
|
col.prop(linestyle, "gap1", text="Gap 1")
|
|
col.prop(linestyle, "gap2", text="2")
|
|
col.prop(linestyle, "gap3", text="3")
|
|
|
|
|
|
class VIEWLAYER_PT_freestyle_linestyle_color(ViewLayerFreestyleLineStyle, Panel):
|
|
bl_label = "Freestyle Color"
|
|
bl_options = {'DEFAULT_CLOSED'}
|
|
|
|
def draw_color_modifier(self, context, modifier):
|
|
layout = self.layout
|
|
|
|
col = layout.column(align=True)
|
|
draw_modifier_box_header(col.box(), modifier)
|
|
if modifier.expanded:
|
|
box = col.box()
|
|
draw_modifier_common(box, modifier)
|
|
|
|
if modifier.type == 'ALONG_STROKE':
|
|
draw_modifier_color_ramp_common(box, modifier, False)
|
|
|
|
elif modifier.type == 'DISTANCE_FROM_OBJECT':
|
|
box.prop(modifier, "target")
|
|
draw_modifier_color_ramp_common(box, modifier, True)
|
|
props = box.operator("scene.freestyle_fill_range_by_selection")
|
|
props.type = 'COLOR'
|
|
props.name = modifier.name
|
|
|
|
elif modifier.type == 'DISTANCE_FROM_CAMERA':
|
|
draw_modifier_color_ramp_common(box, modifier, True)
|
|
props = box.operator("scene.freestyle_fill_range_by_selection")
|
|
props.type = 'COLOR'
|
|
props.name = modifier.name
|
|
|
|
elif modifier.type == 'MATERIAL':
|
|
row = box.row()
|
|
row.prop(modifier, "material_attribute", text="Material Attribute")
|
|
sub = box.column()
|
|
sub.prop(modifier, "use_ramp")
|
|
if modifier.material_attribute in {'LINE', 'DIFF', 'SPEC'}:
|
|
sub.active = True
|
|
show_ramp = modifier.use_ramp
|
|
else:
|
|
sub.active = False
|
|
show_ramp = True
|
|
if show_ramp:
|
|
draw_modifier_color_ramp_common(box, modifier, False)
|
|
|
|
elif modifier.type == 'TANGENT':
|
|
draw_modifier_color_ramp_common(box, modifier, False)
|
|
|
|
elif modifier.type == 'NOISE':
|
|
subcol = box.column(align=True)
|
|
subcol.prop(modifier, "amplitude")
|
|
subcol.prop(modifier, "period")
|
|
subcol.prop(modifier, "seed")
|
|
draw_modifier_color_ramp_common(box, modifier, False)
|
|
|
|
elif modifier.type == 'CREASE_ANGLE':
|
|
subcol = box.column(align=True)
|
|
subcol.prop(modifier, "angle_min", text="Angle Min")
|
|
subcol.prop(modifier, "angle_max", text="Max")
|
|
draw_modifier_color_ramp_common(box, modifier, False)
|
|
|
|
elif modifier.type == 'CURVATURE_3D':
|
|
subcol = box.column(align=True)
|
|
subcol.prop(modifier, "curvature_min", text="Curvature Min")
|
|
subcol.prop(modifier, "curvature_max", text="Max")
|
|
|
|
draw_modifier_color_ramp_common(box, modifier, False)
|
|
|
|
freestyle = context.view_layer.freestyle_settings
|
|
if not freestyle.use_smoothness:
|
|
message = "Enable Face Smoothness to use this modifier"
|
|
draw_modifier_box_error(col.box(), modifier, message)
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = False
|
|
|
|
view_layer = context.view_layer
|
|
lineset = view_layer.freestyle_settings.linesets.active
|
|
|
|
layout.active = view_layer.use_freestyle
|
|
|
|
if lineset is None:
|
|
return
|
|
linestyle = lineset.linestyle
|
|
|
|
if linestyle is None:
|
|
return
|
|
|
|
row = layout.row(align=True)
|
|
row.alignment = 'LEFT'
|
|
row.label(text=lineset.name, icon='LINE_DATA', translate=False)
|
|
row.label(text="", icon='RIGHTARROW')
|
|
row.label(text=linestyle.name, translate=False)
|
|
|
|
col = layout.column()
|
|
row = col.row()
|
|
row.prop(linestyle, "color", text="Base Color")
|
|
col.operator_menu_enum("scene.freestyle_color_modifier_add", "type", text="Add Modifier")
|
|
for modifier in linestyle.color_modifiers:
|
|
self.draw_color_modifier(context, modifier)
|
|
|
|
|
|
class VIEWLAYER_PT_freestyle_linestyle_alpha(ViewLayerFreestyleLineStyle, Panel):
|
|
bl_label = "Freestyle Alpha"
|
|
bl_options = {'DEFAULT_CLOSED'}
|
|
|
|
def draw_alpha_modifier(self, context, modifier):
|
|
layout = self.layout
|
|
|
|
col = layout.column(align=True)
|
|
draw_modifier_box_header(col.box(), modifier)
|
|
if modifier.expanded:
|
|
box = col.box()
|
|
draw_modifier_common(box, modifier)
|
|
|
|
if modifier.type == 'ALONG_STROKE':
|
|
draw_modifier_curve_common(box, modifier, False, False)
|
|
|
|
elif modifier.type == 'DISTANCE_FROM_OBJECT':
|
|
box.prop(modifier, "target")
|
|
draw_modifier_curve_common(box, modifier, True, False)
|
|
props = box.operator("scene.freestyle_fill_range_by_selection")
|
|
props.type = 'ALPHA'
|
|
props.name = modifier.name
|
|
|
|
elif modifier.type == 'DISTANCE_FROM_CAMERA':
|
|
draw_modifier_curve_common(box, modifier, True, False)
|
|
props = box.operator("scene.freestyle_fill_range_by_selection")
|
|
props.type = 'ALPHA'
|
|
props.name = modifier.name
|
|
|
|
elif modifier.type == 'MATERIAL':
|
|
box.prop(modifier, "material_attribute", text="Material Attribute")
|
|
draw_modifier_curve_common(box, modifier, False, False)
|
|
|
|
elif modifier.type == 'TANGENT':
|
|
draw_modifier_curve_common(box, modifier, False, False)
|
|
|
|
elif modifier.type == 'NOISE':
|
|
col = box.column(align=True)
|
|
col.prop(modifier, "amplitude")
|
|
col.prop(modifier, "period")
|
|
col.prop(modifier, "seed")
|
|
draw_modifier_curve_common(box, modifier, False, False)
|
|
|
|
elif modifier.type == 'CREASE_ANGLE':
|
|
col = box.column(align=True)
|
|
col.prop(modifier, "angle_min", text="Angle Min")
|
|
col.prop(modifier, "angle_max", text="Max")
|
|
draw_modifier_curve_common(box, modifier, False, False)
|
|
|
|
elif modifier.type == 'CURVATURE_3D':
|
|
draw_modifier_curve_common(box, modifier, False, False)
|
|
|
|
subcol = box.column(align=True)
|
|
subcol.prop(modifier, "curvature_min", text="Curvature Min")
|
|
subcol.prop(modifier, "curvature_max", text="Max")
|
|
|
|
freestyle = context.view_layer.freestyle_settings
|
|
if not freestyle.use_smoothness:
|
|
message = "Enable Face Smoothness to use this modifier"
|
|
draw_modifier_box_error(col.box(), modifier, message)
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = False
|
|
|
|
view_layer = context.view_layer
|
|
lineset = view_layer.freestyle_settings.linesets.active
|
|
|
|
layout.active = view_layer.use_freestyle
|
|
|
|
if lineset is None:
|
|
return
|
|
linestyle = lineset.linestyle
|
|
|
|
if linestyle is None:
|
|
return
|
|
|
|
row = layout.row(align=True)
|
|
row.alignment = 'LEFT'
|
|
row.label(text=lineset.name, icon='LINE_DATA', translate=False)
|
|
row.label(text="", icon='RIGHTARROW')
|
|
row.label(text=linestyle.name, translate=False)
|
|
|
|
col = layout.column()
|
|
row = col.row()
|
|
row.prop(linestyle, "alpha", text="Base Transparency")
|
|
col.operator_menu_enum("scene.freestyle_alpha_modifier_add", "type", text="Add Modifier")
|
|
for modifier in linestyle.alpha_modifiers:
|
|
self.draw_alpha_modifier(context, modifier)
|
|
|
|
|
|
class VIEWLAYER_PT_freestyle_linestyle_thickness(ViewLayerFreestyleLineStyle, Panel):
|
|
bl_label = "Freestyle Thickness"
|
|
bl_options = {'DEFAULT_CLOSED'}
|
|
|
|
def draw_thickness_modifier(self, context, modifier):
|
|
layout = self.layout
|
|
|
|
col = layout.column(align=True)
|
|
draw_modifier_box_header(col.box(), modifier)
|
|
if modifier.expanded:
|
|
box = col.box()
|
|
draw_modifier_common(box, modifier)
|
|
|
|
if modifier.type == 'ALONG_STROKE':
|
|
draw_modifier_curve_common(box, modifier, False, True)
|
|
|
|
elif modifier.type == 'DISTANCE_FROM_OBJECT':
|
|
box.prop(modifier, "target")
|
|
draw_modifier_curve_common(box, modifier, True, True)
|
|
props = box.operator("scene.freestyle_fill_range_by_selection")
|
|
props.type = 'THICKNESS'
|
|
props.name = modifier.name
|
|
|
|
elif modifier.type == 'DISTANCE_FROM_CAMERA':
|
|
draw_modifier_curve_common(box, modifier, True, True)
|
|
props = box.operator("scene.freestyle_fill_range_by_selection")
|
|
props.type = 'THICKNESS'
|
|
props.name = modifier.name
|
|
|
|
elif modifier.type == 'MATERIAL':
|
|
box.prop(modifier, "material_attribute", text="Material Attribute")
|
|
draw_modifier_curve_common(box, modifier, False, True)
|
|
|
|
elif modifier.type == 'CALLIGRAPHY':
|
|
box.prop(modifier, "orientation")
|
|
subcol = box.column(align=True)
|
|
subcol.prop(modifier, "thickness_min", text="Thickness Min")
|
|
subcol.prop(modifier, "thickness_max", text="Max")
|
|
|
|
elif modifier.type == 'TANGENT':
|
|
self.mapping = 'CURVE'
|
|
subcol = box.column(align=True)
|
|
subcol.prop(modifier, "thickness_min", text="Thickness Min")
|
|
subcol.prop(modifier, "thickness_max", text="Max")
|
|
|
|
draw_modifier_curve_common(box, modifier, False, False)
|
|
|
|
elif modifier.type == 'NOISE':
|
|
col = box.column(align=True)
|
|
col.prop(modifier, "amplitude")
|
|
col.prop(modifier, "period")
|
|
|
|
col = box.column(align=True)
|
|
col.prop(modifier, "seed")
|
|
col.prop(modifier, "use_asymmetric")
|
|
|
|
elif modifier.type == 'CREASE_ANGLE':
|
|
col = box.column(align=True)
|
|
col.prop(modifier, "thickness_min", text="Thickness Min")
|
|
col.prop(modifier, "thickness_max", text="Max")
|
|
|
|
col = box.column(align=True)
|
|
col.prop(modifier, "angle_min", text="Angle Min")
|
|
col.prop(modifier, "angle_max", text="Max")
|
|
|
|
draw_modifier_curve_common(box, modifier, False, False)
|
|
|
|
elif modifier.type == 'CURVATURE_3D':
|
|
subcol = box.column(align=True)
|
|
subcol.prop(modifier, "thickness_min", text="Thickness Min")
|
|
subcol.prop(modifier, "thickness_max", text="Max")
|
|
|
|
subcol = box.column(align=True)
|
|
subcol.prop(modifier, "curvature_min")
|
|
subcol.prop(modifier, "curvature_max")
|
|
|
|
draw_modifier_curve_common(box, modifier, False, False)
|
|
|
|
freestyle = context.view_layer.freestyle_settings
|
|
if not freestyle.use_smoothness:
|
|
message = "Enable Face Smoothness to use this modifier"
|
|
draw_modifier_box_error(col.box(), modifier, message)
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = False
|
|
|
|
view_layer = context.view_layer
|
|
lineset = view_layer.freestyle_settings.linesets.active
|
|
|
|
layout.active = view_layer.use_freestyle
|
|
|
|
if lineset is None:
|
|
return
|
|
linestyle = lineset.linestyle
|
|
|
|
if linestyle is None:
|
|
return
|
|
|
|
row = layout.row(align=True)
|
|
row.alignment = 'LEFT'
|
|
row.label(text=lineset.name, icon='LINE_DATA', translate=False)
|
|
row.label(text="", icon='RIGHTARROW')
|
|
row.label(text=linestyle.name, translate=False)
|
|
|
|
col = layout.column()
|
|
row = col.row()
|
|
row.prop(linestyle, "thickness", text="Base Thickness")
|
|
subcol = col.column()
|
|
subcol.active = linestyle.chaining == 'PLAIN' and linestyle.use_same_object
|
|
row = subcol.row()
|
|
row.prop(linestyle, "thickness_position", expand=False)
|
|
|
|
if linestyle.thickness_position == 'RELATIVE':
|
|
row = subcol.row()
|
|
row.prop(linestyle, "thickness_ratio")
|
|
|
|
col = layout.column()
|
|
col.operator_menu_enum("scene.freestyle_thickness_modifier_add", "type", text="Add Modifier")
|
|
for modifier in linestyle.thickness_modifiers:
|
|
self.draw_thickness_modifier(context, modifier)
|
|
|
|
|
|
class VIEWLAYER_PT_freestyle_linestyle_geometry(ViewLayerFreestyleLineStyle, Panel):
|
|
bl_label = "Freestyle Geometry"
|
|
bl_options = {'DEFAULT_CLOSED'}
|
|
|
|
def draw_geometry_modifier(self, _context, modifier):
|
|
layout = self.layout
|
|
|
|
col = layout.column(align=True)
|
|
draw_modifier_box_header(col.box(), modifier)
|
|
if modifier.expanded:
|
|
box = col.box()
|
|
|
|
if modifier.type == 'SAMPLING':
|
|
box.prop(modifier, "sampling")
|
|
|
|
elif modifier.type == 'BEZIER_CURVE':
|
|
box.prop(modifier, "error")
|
|
|
|
elif modifier.type == 'SINUS_DISPLACEMENT':
|
|
col = box.column(align=True)
|
|
col.prop(modifier, "wavelength")
|
|
col.prop(modifier, "amplitude")
|
|
|
|
col = box.column(align=True)
|
|
col.prop(modifier, "phase")
|
|
|
|
elif modifier.type == 'SPATIAL_NOISE':
|
|
col = box.column(align=True)
|
|
col.prop(modifier, "amplitude")
|
|
col.prop(modifier, "scale")
|
|
col.prop(modifier, "octaves")
|
|
|
|
col = box.column(align=True)
|
|
col.prop(modifier, "smooth")
|
|
col.prop(modifier, "use_pure_random")
|
|
|
|
elif modifier.type == 'PERLIN_NOISE_1D':
|
|
col = box.column(align=True)
|
|
col.prop(modifier, "frequency")
|
|
col.prop(modifier, "amplitude")
|
|
col.prop(modifier, "seed")
|
|
|
|
col = box.column(align=True)
|
|
col.prop(modifier, "octaves")
|
|
col.prop(modifier, "angle")
|
|
|
|
elif modifier.type == 'PERLIN_NOISE_2D':
|
|
col = box.column(align=True)
|
|
col.prop(modifier, "frequency")
|
|
col.prop(modifier, "amplitude")
|
|
col.prop(modifier, "seed")
|
|
|
|
col = box.column(align=True)
|
|
col.prop(modifier, "octaves")
|
|
col.prop(modifier, "angle")
|
|
|
|
elif modifier.type == 'BACKBONE_STRETCHER':
|
|
box.prop(modifier, "backbone_length")
|
|
|
|
elif modifier.type == 'TIP_REMOVER':
|
|
box.prop(modifier, "tip_length")
|
|
|
|
elif modifier.type == 'POLYGONIZATION':
|
|
box.prop(modifier, "error")
|
|
|
|
elif modifier.type == 'GUIDING_LINES':
|
|
box.prop(modifier, "offset")
|
|
|
|
elif modifier.type == 'BLUEPRINT':
|
|
row = box.row()
|
|
row.prop(modifier, "shape", expand=True)
|
|
box.prop(modifier, "rounds")
|
|
subcol = box.column(align=True)
|
|
if modifier.shape in {'CIRCLES', 'ELLIPSES'}:
|
|
subcol.prop(modifier, "random_radius", text="Random Radius")
|
|
subcol.prop(modifier, "random_center", text="Center")
|
|
elif modifier.shape == 'SQUARES':
|
|
subcol.prop(modifier, "backbone_length", text="Backbone Length")
|
|
subcol.prop(modifier, "random_backbone", text="Randomness")
|
|
|
|
elif modifier.type == '2D_OFFSET':
|
|
subcol = box.column(align=True)
|
|
subcol.prop(modifier, "start")
|
|
subcol.prop(modifier, "end")
|
|
|
|
subcol = box.column(align=True)
|
|
subcol.prop(modifier, "x")
|
|
subcol.prop(modifier, "y")
|
|
|
|
elif modifier.type == '2D_TRANSFORM':
|
|
box.prop(modifier, "pivot")
|
|
if modifier.pivot == 'PARAM':
|
|
box.prop(modifier, "pivot_u")
|
|
elif modifier.pivot == 'ABSOLUTE':
|
|
subcol = box.column(align=True)
|
|
subcol.prop(modifier, "pivot_x", text="Pivot X")
|
|
subcol.prop(modifier, "pivot_y", text="Y")
|
|
subcol = box.column(align=True)
|
|
subcol.prop(modifier, "scale_x", text="Scale X")
|
|
subcol.prop(modifier, "scale_y", text="Y")
|
|
box.prop(modifier, "angle")
|
|
|
|
elif modifier.type == 'SIMPLIFICATION':
|
|
box.prop(modifier, "tolerance")
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = False
|
|
|
|
view_layer = context.view_layer
|
|
lineset = view_layer.freestyle_settings.linesets.active
|
|
|
|
layout.active = view_layer.use_freestyle
|
|
|
|
if lineset is None:
|
|
return
|
|
linestyle = lineset.linestyle
|
|
|
|
if linestyle is None:
|
|
return
|
|
|
|
row = layout.row(align=True)
|
|
row.alignment = 'LEFT'
|
|
row.label(text=lineset.name, icon='LINE_DATA', translate=False)
|
|
row.label(text="", icon='RIGHTARROW')
|
|
row.label(text=linestyle.name, translate=False)
|
|
|
|
col = layout.column()
|
|
col.operator_menu_enum("scene.freestyle_geometry_modifier_add", "type", text="Add Modifier")
|
|
for modifier in linestyle.geometry_modifiers:
|
|
self.draw_geometry_modifier(context, modifier)
|
|
|
|
|
|
class VIEWLAYER_PT_freestyle_linestyle_texture(ViewLayerFreestyleLineStyle, Panel):
|
|
bl_label = "Freestyle Texture"
|
|
bl_options = {'DEFAULT_CLOSED'}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = False
|
|
|
|
view_layer = context.view_layer
|
|
lineset = view_layer.freestyle_settings.linesets.active
|
|
|
|
layout.active = view_layer.use_freestyle
|
|
|
|
if lineset is None:
|
|
return
|
|
linestyle = lineset.linestyle
|
|
|
|
if linestyle is None:
|
|
return
|
|
|
|
row = layout.row(align=True)
|
|
row.alignment = 'LEFT'
|
|
row.label(text=lineset.name, icon='LINE_DATA', translate=False)
|
|
row.label(text="", icon='RIGHTARROW')
|
|
row.label(text=linestyle.name, translate=False)
|
|
|
|
layout.prop(linestyle, "use_nodes")
|
|
layout.prop(linestyle, "texture_spacing", text="Spacing Along Stroke")
|
|
|
|
row = layout.row()
|
|
props = row.operator(
|
|
"wm.properties_context_change",
|
|
text="Go to Linestyle Textures Properties",
|
|
icon='TEXTURE',
|
|
)
|
|
props.context = 'TEXTURE'
|
|
|
|
|
|
class VIEWLAYER_PT_freestyle_animation(ViewLayerFreestyleButtonsPanel, PropertiesAnimationMixin, Panel):
|
|
bl_label = "Freestyle Animation"
|
|
COMPAT_ENGINES = {
|
|
'BLENDER_RENDER',
|
|
'BLENDER_EEVEE_NEXT',
|
|
'BLENDER_WORKBENCH',
|
|
}
|
|
|
|
@classmethod
|
|
def _animated_id(cls, context):
|
|
try:
|
|
return context.view_layer.freestyle_settings.linesets.active.linestyle
|
|
except AttributeError:
|
|
return None
|
|
|
|
|
|
# Material properties
|
|
class MaterialFreestyleButtonsPanel:
|
|
bl_space_type = 'PROPERTIES'
|
|
bl_region_type = 'WINDOW'
|
|
bl_context = "material"
|
|
# COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
scene = context.scene
|
|
material = context.material
|
|
with_freestyle = bpy.app.build_options.freestyle
|
|
return (
|
|
with_freestyle and
|
|
material and
|
|
scene and
|
|
scene.render.use_freestyle and
|
|
(context.engine in cls.COMPAT_ENGINES)
|
|
)
|
|
|
|
|
|
class MATERIAL_PT_freestyle_line(MaterialFreestyleButtonsPanel, Panel):
|
|
bl_label = "Freestyle Line"
|
|
bl_options = {'DEFAULT_CLOSED'}
|
|
COMPAT_ENGINES = {
|
|
'BLENDER_RENDER',
|
|
'BLENDER_EEVEE_NEXT',
|
|
'BLENDER_WORKBENCH',
|
|
}
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
layout.use_property_decorate = False
|
|
|
|
mat = context.material
|
|
|
|
col = layout.column()
|
|
col.prop(mat, "line_color")
|
|
col.prop(mat, "line_priority", text="Priority")
|
|
|
|
|
|
classes = (
|
|
RENDER_PT_freestyle,
|
|
VIEWLAYER_UL_linesets,
|
|
RENDER_MT_lineset_context_menu,
|
|
VIEWLAYER_PT_freestyle,
|
|
VIEWLAYER_PT_freestyle_edge_detection,
|
|
VIEWLAYER_PT_freestyle_style_modules,
|
|
VIEWLAYER_PT_freestyle_lineset,
|
|
VIEWLAYER_PT_freestyle_lineset_visibilty,
|
|
VIEWLAYER_PT_freestyle_lineset_edgetype,
|
|
VIEWLAYER_PT_freestyle_lineset_facemarks,
|
|
VIEWLAYER_PT_freestyle_lineset_collection,
|
|
VIEWLAYER_PT_freestyle_linestyle_strokes,
|
|
VIEWLAYER_PT_freestyle_linestyle_strokes_chaining,
|
|
VIEWLAYER_PT_freestyle_linestyle_strokes_splitting,
|
|
VIEWLAYER_PT_freestyle_linestyle_strokes_splitting_pattern,
|
|
VIEWLAYER_PT_freestyle_linestyle_strokes_sorting,
|
|
VIEWLAYER_PT_freestyle_linestyle_strokes_selection,
|
|
VIEWLAYER_PT_freestyle_linestyle_strokes_dashedline,
|
|
VIEWLAYER_PT_freestyle_linestyle_color,
|
|
VIEWLAYER_PT_freestyle_linestyle_alpha,
|
|
VIEWLAYER_PT_freestyle_linestyle_thickness,
|
|
VIEWLAYER_PT_freestyle_linestyle_geometry,
|
|
VIEWLAYER_PT_freestyle_linestyle_texture,
|
|
VIEWLAYER_PT_freestyle_animation,
|
|
MATERIAL_PT_freestyle_line,
|
|
)
|
|
|
|
if __name__ == "__main__": # only for live edit.
|
|
from bpy.utils import register_class
|
|
|
|
for cls in classes:
|
|
register_class(cls)
|