145 lines
3.7 KiB
Python
145 lines
3.7 KiB
Python
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
import bpy
|
|
import math
|
|
|
|
from collections import namedtuple
|
|
|
|
from bpy.props import (
|
|
BoolProperty,
|
|
IntProperty,
|
|
FloatProperty,
|
|
PointerProperty
|
|
)
|
|
|
|
|
|
ScatterSettings = namedtuple("ScatterSettings",
|
|
["seed", "density", "radius", "scale", "random_scale",
|
|
"rotation", "normal_offset", "use_normal_rotation"])
|
|
|
|
class ObjectScatterProperties(bpy.types.PropertyGroup):
|
|
seed: IntProperty(
|
|
name="Seed",
|
|
default=0,
|
|
description="Change it to get a different scatter pattern",
|
|
)
|
|
|
|
density: FloatProperty(
|
|
name="Density",
|
|
default=10,
|
|
min=0,
|
|
soft_max=50,
|
|
description="The amount of objects per unit on the line",
|
|
)
|
|
|
|
radius: FloatProperty(
|
|
name="Radius",
|
|
default=1,
|
|
min=0,
|
|
soft_max=5,
|
|
subtype='DISTANCE',
|
|
unit='LENGTH',
|
|
description="Maximum distance of the objects to the line",
|
|
)
|
|
|
|
scale: FloatProperty(
|
|
name="Scale",
|
|
default=0.3,
|
|
min=0.00001,
|
|
soft_max=1,
|
|
description="Size of the generated objects",
|
|
)
|
|
|
|
random_scale_percentage: FloatProperty(
|
|
name="Random Scale Percentage",
|
|
default=80,
|
|
min=0,
|
|
max=100,
|
|
subtype='PERCENTAGE',
|
|
precision=0,
|
|
description="Increase to get a larger range of sizes",
|
|
)
|
|
|
|
rotation: FloatProperty(
|
|
name="Rotation",
|
|
default=0.5,
|
|
min=0,
|
|
max=math.pi * 2,
|
|
soft_max=math.pi / 2,
|
|
subtype='ANGLE',
|
|
unit='ROTATION',
|
|
description="Maximum rotation of the generated objects",
|
|
)
|
|
|
|
normal_offset: FloatProperty(
|
|
name="Normal Offset",
|
|
default=0,
|
|
soft_min=-1.0,
|
|
soft_max=1.0,
|
|
description="Distance from the surface",
|
|
)
|
|
|
|
use_normal_rotation: BoolProperty(
|
|
name="Use Normal Rotation",
|
|
default=True,
|
|
description="Rotate the instances according to the surface normals",
|
|
)
|
|
|
|
def to_settings(self):
|
|
return ScatterSettings(
|
|
seed=self.seed,
|
|
density=self.density,
|
|
radius=self.radius,
|
|
scale=self.scale,
|
|
random_scale=self.random_scale_percentage / 100,
|
|
rotation=self.rotation,
|
|
normal_offset=self.normal_offset,
|
|
use_normal_rotation=self.use_normal_rotation,
|
|
)
|
|
|
|
|
|
class ObjectScatterPanel(bpy.types.Panel):
|
|
bl_idname = "OBJECT_PT_object_scatter"
|
|
bl_label = "Object Scatter"
|
|
bl_space_type = 'VIEW_3D'
|
|
bl_region_type = 'UI'
|
|
bl_category = "Tool"
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = True
|
|
scatter = context.scene.scatter_properties
|
|
|
|
layout.prop(scatter, "density", slider=True)
|
|
layout.prop(scatter, "radius", slider=True)
|
|
|
|
col = layout.column(align=True)
|
|
col.prop(scatter, "scale", slider=True)
|
|
col.prop(scatter, "random_scale_percentage", text="Randomness", slider=True)
|
|
|
|
layout.prop(scatter, "use_normal_rotation")
|
|
layout.prop(scatter, "rotation", slider=True)
|
|
layout.prop(scatter, "normal_offset", text="Offset", slider=True)
|
|
layout.prop(scatter, "seed")
|
|
|
|
def draw_menu(self, context):
|
|
layout = self.layout
|
|
layout.operator("object.scatter")
|
|
|
|
classes = (
|
|
ObjectScatterProperties,
|
|
ObjectScatterPanel,
|
|
)
|
|
|
|
def register():
|
|
for cls in classes:
|
|
bpy.utils.register_class(cls)
|
|
bpy.types.Scene.scatter_properties = PointerProperty(type=ObjectScatterProperties)
|
|
bpy.types.VIEW3D_MT_object.append(draw_menu)
|
|
|
|
def unregister():
|
|
for cls in classes:
|
|
bpy.utils.unregister_class(cls)
|
|
del bpy.types.Scene.scatter_properties
|
|
bpy.types.VIEW3D_MT_object.remove(draw_menu)
|