2
$\begingroup$

I am trying to create Conway's game of life in blender, but every time I am getting the error

Info: Deleted 13 object(s)

Info: Saved "untitled2.blend"

Info: Deleted 12 object(s)

Info: Saved "untitled2.blend"

add_operation: Operation already exists - 4)Parameters Component : LSLineStyle( affects_directly_visible: false) has PARAMETERS_ENTRY() at 0000015542C29588
add_operation: Operation already exists - 4)Parameters Component : LSLineStyle( affects_directly_visible: true) has PARAMETERS_EVAL() at 0000015542C29448
add_operation: Operation already exists - 4)Parameters Component : LSLineStyle( affects_directly_visible: true) has PARAMETERS_EXIT() at 0000015542C29308
add_operation: Operation already exists - 13)Audio Component : SCScene( affects_directly_visible: true) has AUDIO_ENTRY() at 0000015542C28E08
add_operation: Operation already exists - 13)Audio Component : SCScene( affects_directly_visible: false) has SOUND_EVAL() at 000001551D479A88
add_operation: Operation already exists - 13)Audio Component : SCScene( affects_directly_visible: true) has AUDIO_VOLUME() at 000001551D479D08
add_operation: Operation already exists - 9)Sequencer Component : SCScene( affects_directly_visible: true) has SEQUENCES_EVAL() at 000001551D479948
add_operation: Operation already exists - 10)LayerCollections Component : SCScene( affects_directly_visible: true) has VIEW_LAYER_EVAL() at 000001551D478B88
add_operation: Operation already exists - 4)Parameters Component : SCScene( affects_directly_visible: true) has PARAMETERS_ENTRY() at 000001551D479088
add_operation: Operation already exists - 4)Parameters Component : SCScene( affects_directly_visible: true) has PARAMETERS_EVAL() at 000001551D4791C8
add_operation: Operation already exists - 4)Parameters Component : SCScene( affects_directly_visible: true) has PARAMETERS_EXIT() at 000001551D4787C8
add_operation: Operation already exists - 4)Parameters Component : SCScene( affects_directly_visible: true) has SCENE_EVAL() at 000001551D478188
Error   : EXCEPTION_ACCESS_VIOLATION
Address : 0x00007FF60DEB1C59
Module  : blender.exe
Thread  : 00002cf4
Writing: C:\Users\****\AppData\Local\Temp\untitled2.crash.txt

Here is the code

# adding system packages
import sys

sys.path.append("C:\\Users\\***\\AppData\\Roaming\\Python\\Python39\\site-packages")

import bpy
import numpy as np
import random
from scipy import signal
import time
import threading

# remove exixting objects
bpy.ops.object.select_all(action='DESELECT')
bpy.ops.object.delete()

# set of active objects
active_objects = set()

#set the grid size
grid_size = 20
grid = np.zeros((grid_size,)*3, dtype=int)

# randomly place some 'n' 1s
#n = 10
#for i in range(n):
#    grid[random.randint(0, grid_size-1),
#        random.randint(0, grid_size-1),
#        random.randint(0, grid_size-1)] = 1

grid[10, 10, 10] = 1
grid[10, 10, 8] = 1
grid[10, 10, 12] = 1
grid[10, 8, 10] = 1
grid[10,12, 10] = 1
grid[12, 10, 10] = 1
grid[8,10,10] = 1
        
# now place the cubes
for cor in zip(*np.where(grid == 1)):
    bpy.ops.mesh.primitive_cube_add(size=1,
                                    calc_uvs=False,
                                    location=cor)
    obj = bpy.context.object
    obj.name = str(cor)
    active_objects.add(cor)
    
    
# now in next step we will calculate Conway's conditions
kernel = np.ones((3,3,3), dtype=int)
kernel[1,1,1] = 0

def loop_generation(generation = 10, delay = 1):
    
    global active_objects
    
    for _ in range(generation):
        
        time.sleep(delay)
        
        convolution = signal.convolve(grid, kernel, mode='same')
        
        # extract the living cells
        new_living = set()
        for cord in zip(*np.where((convolution == 2) | (convolution == 3))):
            new_living.add(cord)
            
        to_kill = active_objects.difference(new_living)
        add_new = new_living.difference(active_objects)
        print(convolution)
        
        for del_cor in to_kill:
                bpy.data.objects.remove(bpy.data.objects[str(del_cor)])
        
        for new_cor in add_new:
            bpy.ops.mesh.primitive_cube_add(size=1,
                                        calc_uvs=False,
                                        location=new_cor)
                                        
            obj = bpy.context.view_layer.objects.active
            print(obj)
            #obj = bpy.context.object
            obj.name = str(new_cor)
          
        active_objects = new_living
            
            



