New member here so please let me know is I'm doing anything wrong in this post and I'll adjust accordingly.

I'd like to create the following image. I create a hexagon (circle with 6 sides), make the face, add one array modifier in x 20 times, another in x&y once to create two rows, then another in y to create many rows. So far so good. I now set origins to geometry and apply a transform random in x & y only. Perfect so far. NOW if I extrude these faces in z, they obviously don't tesselate properly because the rotation has kinda shrunk them when viewed from directly above.

How do I rotate randomly AND maintain the tessellating columns of hexagons afterwards?

Some sort of elaborate boolean cutting operation?

Appreciate any workflow help from the pros here! Many thanks.

enter image description here


A procedural displacement, shader-only approach, using the HexGrid node group discussed here

enter image description here

  • The 'Cell ID' output is used to produce a UV into a Noise texture, to generate a random value
  • That value is used to rotate the Cell UV's, per cell.
  • The U is extracted from the rotated UV, to produce a gradient across the cell, in a random direction
  • The 'Distance From Edge' output is used to subtract from the displacement value, to give a slight bevel on the edges of the hexagons, which cleans up the near-vertical sides of the columns, and sink the cracks between them

enter image description here

  • 2
    $\begingroup$ Fun to play with! Do you have an idea how to get rid of the artifacts for a close-up Robin: i.stack.imgur.com/iUnFg.jpg ? Even if the levels are set to 6 it's still visible... $\endgroup$ – brockmann Feb 14 '20 at 20:55
  • $\begingroup$ @brockmann Yup, that's tough. Racking up the dicing ratio might help, increasing the bevel? But this is far from ideal for displacement. No info in the verticals. Got a script for geometry coming up. $\endgroup$ – Robin Betts Feb 14 '20 at 21:32

You can use the random transform operator to orient a bunch of hexagons randomly, merge them into one object and extrude the outer edge of each hexagon to the back:

enter image description here

  1. For the base geometry, see the answers of How can I make a hexagonal grill?
  2. Apply the array modifiers but disable the Merge property
  3. Separate each hexagon (Edit Mode > P > By Loose Parts)
  4. Select all hexagons in Object Mode and set their origin to the center (Set Origin > Origin to Geometry)
  5. Press F3 to call Randomize Transform and play with the settings:

    enter image description here

  6. Merge all back into one object using CtrlJ

  7. Switch to Edit Mode, select the outer edge of one hexagon and choose Select > Select Similar > Amount of connecting Egdes to get all of them
  8. Extrude the selected edges to the back
  9. Finally add a bevel and subdivision modifier to the mesh
  • 2
    $\begingroup$ Rotating the hexagons doesn't preserve their volume/diameter, shearing would be required for this. $\endgroup$ – Robert Gützkow Feb 14 '20 at 12:17
  • 2
    $\begingroup$ True, but I don't think you can tell the difference for such close-up @RobertGützkow $\endgroup$ – brockmann Feb 14 '20 at 12:31
  • $\begingroup$ Thanks for the reply brockmann, this is almost the same route I have taken at present however the gaps it creates are the problem I'm trying to avoid. $\endgroup$ – dwbell Feb 14 '20 at 16:49

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 :

enter image description here

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 :

enter image description here

  • 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

enter image description here

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

enter image description here

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:
    object.modifiers.new(modifierName, modifierType)
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"

enter image description here

  • 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"

enter image description here

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

enter image description here

  • 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 :

enter image description here

Tweak the "columns" and "rows" at the very beggining of your tree to your liking, and tweak the material to your liking.

Result : enter image description here

For some reason this scene crashes when I try rendering. If it does to for you, create a script in blender and write

import bpy

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

  • 1
    $\begingroup$ Cool to see an answer using Animation Nodes. $\endgroup$ – brockmann Feb 14 '20 at 12:41
  • $\begingroup$ Thanks, seems really overkill relatively to your answer but that was fun ! In France we have a saying "Why make it simple when you can make it complicated ?" $\endgroup$ – Gorgious Feb 14 '20 at 12:44
  • $\begingroup$ Nah. Once you have it, it's nice to play with the values so I think that's absolutely worth it @Georgius $\endgroup$ – brockmann Feb 14 '20 at 12:52
  • 1
    $\begingroup$ Crikey Gorgious, thanks for the in depth response! I'm new to Blender (thanks to 2.8!) so I'm not sure if I can follow your steps without getting lost, but I'll certainly give it a try! I appreciate you taking the time to help very much! $\endgroup$ – dwbell Feb 14 '20 at 16:58

There are limitations on scalar displacement.. as commented.. (apart from being Cycles only, and expensive)

Here's a script to do the tilting in geometry.

  • ShiftACreate a Mesh > Extra Objects > Honeycomb, Z up.
  • In Edit Mode, F fill it. (This may create some unwanted faces)
  • Select a hexagonal face, ShiftG Select Similar > Area
  • CtrlI invert the selection, and X delete those faces.

With the remaining separated hexagons - object selected, in Object Mode, run this script:

import bpy
from  mathutils import Matrix
import random

ob = bpy.context.object
me = ob.data

for p in me.polygons:

    #sh: the variance in tilt. Increase factor for more.
    sh =  random.random() * .5

    ctr = p.center
    rt = random.random() * 6.283185307179586

    mat_trans = Matrix.Translation(ctr)    
    mat_shear = Matrix.Shear('YZ',4,(0,sh))
    mat_rot = Matrix.Rotation(rt, 4, 'Z')

    mat_tilt = mat_rot.inverted() @ mat_shear @ mat_rot
    mat_tilt = mat_trans @ mat_tilt @ mat_trans.inverted()

    for v_idx in p.vertices:
        v =  me.vertices[v_idx]
        v.co = mat_tilt @ v.co

Then you can do your extrusion, bevelling, etc.

enter image description here


Instead of rotation, I suggest using Shear - that is what your sample image is doing. It will avoid distorting the hexagonal profile from above, which I gather is your intention.

The other answers are fascinating and I'm going to play with them, but this seems like the fast solution.

  • 4
    $\begingroup$ While this is good advice, the Shear Tool doesn't work well with proportional editing - it creates non-planar faces (no idea why). And since the OP is using 100+ hexagons, and wants to do it randomly, it would be rather tedious :). $\endgroup$ – Jachym Michal Feb 15 '20 at 14:04
  • 3
    $\begingroup$ The proportional editing + random definitely does wacky things on shear, yes. 100+ faces randomly, owch. A python script that calls shear might be the simplest at that point. Which would be Robin's answer! $\endgroup$ – Emily Feb 16 '20 at 13:18

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.