diff --git a/bdk_addon/property_group_helpers.py b/bdk_addon/property_group_helpers.py index 62dd925..791e2a1 100644 --- a/bdk_addon/property_group_helpers.py +++ b/bdk_addon/property_group_helpers.py @@ -3,6 +3,7 @@ def add_curve_modifier_properties(cls): # Add the curve modifier properties to the type annotation of the given class. + cls.__annotations__['use_curve_modifiers'] = BoolProperty(name='Use Curve Modifiers', default=False) cls.__annotations__['is_curve_reversed'] = BoolProperty(name='Reverse Curve', default=False) # TODO: Rename to curve_is_reversed cls.__annotations__['curve_trim_mode'] = EnumProperty(name='Trim Mode', items=(('NONE', 'None', '', 0), ('FACTOR', 'Factor', '', 1),('LENGTH', 'Distance', '', 2),), default='NONE') cls.__annotations__['curve_trim_factor_start'] = FloatProperty(name='Trim Factor Start', default=0.0, min=0.0, max=1.0, subtype='FACTOR') diff --git a/bdk_addon/terrain/doodad/builder.py b/bdk_addon/terrain/doodad/builder.py index ba5d075..b886389 100644 --- a/bdk_addon/terrain/doodad/builder.py +++ b/bdk_addon/terrain/doodad/builder.py @@ -604,32 +604,43 @@ def add_distance_to_doodad_layer_nodes(node_tree: NodeTree, layer, layer_type: s match terrain_doodad.object.type: case 'CURVE': - curve_modifier_node = node_tree.nodes.new(type='GeometryNodeGroup') - curve_modifier_node.node_tree = ensure_curve_modifier_node_tree() + def add_curve_modifier_nodes(node_tree: NodeTree, layer, layer_type, curve_socket: NodeSocket) -> NodeSocket: + switch_node = node_tree.nodes.new(type='GeometryNodeSwitch') + switch_node.input_type = 'GEOMETRY' + + add_doodad_layer_driver(switch_node.inputs['Switch'], layer, layer_type, 'use_curve_modifiers') + + modifier_node = node_tree.nodes.new(type='GeometryNodeGroup') + modifier_node.node_tree = ensure_curve_modifier_node_tree() + + def add_curve_modifier_driver(input_name: str, data_path: str): + add_doodad_layer_driver(modifier_node.inputs[input_name], layer, layer_type, data_path) + + # Drivers + add_curve_modifier_driver('Is Curve Reversed', 'is_curve_reversed') + add_curve_modifier_driver('Trim Mode', 'curve_trim_mode') + add_curve_modifier_driver('Trim Factor Start', 'curve_trim_factor_start') + add_curve_modifier_driver('Trim Factor End', 'curve_trim_factor_end') + add_curve_modifier_driver('Trim Length Start', 'curve_trim_length_start') + add_curve_modifier_driver('Trim Length End', 'curve_trim_length_end') + add_curve_modifier_driver('Normal Offset', 'curve_normal_offset') + + # Links + node_tree.links.new(curve_socket, modifier_node.inputs['Curve']) + node_tree.links.new(curve_socket, switch_node.inputs['False']) + node_tree.links.new(modifier_node.outputs['Curve'], switch_node.inputs['True']) + + return switch_node.outputs['Output'] distance_to_curve_node = node_tree.nodes.new(type='GeometryNodeGroup') distance_to_curve_node.node_tree = ensure_distance_to_curve_node_group() - def add_curve_modifier_driver(input_name: str, data_path: str): - add_doodad_layer_driver(curve_modifier_node.inputs[input_name], layer, layer_type, data_path) + curve_socket = add_curve_modifier_nodes(node_tree, layer, layer_type, terrain_doodad_object_info_node.outputs['Geometry']) - # Drivers - add_curve_modifier_driver('Is Curve Reversed', 'is_curve_reversed') - add_curve_modifier_driver('Trim Mode', 'curve_trim_mode') - add_curve_modifier_driver('Trim Factor Start', 'curve_trim_factor_start') - add_curve_modifier_driver('Trim Factor End', 'curve_trim_factor_end') - add_curve_modifier_driver('Trim Length Start', 'curve_trim_length_start') - add_curve_modifier_driver('Trim Length End', 'curve_trim_length_end') - add_curve_modifier_driver('Normal Offset', 'curve_normal_offset') - - # Links - node_tree.links.new(terrain_doodad_object_info_node.outputs['Geometry'], - curve_modifier_node.inputs['Curve']) - node_tree.links.new(curve_modifier_node.outputs['Curve'], distance_to_curve_node.inputs['Curve']) + node_tree.links.new(curve_socket, distance_to_curve_node.inputs['Curve']) return distance_to_curve_node.outputs['Distance'] case 'MESH': - # TODO: set up a switch for points vs. faces distance_to_mesh_node_group = ensure_distance_to_mesh_node_group() # Add a new node group node. diff --git a/bdk_addon/terrain/doodad/scatter/builder.py b/bdk_addon/terrain/doodad/scatter/builder.py index 7edf3ee..ffad58f 100644 --- a/bdk_addon/terrain/doodad/scatter/builder.py +++ b/bdk_addon/terrain/doodad/scatter/builder.py @@ -1437,36 +1437,31 @@ def add_scatter_layer_driver(struct: bpy_struct, data_path: str, index: int = -1 spacing_length_socket = spacing_mode_switch_node.outputs['Output'] - curve_modifier_group_node = node_tree.nodes.new(type='GeometryNodeGroup') - curve_modifier_group_node.node_tree = ensure_curve_modifier_node_tree() - - add_scatter_layer_driver(curve_modifier_group_node.inputs['Is Curve Reversed'], - 'is_curve_reversed') - add_scatter_layer_driver(curve_modifier_group_node.inputs['Trim Mode'], 'curve_trim_mode') - add_scatter_layer_driver(curve_modifier_group_node.inputs['Trim Factor Start'], - 'curve_trim_factor_start') - add_scatter_layer_driver(curve_modifier_group_node.inputs['Trim Factor End'], - 'curve_trim_factor_end') - add_scatter_layer_driver(curve_modifier_group_node.inputs['Trim Length Start'], - 'curve_trim_length_start') - add_scatter_layer_driver(curve_modifier_group_node.inputs['Trim Length End'], - 'curve_trim_length_end') - add_scatter_layer_driver(curve_modifier_group_node.inputs['Normal Offset'], - 'curve_normal_offset') - - curve_to_points_group_node = node_tree.nodes.new(type='GeometryNodeGroup') - curve_to_points_group_node.node_tree = ensure_scatter_layer_curve_to_points_node_tree() - - add_scatter_layer_driver(curve_to_points_group_node.inputs['Normal Offset Max'], - 'curve_normal_offset_max') - add_scatter_layer_driver(curve_to_points_group_node.inputs['Normal Offset Seed'], - 'curve_normal_offset_seed') - add_scatter_layer_driver(curve_to_points_group_node.inputs['Tangent Offset Max'], - 'curve_tangent_offset_max') - add_scatter_layer_driver(curve_to_points_group_node.inputs['Tangent Offset Seed'], - 'curve_tangent_offset_seed') - add_scatter_layer_driver(curve_to_points_group_node.inputs['Global Seed'], 'global_seed') - add_scatter_layer_driver(curve_to_points_group_node.inputs['Fence Mode'], 'fence_mode') + curve_switch_node = node_tree.nodes.new(type='GeometryNodeSwitch') + curve_switch_node.input_type = 'GEOMETRY' + + add_scatter_layer_driver(curve_switch_node.inputs['Switch'], 'use_curve_modifiers') + + curve_modifier_node = node_tree.nodes.new(type='GeometryNodeGroup') + curve_modifier_node.node_tree = ensure_curve_modifier_node_tree() + + add_scatter_layer_driver(curve_modifier_node.inputs['Is Curve Reversed'], 'is_curve_reversed') + add_scatter_layer_driver(curve_modifier_node.inputs['Trim Mode'], 'curve_trim_mode') + add_scatter_layer_driver(curve_modifier_node.inputs['Trim Factor Start'], 'curve_trim_factor_start') + add_scatter_layer_driver(curve_modifier_node.inputs['Trim Factor End'], 'curve_trim_factor_end') + add_scatter_layer_driver(curve_modifier_node.inputs['Trim Length Start'], 'curve_trim_length_start') + add_scatter_layer_driver(curve_modifier_node.inputs['Trim Length End'], 'curve_trim_length_end') + add_scatter_layer_driver(curve_modifier_node.inputs['Normal Offset'], 'curve_normal_offset') + + curve_to_points_node = node_tree.nodes.new(type='GeometryNodeGroup') + curve_to_points_node.node_tree = ensure_scatter_layer_curve_to_points_node_tree() + + add_scatter_layer_driver(curve_to_points_node.inputs['Normal Offset Max'], 'curve_normal_offset_max') + add_scatter_layer_driver(curve_to_points_node.inputs['Normal Offset Seed'], 'curve_normal_offset_seed') + add_scatter_layer_driver(curve_to_points_node.inputs['Tangent Offset Max'], 'curve_tangent_offset_max') + add_scatter_layer_driver(curve_to_points_node.inputs['Tangent Offset Seed'], 'curve_tangent_offset_seed') + add_scatter_layer_driver(curve_to_points_node.inputs['Global Seed'], 'global_seed') + add_scatter_layer_driver(curve_to_points_node.inputs['Fence Mode'], 'fence_mode') shrinkwrap_curve_to_terrain_node = node_tree.nodes.new(type='GeometryNodeGroup') shrinkwrap_curve_to_terrain_node.node_tree = ensure_shrinkwrap_curve_to_terrain_node_tree() @@ -1479,27 +1474,22 @@ def add_scatter_layer_driver(struct: bpy_struct, data_path: str, index: int = -1 terrain_info_object_node = node_tree.nodes.new(type='GeometryNodeObjectInfo') terrain_info_object_node.inputs['Object'].default_value = terrain_info.terrain_info_object - node_tree.links.new(terrain_doodad_object_info_node.outputs['Geometry'], - shrinkwrap_curve_to_terrain_node.inputs['Curve']) - node_tree.links.new(terrain_info_object_node.outputs['Geometry'], - shrinkwrap_curve_to_terrain_node.inputs['Terrain Geometry']) + node_tree.links.new(terrain_doodad_object_info_node.outputs['Geometry'], shrinkwrap_curve_to_terrain_node.inputs['Curve']) + node_tree.links.new(terrain_info_object_node.outputs['Geometry'], shrinkwrap_curve_to_terrain_node.inputs['Terrain Geometry']) node_tree.links.new(terrain_info_object_node.outputs['Transform'], shrinkwrap_curve_to_terrain_node.inputs['Terrain Transform']) - node_tree.links.new(shrinkwrap_curve_to_terrain_node.outputs['Curve'], - shrinkwrap_curve_to_terrain_switch_node.inputs['True']) - node_tree.links.new(terrain_doodad_object_info_node.outputs['Geometry'], - shrinkwrap_curve_to_terrain_switch_node.inputs['False']) + node_tree.links.new(shrinkwrap_curve_to_terrain_node.outputs['Curve'], shrinkwrap_curve_to_terrain_switch_node.inputs['True']) + node_tree.links.new(terrain_doodad_object_info_node.outputs['Geometry'], shrinkwrap_curve_to_terrain_switch_node.inputs['False']) - node_tree.links.new(shrinkwrap_curve_to_terrain_switch_node.outputs['Output'], - curve_modifier_group_node.inputs['Curve']) - node_tree.links.new(curve_modifier_group_node.outputs['Curve'], - curve_to_points_group_node.inputs['Curve']) + node_tree.links.new(shrinkwrap_curve_to_terrain_switch_node.outputs['Output'], curve_modifier_node.inputs['Curve']) + node_tree.links.new(shrinkwrap_curve_to_terrain_switch_node.outputs['Output'], curve_switch_node.inputs['False']) + node_tree.links.new(curve_modifier_node.outputs['Curve'], curve_switch_node.inputs['True']) + node_tree.links.new(curve_switch_node.outputs['Output'], curve_to_points_node.inputs['Curve']) if spacing_length_socket is not None: - node_tree.links.new(spacing_length_socket, - curve_to_points_group_node.inputs['Spacing Length']) + node_tree.links.new(spacing_length_socket, curve_to_points_node.inputs['Spacing Length']) - points_socket = curve_to_points_group_node.outputs['Points'] + points_socket = curve_to_points_node.outputs['Points'] case 'EMPTY': # TODO: we're gonna certainly want more options here (e.g., random distance/angle from the # center) diff --git a/bdk_addon/terrain/doodad/ui.py b/bdk_addon/terrain/doodad/ui.py index 05003be..1e2390b 100644 --- a/bdk_addon/terrain/doodad/ui.py +++ b/bdk_addon/terrain/doodad/ui.py @@ -567,28 +567,32 @@ def draw(self, context: 'Context'): flow.prop(scatter_layer, 'fence_mode') flow.separator() - # Curve settings - draw_curve_modifier_settings(flow, scatter_layer, curve_data=terrain_doodad.object.data) - - flow.separator() - flow.prop(scatter_layer, 'curve_spacing_method') - - match scatter_layer.curve_spacing_method: - case'RELATIVE': - flow.prop(scatter_layer, 'curve_spacing_relative_axis', text='Axis') - flow.prop(scatter_layer, 'curve_spacing_relative_factor', text='Factor') - case 'ABSOLUTE': - flow.prop(scatter_layer, 'curve_spacing_absolute', text='Distance') - - flow.separator() - - flow.prop(scatter_layer, 'curve_normal_offset_max', text='Normal Offset Max') - flow.prop(scatter_layer, 'curve_normal_offset_seed', text='Seed') - - flow.separator() - - flow.prop(scatter_layer, 'curve_tangent_offset_max', text='Tangent Offset Max') - flow.prop(scatter_layer, 'curve_tangent_offset_seed', text='Seed') + # Curve Modifiers + draw_curve_modifier_settings(flow, scatter_layer) + + # Spacing + spacing_header, spacing_panel = flow.panel('Spacing', default_closed=True) + spacing_header.label(text='Spacing') + if spacing_panel: + col = spacing_panel.column(align=True) + col.prop(scatter_layer, 'curve_spacing_method') + match scatter_layer.curve_spacing_method: + case'RELATIVE': + col.prop(scatter_layer, 'curve_spacing_relative_axis', text='Axis') + col.prop(scatter_layer, 'curve_spacing_relative_factor', text='Factor') + case 'ABSOLUTE': + col.prop(scatter_layer, 'curve_spacing_absolute', text='Distance') + + # Offsets + offsets_header, offsets_panel = flow.panel('Offsets', default_closed=True) + offsets_header.label(text='Offsets') + if offsets_panel: + col = offsets_panel.column(align=True) + col.prop(scatter_layer, 'curve_normal_offset_max', text='Normal Offset Max') + col.prop(scatter_layer, 'curve_normal_offset_seed', text='Seed') + col.separator() + col.prop(scatter_layer, 'curve_tangent_offset_max', text='Tangent Offset Max') + col.prop(scatter_layer, 'curve_tangent_offset_seed', text='Seed') def get_selected_terrain_doodad_scatter_layer_object(context: Context): @@ -867,24 +871,27 @@ def draw(self, context): flow.prop(scatter_layer, 'actor_group', text='Group') -def draw_curve_modifier_settings(layout: UILayout, data, curve_data: Curve = None): - layout.prop(data, 'is_curve_reversed') - layout.prop(data, 'curve_normal_offset') - - layout.separator() - - layout.prop(data, 'curve_trim_mode') - - if data.curve_trim_mode == 'FACTOR': - col = layout.column(align=True) - col.prop(data, 'curve_trim_factor_start', text='Trim Start') - col.prop(data, 'curve_trim_factor_end', text='End') - if data.curve_trim_factor_start >= data.curve_trim_factor_end: - layout.label(text='Trim start should be less than trim end', icon='ERROR') - elif data.curve_trim_mode == 'LENGTH': - col = layout.column(align=True) - col.prop(data, 'curve_trim_length_start', text='Trim Start') - col.prop(data, 'curve_trim_length_end', text='End') +def draw_curve_modifier_settings(layout: UILayout, data): + curve_modifier_header, curve_modifier_panel = layout.panel('Curve Modifiers', default_closed=True) + curve_modifier_header.use_property_split = False + curve_modifier_header.prop(data, 'use_curve_modifiers', text='Curve Modifiers') + if curve_modifier_panel: + curve_modifier_panel.prop(data, 'is_curve_reversed') + curve_modifier_panel.prop(data, 'curve_normal_offset') + curve_modifier_panel.separator() + curve_modifier_panel.prop(data, 'curve_trim_mode') + + match data.curve_trim_mode: + case 'FACTOR': + col = curve_modifier_panel.column(align=True) + col.prop(data, 'curve_trim_factor_start', text='Trim Start') + col.prop(data, 'curve_trim_factor_end', text='End') + if data.curve_trim_factor_start >= data.curve_trim_factor_end: + curve_modifier_panel.label(text='Trim start should be less than trim end', icon='ERROR') + case 'LENGTH': + col = curve_modifier_panel.column(align=True) + col.prop(data, 'curve_trim_length_start', text='Trim Start') + col.prop(data, 'curve_trim_length_end', text='End') class BDK_PT_terrain_doodad_scatter_layer_settings(Panel):