@tool extends StaticBody3D @export var item: Item: set(val): item = val if !is_node_ready(): await ready $Props.multimesh.mesh = item.model $Cone.material_override = item.model.surface_get_material(0) @export var count: int = 10: set(val): count = val update() @export var item_volume: float = 0.2: set(val): item_volume = val item_radius = pow(item_volume,1.0/3.0) update() @export var item_radius: float = 0.0: set(val): item_radius = val item_volume = pow(item_radius, 3.0) update() @export_range(0,60) var slope_angle: float = 45: set(val): slope_angle = val slope_ratio = cos(deg_to_rad(slope_angle)) / sin(deg_to_rad(slope_angle)) print("slope ratio: %f" % slope_ratio) update() var slope_ratio: float = 1.0 @onready var cone: MeshInstance3D = $Cone @onready var props: MultiMeshInstance3D = $Props @onready var collision_shape: CollisionShape3D = $CollisionShape3D func _ready() -> void: props.multimesh = props.multimesh.duplicate() func update() -> void: var volume: float = count * item_volume var three_v_over_pi: float = (3 * volume) / PI var height: float = pow(three_v_over_pi, 1.0/3.0) / pow(slope_ratio, 2.0/3.0) var radius: float = height * slope_ratio var v: float = (1.0/3.0) * PI * pow(radius,2) * height assert(is_equal_approx(v,volume)) cone.scale = Vector3(radius,height,radius) cone.position.y = height/2.0 var slope_length: float = Vector2(radius,height).length() var ring_count: int = ceili(slope_length / (item_radius*2)) var positions: PackedVector3Array = [] var angle: float = 0.0 for ring in range(ring_count): #var perc: float = ring/float(ring_count-1) var slope_l: float = ring * (item_radius * 2) var ring_y: float = height-( sin(deg_to_rad(slope_angle)) * slope_l ) var ring_radius: float = cos(deg_to_rad(slope_angle)) * slope_l var ring_circ: float = ring_radius * TAU var ring_item_count: int = ceili(ring_circ / (item_radius*2)) if ring_item_count == 0: ring_item_count = 1 var ring_angle_offset: float = TAU / ring_item_count for i in range(ring_item_count): angle += ring_angle_offset #var angle: float = ring_angle_offset * i var x: float = cos(angle) * ring_radius var z: float = sin(angle) * ring_radius var pos: Vector3 = Vector3(x,ring_y,z) positions.append(pos) props.multimesh.instance_count = positions.size() for i in range(positions.size()): #DebugDraw3D.draw_sphere(positions[i], item_radius, Color.RED, 0.1) #var y_rot: float = randf() * TAU var y_rot: float = 0 props.multimesh.set_instance_transform(i, Transform3D(Basis(Vector3.UP,y_rot),positions[i])) props.multimesh.visible_instance_count = min(count, positions.size()) #print("Rings: %d, Items: %d" % [ring_count, positions.size()]) #var surface_item_count: int = ceil(pow(count, 2.0/3.0)) #props.multimesh.instance_count = ceil(surface_item_count) #var theta: float = chord_offset / distance_offset #for i in range(surface_item_count): #var away: float = distance_offset * theta #var around: float = theta + 0 #var x: float = cos(around) * away #var z: float = sin(around) * away #var y: float = height - (away * slope_ratio) #var trans: Transform3D = Transform3D(Basis(), Vector3(x,y,z)) #props.multimesh.set_instance_transform(i,trans) #theta += chord_offset / away