if __name__ == '__main__':
    threading.Thread(target=loop_generation).start()
$\endgroup$
3
  • 2
    $\begingroup$ Blender and threading do not always play well together. See first few posts blender.stackexchange.com/search?q=%5Bpython%5D+threading+ For what you are trying to achieve here, look at the Text Editor > Templates > Python > Modal Timer Operator Objects can be added removed based on its elapsed time. $\endgroup$
    – batFINGER
    Commented Sep 11, 2021 at 13:49
  • 1
    $\begingroup$ blender.stackexchange.com/questions/181400/… $\endgroup$
    – batFINGER
    Commented Sep 11, 2021 at 13:58
  • $\begingroup$ Thanks for the suggestion, it is working nicely, but there is lack of smoothness during function executionn $\endgroup$
    – Epsi95
    Commented Sep 11, 2021 at 14:47

1 Answer 1

3
$\begingroup$

Finally solved the problem using timer, thanks @batFINGER

import sys
import bpy
import bmesh
import numpy as np
import random
from scipy import signal
import time
import mathutils

# globals
color_turn = True
mask = None
new_living = None
to_kill = None
add_new = None

# remove exixting objects
bpy.ops.object.select_all(action='DESELECT')
bpy.ops.object.delete()

# set of active objects
active_objects = set()

#set the grid size
grid_size = 20
grid = np.zeros((grid_size,)*3, dtype=int)

# randomly place some 'n' 1s
#n = 6
#for i in range(n):
#    grid[random.randint(0, (grid_size-1)//2),
#        random.randint(0, (grid_size-1)//2),
#        random.randint(0, (grid_size-1)//2)] = 1

for i in range(6,9):
    grid[10, 6, i] = 1
    grid[10, 10, i] = 1
for i in range(7,10):
    grid[10, i, 5] = 1
    grid[10, i, 9] = 1

# red material
mat = bpy.data.materials.new("PKHG")
mat.diffuse_color = (1.0,0.0,0.0,1.0)
        
# now place the cubes
for cor in zip(*np.where(grid == 1)):
    bpy.ops.mesh.primitive_cube_add(size=1,
                                    calc_uvs=False,
                                    location=cor)
    obj = bpy.context.object
    obj.name = str(cor)
    active_objects.add(cor)
    
    
# now in next step we will calculate Conway's conditions
kernel = np.ones((3,3,3), dtype=int)
kernel[1,1,1] = 0

def create_cube(name, loc):
    bpyscene = bpy.context.scene

    # Create an empty mesh and the object.
    mesh = bpy.data.meshes.new(name)
    basic_cube = bpy.data.objects.new(name, mesh)

    # Add the object into the scene.
    bpyscene.collection.objects.link(basic_cube)

    # Construct the bmesh cube and assign it to the blender mesh.
    bm = bmesh.new()
    bmesh.ops.create_cube(bm, size=1.0, matrix=mathutils.Matrix.Translation(loc))
    bm.to_mesh(mesh)
    bm.free()

def loop_generation(delay = 1):
    
    global active_objects, color_turn, mask, to_kill, add_new, new_living
    
    # calculating the mask
    if mask is None:
        convolution = signal.convolve(grid, kernel, mode='same')
        
        # Any live cell with 5-6 live neighbors survives
        mask_1 = ((convolution == 5) | (convolution == 6)) & (grid == 1)
        # Any dead cell with 4 live neighbors becomes a live cell
        mask_2 = (convolution == 4) & (grid == 0)
        mask = mask_1 | mask_2
    
        # extract the living cells
        new_living = set()
        for cord in zip(*np.where(mask)):
            new_living.add(cord)
            
        to_kill = active_objects.difference(new_living)
        add_new = new_living.difference(active_objects)
    
    if color_turn:
        for del_cor in to_kill:
            bpy.data.objects[str(del_cor)].active_material = mat
        color_turn = not color_turn
            
        return delay
    
    # update the grid
    grid[:] = 0
    grid[mask] = 1
    
    
    for del_cor in to_kill:
        bpy.data.objects.remove(bpy.data.objects[str(del_cor)])
    
    for new_cor in add_new:
        create_cube(str(new_cor), new_cor)
      
    active_objects = new_living
    color_turn = not color_turn
    mask = None
    return delay
        


if __name__ == '__main__':
    bpy.app.timers.register(loop_generation)
```
$\endgroup$
1
  • $\begingroup$ Yah, works like magic with timer instead of Thread. Incredible, thanks for sharing your solution! $\endgroup$ Commented Feb 26, 2022 at 21:49

You must log in to answer this question.

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