4
$\begingroup$

I would like to create a geometry node tree that randomly rotates every object it is added to. This will let me create, say, one brick, and make each duplicate procedurally rotated slightly differently while still placing them manually.

In other words: for every object, a random value is generated (I don't know if this would use ID or index or something else; I'm not good with Geometry Nodes). This can be fed into some sort of transform node to rotate each object's geometry differently within the node tree.

How can I accomplish this?

$\endgroup$

3 Answers 3

3
$\begingroup$

Update:

you can use this node setup:

enter image description here

unfortunately you have to give each object another value so that it is random.

enter image description here


you could use this node setup:

enter image description here

Just add your objects to that collection.

$\endgroup$
1
  • $\begingroup$ I suppose this is a workable solution, but I would much rather just be able to add a geometry node tree to any object and have it happen just like that. More convenient that way. This is still useful though for other reasons, so thank you! $\endgroup$
    – Legoman
    Commented Feb 20, 2022 at 7:47
3
$\begingroup$

Here's the simplest way I could solve it.

enter image description here

It's not true, full randomization since you need one external object to act as seed and it is location-dependent so they keep rotating if you move them (if two objects are in the same world-position, their rotations are also the same) but it's a quick set-up and would work in many cases (like stationary bricks). The whole point of the seed object is to get a world-coordinate info into the node tree, which I couldn't figure out how to do without an external object but I'm no expert so it might be redundant if there's a simpler method to get stable unique ids per object I'm not aware of.

One other note: the "precision value" here exaggerates the distance between the input object and the seed, so the higher the number, more seed-changes while moving the object. I tried exposing this number in the Group Input as well, but as soon as I do that we lose randomization per object and all copies get the same seed, no matter if it's exposed as a Vector input or Float. I don't know why this happens and I'd appreciate any insight.

enter image description here Min and Max random rotations are exposed in the Group Input so you can independently control them for each object. Here, active object's rotation is limited to the Z axis.

$\endgroup$
3
$\begingroup$

You can add an integer input to your node setup, and add a driver to it in the modifier stack: fmod(hash(name), 10e7).

Then the geo setup:

Then you can duplicate your cube:

❌ The biggest problem with this solution is that it requires enabling Script Auto-execution, which introduces security risks and makes it harder to share work with others. See my answer to another question, where I elaborate.

According to bpy_driver.c in Blender source, there's really no way to convert a string into a somewhat unique number. If not for a 256 character limit of driver expressions, you could use a script like that:

from bpy import context as C
import string

chars = string.ascii_letters + string.digits
significant_characters = 20
base = len(chars)

expr = ""
for i in range(significant_characters):
    for j, c in enumerate(chars):
        if i or j:
            expr += "+"
        expr += f"{base**i+j}*(n[{i}]=='{c}')"
        
C.active_object.animation_data.drivers[0].driver.expression = expr

✅ But to lighten things up, there are some important advantages of this approach: the rotation is decoupled from position. And object can move without rotating if you want it to. An object following another object won't mimic the rotation of the one in front from a moment ago.

$\endgroup$
9
  • $\begingroup$ I've been looking everywhere for a persistent object UID, independent of name and other attributes.. I wonder how the shader node Object Info > 'Random' does it? $\endgroup$
    – Robin Betts
    Commented Feb 20, 2022 at 20:05
  • $\begingroup$ @RobinBetts Probably could be implemented for geometry nodes as well, but it's hidden behind so many layers of abstraction that it's hard to figure what's going on... \source\blender\intern\cycles\kernel\svm\svm.h has svm_node_object_info(kg, sd, stack, node.y, node.z);, which is implemented in svm\geometry.h as data = object_random_number(kg, sd->object);, which is in kernel\geom\object.h and so on... $\endgroup$ Commented Feb 20, 2022 at 20:55
  • $\begingroup$ aaaargh! No wonder I couldn't find it with github alone... Thanks so much for trying ! $\endgroup$
    – Robin Betts
    Commented Feb 20, 2022 at 20:58
  • 1
    $\begingroup$ @RobinBetts Blender is quite tricky when it comes to equality. In Python it's idiomatic to use is to compare identities, but sometimes in bpy it's not a correct way, try this in console: arm = D.armatures[0]; arm.bones[0] is arm.bones[0] - it's not a bug! At each access a new Python wrapper is created for a bone, so to compare if two wrappers relate to the same internal object, you actually have to use == or !=... Also in many cases you only have a name, e.g. D.libraries.load(). Also wrappers are short-lived (and you recreate them using names) $\endgroup$ Commented Feb 20, 2022 at 21:27
  • 1
    $\begingroup$ @RobinBetts I think it's here: Blender\source\blender\intern\cycles\scene\object.cpp, line 406: (float)ob->random_id * (1.0f / (float)0xFFFFFFFF), and the random_id is set in cycles\blender\object.cpp line 330 for an instance: object->set_random_id(b_instance.random_id()), and line 335 otherwise: object->set_random_id(hash_uint2(hash_string(object->name.c_str()), 0)) So turns out the random per object really is based on a hash of the name! $\endgroup$ Commented Feb 21, 2022 at 13:02

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .