For a scientific study about air flow distribution through stacked pellets we want to build a model (stl-file) of hunderds of random stacked pellets in space. The individual pellets have all a dimension of 10 mm length and a diameter of 6 mm. The pellets have to be stacked in a way that they can make only surface contact with each other but without cutting through the volume of each other.

Do you think this is possible with Blender?

For illustration (see attachment) I made a small example in CAD software (Geomagic Design) based on a stl-file of one pellet but it is very time consuming to do it manually. By the way… up to now I don’t have any experience with Blender.

Thank you for your answer! enter image description here Paul


I think I might have a solution. I am not sure if it will meet all the requirements, but maybe it will help.

You can achieve the render above by using an awesome add-on called Animation Nodes.

Here are the instructions:

1.Go to https://github.com/JacquesLucke/animation_nodes, download and install the add-on as you would with any other.

2.Make sure the add-on is enabled and then add the object that we will be instancing into the 3d view. In your case the pellet, I used a cylinder.

3.Switch the screen layout from default to compositing.

4.In the node editor, on the bottom, click on the animation nodes tree type. It should be on the right of View Select Add Node. Then, click new.

5.Now we are ready to create the node tree. Each node can be added by pressing Shift A and choose it from there or Ctr A and type the name of the necessary node. I will be using the latter.

6.Press Ctr A , type object instancer and select it. Here you can select how many pellets you want and underneath you can select the pellet model itself(where the little cube is).

  1. Click on the object instancer node and press w. You will get a pie menu. Click on Loop through Objects.Now you will get two more nodes: Invoke subprogram(which will be connected to object instancer) and the Loop input.

8.Press Ctr A again and type Object Transforms Output. Check the XYZ checkboxes on Location and Rotation.

9.Now, on the Loop Input node, grab the black socket that has the word Object next to it, click it and drag to the black socket of the Object Transforms Output.

10.Next, press Ctr A and type random vector . Go back to the Loop input node and drag the blue socket from Index to the Seed of Random vector, then from the Vector of Random Vector to Location of Object Transforms Output.

Play around with the scale and node seed of Random Vector to get the positions that you want.

  1. Finally, let's randomize the rotation: Ctr A , type Random Euler, drag the Index of Loop Input to Seed of Random Euler and from the Euler of Random Euler to Rotation of Object Transforms Output.

And that's it, change the values of scale and seeds of both Random Vector and Random Euler until you get the number of pellets you want. If you want to add more pellets, go to the Object Instancer Node and add as many instances as you need.

Hope this was helpful! If you have any other questions about this method please go ahead!

  • $\begingroup$ Thank you so much for this support and your effort! Indeed... it is not a "closed" solution because of tuning some parameters to avoid the intersection between the individual pellets vs. an optimal stacking/packing. On the other hand I think this solution will be usable for the simulations that I want to do. Despite of the fact that I don't have any experience with Blender it was possible to work through this "mini-manual" without too much obstructions. :-) $\endgroup$ – Paul Janssen Mar 29 '17 at 20:20
  • $\begingroup$ Your welcome! Yes, I am not really sure about the collision aspect. I would suggest researching the Physics and/or the Particles capabilities of Blender. All the best! $\endgroup$ – user37388 Mar 30 '17 at 20:06
  • $\begingroup$ i am looking at a similar challenge, but i struggle with the solution. Would you mind sharing the .blend file? this would be a great starting point! Cheers Lars $\endgroup$ – L4R5 Oct 9 '17 at 19:18

You can use this script, but there is a problem in the collision when you increase the number of cylinders, Can be someone solve the problem of overlap!.

enter image description here

import bpy
from random import randint, random
from math import sqrt, pi

# Function to calculate the distance between two points
def distance(a, b) :
    list , list --> float
    a = list with three element
    b = list with three element

    return the distance between two points in float
    return sqrt((a[0]-b[0])**2+(a[1]-b[1])**2+(a[2]-b[2])**2)

# How many cylinder you want to add
count = 50

# Cylinder properties
radius = 0.15
depth = 0.5

# The cylinder will be created between -domain <--> domain
domain = 1

# Max time to try finding a new location before break the loop
maxTry = 500

# Variable to count how many try has been done
Try = 0

# list with three element to generate locations
location = [0, 0, 0]

# Variable to hold the distant between balls
dist = 0

# True == Won't collide , False == Will collide
State = True

# This tuple will hold centers of created cylinders
locList = ()

while count > 0 :

    # Calculate x, y, z position
    location[0] = randint(-domain*10, domain*10)/10.0
    location[1] = randint(-domain*10, domain*10)/10.0
    location[2] = randint(-domain*10, domain*10)/10.0

    # Start check if it will collide with other cylinders
    for x in locList :
        # Calculate the distant
        dist = distance(x, location)

        # If it's too close make State = False
        if dist < size*2 + 0.1 :
            State = False
        # If it's in a good position State = True
        else :
            State = True

    # The distant is too close , recalculate the location
    if State == False :
        Try += 1

    # After Try reach maxTry break the loop
    if Try > maxTry :

    # Successfully found a New location
    # Add this point
    locList += (location[:],)

    # Smooth the faces

    #Create a new cylinder at the same location, and resize it to an cylinder
    bpy.ops.mesh.primitive_cylinder_add(radius = radius, depth = depth, location = location)

    #Give the cylinder a random orientation
    bpy.ops.transform.rotate(value=(2*pi*random()-1), axis=((2*pi*random()-1), (2*pi*random()-1), (2*pi*random()-1)))

    #Smooth the faces

    # reset Try
    Try = 0

    # Decrease the counter
    count -= 1     

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.