4

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?

Gorgious
  • 30,723
  • 2
  • 44
  • 101
Legoman
  • 1,779
  • 8
  • 28
  • 56

3 Answers3

3

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.

Chris
  • 59,454
  • 6
  • 30
  • 84
  • 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! – Legoman Feb 20 '22 at 07:47
3

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.

Kuboå
  • 8,790
  • 1
  • 16
  • 42
3

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.

Markus von Broady
  • 36,563
  • 3
  • 30
  • 99
  • 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? – Robin Betts Feb 20 '22 at 20:05
  • @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... – Markus von Broady Feb 20 '22 at 20:55
  • aaaargh! No wonder I couldn't find it with github alone... Thanks so much for trying ! – Robin Betts Feb 20 '22 at 20:58
  • @RobinBetts BTW, when should an object be unique? For example, if you have files A and B, and you append an object from file A to B, and remove it in A, but later you append the same object from B to A, should it still have the same UID as it had before being removed in A? – Markus von Broady Feb 20 '22 at 21:09
  • groan ... you're right.. there would have to be another layer, 'mesh-instances' and 'object-instances'... the hardest problem in computing.. (beloved of LISP programmers and other philosophers) .. the nature of equality :D – Robin Betts Feb 20 '22 at 21:19
  • 1
    @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) – Markus von Broady Feb 20 '22 at 21:27
  • 1
    @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! – Markus von Broady Feb 21 '22 at 13:02
  • Yikes. That means changing the name changes the value? I'll check it out when I can .. – Robin Betts Feb 21 '22 at 13:58
  • @RobinBetts on my 3.0.0 this gives white for default "Cube" (deterministically, tested twice). Duplicating it will make the duplicate black. Renaming the duplicate from "Cube.001" to "Cube" will make it white, but the original cube stays white - you need to somehow refresh it to make it black.. Doing many things like disconnecting and reconnecting material output, or playing the animation doesn't refresh it. Doing some other things like making a single user copy of a material or renaming the Cube to the same name it already has - does refresh it. – Markus von Broady Feb 21 '22 at 14:22