"for obj in bpy.data.objects" changes order?

Scripting in Blender with Python, and working on the API

Moderators: jesterKing, stiv

Post Reply
sussea
Posts: 0
Joined: Fri Jun 28, 2013 4:21 pm

"for obj in bpy.data.objects" changes order?

Post by sussea » Mon Jul 01, 2013 6:14 pm

Sorry in advance if this is the wrong place for this. I'm making a script that visualizes a bunch of particles (~10,000) moving around according to inputted data. The particles are represented by planes. I noticed it takes a long time to plane_primitive_add() 10,000 particles, so I decided to make them in advance and just have the script manipulate them. If it only needs 8,000 particles, only 8,000 particles are set to be rendered and moved around. The other 2,000 are ignored. The issue is it seems like the order of the planes in bpy.data.objects seems to change between for-loops. An early for-loop goes through bpy.data.objects sequentially, setting exactly the right number of planes to be render-visible. A later for-loop should then be able to go through the list in the same order, and keep moving the particles until it finds one that's not render-visible and uses break. But doing this makes the program stop early. I can solve this by making it go through every single object in bpy.data.objects and use continue at render-invisible particles, but that can be very wasteful when I only need to move a small percentage of them. I could also make a new list and fill it with all the particles I want to render, but I can't see that being so efficient. It's also entirely possible the problem is not that the list changes order, and that I'm just doing something incredibly stupid. I've run tests though, and it does seem like that's what happening. Does anyone know any better solutions?

CoDEmanX
Posts: 0
Joined: Sun Apr 05, 2009 7:42 pm
Location: Germany

Post by CoDEmanX » Tue Jul 02, 2013 9:37 am

most objects are ordered by name, so if you have 3 meshes with the names "A_Plane", "Cube", "Monkey", they will have the indices 0, 1 and 2. If you renamed "A_Plane" to "Plane" it would change order:

[0] - Cube
[1] - Monkey
[2] - Plane

If you don't change the names and not add new objects, the order should stay the same.

Note: you should really not call *_primitive_add() thousands of times. Do it once and create (linked) duplicates using .copy(). If you only need to manipulate the object's data but not the mesh data of each instance, then do

Code: Select all

bpy.ops.mesh.plane_primitive_add()
ob = bpy.context.object

for i i range(10000):
    ob_copy = ob.copy()
    bpy.context.scene.objects.link(ob_copy)
bpy.context.scene.update()
for independent duplicates, use

ob_copy = ob.copy()
ob_copy.data = ob.data.copy()
I'm sitting, waiting, wishing, building Blender in superstition...

sussea
Posts: 0
Joined: Fri Jun 28, 2013 4:21 pm

Post by sussea » Tue Jul 02, 2013 4:22 pm

No name changes happened, but that's very helpful advice! Thanks, CoDEmanX.

sussea
Posts: 0
Joined: Fri Jun 28, 2013 4:21 pm

Post by sussea » Mon Jul 15, 2013 4:39 pm

The issue has been solved. It was an automatic sort-by-name issue. I was making the planes as 1,2,3,4... but bpy.data.objects was storing them as 1,10,11,...

Changing to .copy() made the program much smaller and a little faster, too! My old solution was to run all my primitive_add() functions one time and then save the file with them pre-generated for future runs.

CoDEmanX
Posts: 0
Joined: Sun Apr 05, 2009 7:42 pm
Location: Germany

Post by CoDEmanX » Mon Jul 15, 2013 10:57 pm

ah ok, so it's not using natural sort but plain computer-logic sort, good find! If could avoid it by using leading zeroes, e.g. 001, 002, ...
I'm sitting, waiting, wishing, building Blender in superstition...

sussea
Posts: 0
Joined: Fri Jun 28, 2013 4:21 pm

Post by sussea » Tue Jul 16, 2013 7:15 pm

I just took the max number of digits any of them would have and added a power of ten higher than that to everything. It's basically the same as trailing zeros, but with a 1 at the front and it's a little easier to write if you know the math. I don't know which is more efficient, but I'm happy enough with what I have that I don't think I'll bother changing it. Thanks again, CoDEmanX.

Post Reply