WIP: uv-simple-select #1

Closed
Chris Blackbourn wants to merge 182 commits from uv-simple-select into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
2 changed files with 103 additions and 34 deletions
Showing only changes of commit 637dcd8a0a - Show all commits

View File

@ -36,67 +36,135 @@ class ObjectModeOperator:
class QuickFur(ObjectModeOperator, Operator): class QuickFur(ObjectModeOperator, Operator):
"""Add fur setup to the selected objects""" """Add a fur setup to the selected objects"""
bl_idname = "object.quick_fur" bl_idname = "object.quick_fur"
bl_label = "Quick Fur" bl_label = "Quick Fur"
bl_options = {'REGISTER', 'UNDO'} bl_options = {'REGISTER', 'UNDO'}
density: EnumProperty( density: EnumProperty(
name="Fur Density", name="Density",
items=( items=(
('LIGHT', "Light", ""), ('LOW', "Low", ""),
('MEDIUM', "Medium", ""), ('MEDIUM', "Medium", ""),
('HEAVY', "Heavy", ""), ('HIGH', "High", ""),
), ),
default='MEDIUM', default='MEDIUM',
) )
view_percentage: IntProperty(
name="View %",
min=1, max=100,
soft_min=1, soft_max=100,
default=10,
)
length: FloatProperty( length: FloatProperty(
name="Length", name="Length",
min=0.001, max=100, min=0.001, max=100,
soft_min=0.01, soft_max=10, soft_min=0.01, soft_max=10,
default=0.1, default=0.1,
subtype='DISTANCE'
)
radius: FloatProperty(
name="Hair Radius",
min=0.0, max=10,
soft_min=0.0001, soft_max=0.1,
default=0.001,
subtype='DISTANCE'
)
view_percentage: FloatProperty(
name="View Percentage",
min=0.0, max=1.0,
default=1.0,
subtype='FACTOR'
)
apply_hair_guides: BoolProperty(
name="Apply Hair Guides",
default=True,
)
use_noise: BoolProperty(
name="Noise",
default=True,
)
use_frizz: BoolProperty(
name="Frizz",
default=True,
) )
def execute(self, context): def execute(self, context):
fake_context = context.copy() import os
mesh_objects = [obj for obj in context.selected_objects mesh_objects = [obj for obj in context.selected_objects if obj.type == 'MESH']
if obj.type == 'MESH']
if not mesh_objects: if not mesh_objects:
self.report({'ERROR'}, "Select at least one mesh object") self.report({'ERROR'}, "Select at least one mesh object")
return {'CANCELLED'} return {'CANCELLED'}
mat = bpy.data.materials.new("Fur Material") if self.density == 'LOW':
count = 1000
for obj in mesh_objects:
fake_context["object"] = obj
bpy.ops.object.particle_system_add(fake_context)
psys = obj.particle_systems[-1]
psys.settings.type = 'HAIR'
if self.density == 'LIGHT':
psys.settings.count = 100
elif self.density == 'MEDIUM': elif self.density == 'MEDIUM':
psys.settings.count = 1000 count = 10000
elif self.density == 'HEAVY': elif self.density == 'HIGH':
psys.settings.count = 10000 count = 100000
psys.settings.child_nbr = self.view_percentage node_groups_to_append = {"Generate Hair Curves", "Set Hair Curve Profile", "Interpolate Hair Curves"}
psys.settings.hair_length = self.length if self.use_noise:
psys.settings.use_strand_primitive = True node_groups_to_append.add("Hair Curves Noise")
psys.settings.use_hair_bspline = True if self.use_frizz:
psys.settings.child_type = 'INTERPOLATED' node_groups_to_append.add("Frizz Hair Curves")
psys.settings.tip_radius = 0.25 assets_directory = os.path.join(bpy.utils.system_resource('DATAFILES'),
"assets",
"geometry_nodes",
"procedural_hair_node_assets.blend",
"NodeTree")
for name in node_groups_to_append:
bpy.ops.wm.append(directory=assets_directory,
filename=name,
use_recursive=True,
do_reuse_local_id=True)
generate_group = bpy.data.node_groups["Generate Hair Curves"]
interpolate_group = bpy.data.node_groups["Interpolate Hair Curves"]
radius_group = bpy.data.node_groups["Set Hair Curve Profile"]
noise_group = bpy.data.node_groups["Hair Curves Noise"] if self.use_noise else None
frizz_group = bpy.data.node_groups["Frizz Hair Curves"] if self.use_frizz else None
obj.data.materials.append(mat) material = bpy.data.materials.new("Fur Material")
psys.settings.material = len(obj.data.materials)
for mesh_object in mesh_objects:
mesh = mesh_object.data
with context.temp_override(active_object=mesh_object):
bpy.ops.object.curves_empty_hair_add()
curves_object = context.active_object
curves = curves_object.data
curves.materials.append(material)
area = 0.0
for poly in mesh.polygons:
area += poly.area
density = count / area
generate_modifier = curves_object.modifiers.new(name="Generate", type='NODES')
generate_modifier.node_group = generate_group
generate_modifier["Input_2"] = mesh_object
generate_modifier["Input_18_attribute_name"] = curves.surface_uv_map
generate_modifier["Input_20"] = self.length
generate_modifier["Input_22"] = material
generate_modifier["Input_15"] = density * 0.01
curves_object.modifiers.move(1, 0)
radius_modifier = curves_object.modifiers.new(name="Set Hair Curve Profile", type='NODES')
radius_modifier.node_group = radius_group
radius_modifier["Input_3"] = self.radius
interpolate_modifier = curves_object.modifiers.new(name="Interpolate Hair Curves", type='NODES')
interpolate_modifier.node_group = interpolate_group
interpolate_modifier["Input_2"] = mesh_object
interpolate_modifier["Input_18_attribute_name"] = curves.surface_uv_map
interpolate_modifier["Input_15"] = density
interpolate_modifier["Input_17"] = self.view_percentage
interpolate_modifier["Input_24"] = True
if noise_group:
noise_modifier = curves_object.modifiers.new(name="Hair Curves Noise", type='NODES')
noise_modifier.node_group = noise_group
if frizz_group:
frizz_modifier = curves_object.modifiers.new(name="Frizz Hair Curves", type='NODES')
frizz_modifier.node_group = frizz_group
if self.apply_hair_guides:
with context.temp_override(object=curves_object):
bpy.ops.object.modifier_apply(modifier=generate_modifier.name)
return {'FINISHED'} return {'FINISHED'}

View File

@ -2117,6 +2117,7 @@ class VIEW3D_MT_curve_add(Menu):
layout.separator() layout.separator()
layout.operator("object.curves_empty_hair_add", text="Empty Hair", icon='CURVES_DATA') layout.operator("object.curves_empty_hair_add", text="Empty Hair", icon='CURVES_DATA')
layout.operator("object.quick_fur", text="Fur", icon='CURVES_DATA')
experimental = context.preferences.experimental experimental = context.preferences.experimental
if experimental.use_new_curves_tools: if experimental.use_new_curves_tools: