This will be rather long and is a bit advanced but you can follow along and I will give you the project file at the end. It can be done with animation nodes. First you need to download the latest working version from the animation nodes github : https://animation-nodes.com/#download ,and install it like any other add-on. If you have trouble for this add-on specifically there are some steps in the official documentation for the recurring errors.
- Change the workspace to "Animation Nodes" (Press SHIFT + F3 repeatedly or change it from the topleft corner of any workspace)
- Create a new animation tree
As a general rule, if you are looking for a specific node, press CTRL + A and type parts of the name of the node. Else you can search for it in the submenus using SHIFT + A
- Add two "Integer" inputs, one for the columns, one for the rows (type F2 while a node is selected to rename it)
- Multiply them with a math node to get the total number of hexagons
- Add two "Object instancer" nodes, one for the hexagons, one for the cutting boolean planes. un-check "Copy from source" and set it to "Mesh"
- Add a "Circle mesh" node, set the radial loops to 6 to get hexagons
Add a "Grid mesh" node, set the x and y divisions to 2 to get a square, and set the size to somethin rather large (> 5)
Add a new "Loop Input" subprogram
- Add two "Object" iterators, name them Hexagons and Planes for later
- Add two "Mesh" parameters, name them Hexagon and plane
Add an "Integer" parameter
Add a an "invoke subprogram" node and choose your newly created loop.
- Connect all the relevant nodes like so :
Now we are going to do a bit of math.
Every consecutive hexagon in a column needs to be shifted by a certain amount.
Every consecutive row needs to be shifted by a certain amount, and every other row needs to be shifted a little bit more so that the hexagons fit nicely together.
We will be using a bunch of math nodes to get the exact position of each object. We are transforming the index of each consecutive iteration of the loop to get the x, and y position in the grid, then multiplying them to get the x and y real world positions. These are values I came up with by tinkering and could be gotten mathematically but they work for me.
- Add a new group subprogram, add two "integer" inputs, named index and columns
- Click on the "Output node" button and place it on the right
- Set up the math nodes like so :
- Click on the group input node, then press W and choose "Create invoke node", place it on the right of the loop input node (alternatively add an "invoke subpgrogram" node and choose your group.
- Connect the loop "index" output to the group "index" input
- Connect the loop "columns" output to the group "columns" input
- Add two "Mesh object output" nodes, and pair up each object to its corresponding mesh
In order to create the random cut in each exagon, we are going to rotate each plane randomly and use them as a boolean.
- Add a "Random vector" node, connect the loop index output to its "Seed" input. Set the scale to 30 (meaning the boolean object will rotate randomly between -30 and 30 degrees in each axis)
- Add a "Vector to euleur" node, check "Use degree" and make sure it is set to "Vector to euler"
- Add two "Object transforms output
- On the first one, which will be used by the boolean objects, check all the transforms fields for location and rotation. Plug the plane object into the object input, and the "boolean position" from the previous group in the location. Plus the previous random rotation in the rotation input.
- On the second one, check only the x and y location transforms and the z rotation. Glug in the hexagon object, and the hexagon position from the group to the location. Set the 2 rotation to 30 so the hexagons fit nicely
Almost there ! We are going to write a little script in order to dynamically add modifiers to our objects. Follow along this answer : Is it possible to add modifiers dynamically with animation nodes?
- Add a new input to the "script" node of type "Text" and call it "modifierType"
Change the code to be :
modifierName = modifierName if modifierName != "" else "Fallback"
if not modifierName in object.modifiers:
outObject = object
- Using an "invoke subprogram" node, call your script, plug in the hexagon object and type "solidify" (always without the quotation marks) in the first field, and "SOLIDIFY" in the second one
Let's tweak the solidify so it properly cuts the hexagons
- add an "Object attribute output" and type in the field "modifiers["solidify"].thickness"
- Add a float input value vield and set it to a large negative value, plug it in the value input of the object attribute output
- Add another instance of the script, and this time set the modifier name to "boolean" and the type to "BOOLEAN"
- Using an "invoke subprogram" node, call your script, plug in the boolean plane object and type "solidify" (always without the quotation marks) in the first field, and "SOLIDIFY" in the second one
Let's tweak the solidify modifier
- Add an "Object attribute output" and type in the field "modifiers["solidify"].thickness"
Add a float input value vield and set it to a large negative value
Add another "Object attributes output", write "modifiers["boolean"].object" in the field, plug in the hexagon object in the "object" input and the boolean object in the "value" input
In order to get rid of the boolean objects in the viewport, add an "Object visibility" node, plug in the boolean object and check "Hide in viewport" and "Hide in render"
Last stretch !!
- Add a bevel modifier to the hexagon using the script invoker, name the first field "bevel" and the second "BEVEL"
- Now let us tweak the segments, limit method and width by using "object attribute output" nodes
Add a "Shade object smooth" node, check "Smooth", plug in the hexagon object
Go in the shader editor workspace, add a new material
- Go back in the animation nodes workspace
- Add an "Object material output" and a "material input" nodes, and select the newly created material. Plug the material output into the object material node like so :
Tweak the "columns" and "rows" at the very beggining of your tree to your liking, and tweak the material to your liking.
For some reason this scene crashes when I try rendering. If it does to for you, create a script in blender and write
bpy.ops.render.render( write_still=True )
and click "run" on the top right corner. Be careful to change the render output to where you want it to be rendered before though?
You can check out the blend file here :
You will need animation nodes add-on to tweak the values