Creating instances with predetermined position/rotation?

Hey,

I would like to create an instances that would copy placement and rotation of already existing set of selected objects.

I have no experience with Python, but I suppose this could be done. Would anyone know how to do this?

Thank you for reading!

I’m having trouble visualizing your end result, so feel free to correct me here.

You have a set of objects - let’s call them A, B, and C. You have another object that you plan to instance- D. You want three instances of D that copy the placement and rotation of A, B, and C, respectively. Is that correct?

Yes, exactly that!

Ok, if you want to do this with Python, that’s totally doable :slight_smile: Give me a minute and I’ll whip up a script for you

1 Like

Check into dupliverts and duplifaces.

That’s an interesting idea, but in my case, it’s not what I’m looking for. I need as precise replacement of the mesh as possible, ideally with preserved information such as scale, rotation etc

Select all and then make D the active object. Then press “Ctrl - L” followed by “o”.

If you want to keep A,B and C duplicate them first.

If D should be a collection instance turn it into a collection instance first.

I see. However, preferably, I would like to create instance empties where all those objects are, with their rotation, scale and most importantly, the position.

I would like to be able to move around some of those empties, but Your solution and the solution from Modron would mean I would have to still keep a lot of simplified objects on the scene. Instead of just empties as placeholders.

I hope it make sense.

Hey, just want to politely remind myself! Any luck with that code?

1 Like

It’s not really an efficient option, but here you go:

import bpy

    
for x in [0,1,2]:
    obj = bpy.data.objects["Torus"]
    obj_copy = obj.copy()
    obj_copy.data = obj_copy.data.copy()
    bpy.data.collections["Collection"].objects.link(obj_copy)

for ob in [["Torus.001", "Cone"],["Torus.002", "Suzanne"],["Torus.003", "Cube"]]:
    for i in [0,1,2]:
        bpy.data.objects[ob[0]].location[i] = bpy.data.objects[ob[1]].location[i]
        bpy.data.objects[ob[0]].rotation_euler[i] = bpy.data.objects[ob[1]].rotation_euler[i] 
        bpy.data.objects[ob[0]].scale[i] = bpy.data.objects[ob[1]].scale[i]
    

That created duplicated mesh, extra objects instead of instance. That’s what am I trying to get rid of here :slight_smile:

Replacing original, duplicated objects in the scene with empties from my collection.

To be specific what I’m struggling with - I have a map of a city with a lot of lamp posts (and other things, but let’s talk only lamp posts here). These lamps are individual objects, each with it’s precise placement, rotation and the same scale.

Since the whole scene is hilariously HW intensive, for sake of my mental health, before I continue any work on it, I want to replace such models with instanced empties.

So I don’t have to have around thousands on lamp posts as individual models in the scene.

Also, creating some sort of a loop for creating as many empties as selected objects (lamp posts) instead of creating specifically names would also highly appreciated! :slight_smile:

Don’t mean to sound demanding, just trying to clear up misunderstanding I created.

Dupliverts and duplifaces are instanced objects.

Yes, they are. I tried it, but noticed the second I delete original objects (respective faces I transformed those original objects into before), instances will also disappear.

Yes, this option eases out on HW performance, however, I still need to keep thousands of faces/individual objects in the scene in order to have visible instance of one single lamp post in many locations.

So, little update. While I was fiddling my own code for this, I was told creating empties in opposition to simply linking object data won’t do much of a performance difference.

Here’s the code I originally created. However, I haven’t figure out how to fetch the rotation (and now I think I see it, I wasn’t selecting it from an object, but from a collection instead).

import bpy

context = bpy.context

for obj in context.selected_objects:
    bpy.ops.object.collection_instance_add(collection='lamp_posts', align='WORLD', location=obj.location, rotation=(1, 1, 1))

aaOk, so you have a perfromance issue because of the amount of objects you have in your scene.

This can be solved in several ways. I would try the following sollution first and if that does not work for you there is some information bellow that might help to find a fitting solution:

  1. put all your lamps into a single collection
  2. create a plane in second collection
  3. put geometry nodes modifier on plane
  4. pull lamp collection into geometry nodes. This gives you a collection info node
  5. turn off lamp collection with the little checkbox in the outliner
  6. plug collection info node into a realize instances node
  7. plug realize instances node into output node.

Other way to do this are:
Dupliverts/Duplifaces
A simple instance collection

Now, the trick in each of these is to turn lots of objects into a single objects while keeping the ability to transform them.

There are several ways to do that. Which way works best for you depends on your workflow and particular scene.

The easiest way is to put all your real lamp posts into a single collection, instance your objects with one of the ways mentioned above and then deactivate the lamp collection with the “Exclude Layer” checkbox in the outliner.

Another way would be to create a second scene in your blend file and keep it there.

And another way would be to put all your lamp posts into a different scene and then link the collection.

Or you could give your collection a fake user and then unlink it from your scene.

Here is a Geonodes setup that turns a ton of monkeys into geo nodes goemetry. I have had setups with 180K objects run decently like that but having that amount of monkeys in the file blows up the file and i can not upload it anymore.

It has a “simplify in Viewport” switch in the modier. This switch turns all your lamps into bounding boxes in the viewport but will keep the high poly geometry in render. This can save a lot of RAM.
In very large scenes it also makes sense to implement a switch that deletes a certain percentage of objects in the viewport but not in render.

In Blender 3.2 I think the only possible thing to output as simplified geometry is the bounding box unless you are fine with simplified geo not being rotated and scaled (This is the second geo nodes setup in the scene). At least without python scripting. With python scripting you can get the rotation and scale working by feeding each objects rotation into attributes. But the process of setting this up and handling it is a bit cumbersome and takes away some flexibility.

But with 3.3 Blender will get two nodes (get rotation and get scale) which will make it possible to use any custom Geometry.

instance_Geo2.blend (4.2 MB)

One more thing to consider when creating complex stuff like cities:

It makes sense to split it up in different blend files because otherwise the files get absurdly heavy.
The way I do it:

  • Create several houses, each in a separate file
  • Create road elements in separate file
  • Create other elements like lamps and stuff like that in separate files
  • Create a city block by linking the houses and elements into a new file
  • Create several version of city blocks
  • Create new files in which you combine these blocks into areas
  • Create a new file and combine the areas into a city
  • Create a new file with only the geometry where you want trees and vegetation and plant the vegetation
  • Link the vegetation into your city file
  • Do the same with water

Another way which is porobably better is createing it in Geonodes. There is a theread here in which somebody builds an inca city with a lot of Geonodes and describes the process. This requires quite a bit of geonodes understanding and I can not find that thread at the moment.