2
$\begingroup$

I'm trying to make a simple program where 15 spheres are randomly placed into a 20x20x20 volume, then after two seconds it clears all the spheres and places another 15 randomly.

It will place the first 15 spheres fine after two seconds, then after another two seconds blender closes.

Any help with this is much appreciated.

import bpy
import random
import threading

def place():

    bpy.ops.object.select_all(action='SELECT')
    bpy.ops.object.delete(use_global=False)

    for i in range(0,15):
        x = random.randint(-10,10)
        y = random.randint(-10,10)
        z = random.randint(-10,10)
        bpy.ops.mesh.primitive_uv_sphere_add(location=(x,y,z))

        bpy.ops.object.modifier_add(type='SUBSURF')
        bpy.context.object.modifiers['Subdivision'].render_levels=0
        bpy.context.object.modifiers['Subdivision'].levels=0

        timer = threading.Timer(2.0, place)
        timer.start()

    return None

place()
$\endgroup$
0

2 Answers 2

3
$\begingroup$

Threading and blender are not really designed to go together

Blender API Gotchas: threading

So far, no work has gone into making Blender’s Python integration thread safe, so until its properly supported, best not make use of this.

Here is the second example from link modified to. Add ten spheres, then randomly move them every 2 seconds with thread.

As mentioned in docs, will after a while kill blender.

Also will find that in threads (AFAIK timers are using threads too) context is lost Context is incorrect when calling from a timer . Recommend not referencing context from a thread / timer method. This includes use of operators.

In both timer examples below the spheres are found in the data by name..

import bpy


for i in range(10):
    bpy.ops.mesh.primitive_uv_sphere_add()


def func():
    print("Running...")
    import bpy
    from random import randint
    spheres = [o for o in bpy.data.objects if o.name.startswith("Sphere")]
    
    for o in spheres:
        o.location = tuple(randint(-10, 10) for a in "xyz")

def my_timer():
    from threading import Timer
    t = Timer(2, my_timer)
    t.start()
    func()

my_timer()

This continues to run after blender is closed...

Using app.timers as suggested by @Gorgious

import bpy

for i in range(10):
    bpy.ops.mesh.primitive_uv_sphere_add()


def func():
    print("Running...")
    import bpy
    from random import randint
    spheres = [o for o in bpy.data.objects if o.name.startswith("Sphere")]

    for o in spheres:
        o.location = tuple(randint(-10, 10) for a in "xyz")
        
    return 2

bpy.app.timers.register(func)

Use a modal timer operator.

Modal Timer Operator would be my recommendation for this.

Would recommend using a modal timer for this. See the example in Text Editor > Templates > Python > Operator modal timer change the timer tick/ or count ticks for 2 second intervals.

$\endgroup$
1
  • $\begingroup$ Why does this post have no votes? Another mystery. $\endgroup$
    – brockmann
    Sep 11, 2021 at 19:15
2
$\begingroup$

If I understand the code correctly, each place() method then recursively calls 15 more place() after 2 seconds, which each of these instances themselves call place() 15 more times after 2 seconds. etc. I think this will crash any program in python pretty quickly.

Blender has specialized methods for recurrent calling of methods. See the documentation : https://docs.blender.org/api/current/bpy.app.timers.html

Exemple :

import bpy


def every_2_seconds():
    print("Hello World")
    return 2.0


bpy.app.timers.register(every_2_seconds)
$\endgroup$
1
  • 1
    $\begingroup$ Think the recursive nature above was a logic error. The first 15 spheres not placed from thread call the next time it is, and crash. Even if unindented outside of for loop will In both cases ( using threading and using timer (using threading too i believe) } context will be lost. blender.stackexchange.com/questions/135970/… Would recommend a modal timer operator to do this. $\endgroup$
    – batFINGER
    Jun 5, 2020 at 17:54

You must log in to answer this question.