0
$\begingroup$

I'm creating a simple for loop that creates a grid of lego objects. I was wondering if there was a way to avoid objects overlapping on top of each other.

import bpy
import random
from random import randint, uniform
import math
def clean_scene():

    # select all the object and delete them (just like pressing A + X + D in the viewport)
    bpy.ops.object.select_all(action="SELECT")
    bpy.ops.object.delete()

clean_scene()

count = 15
height = 1
spacing = 2
rndVal = 2.5
location = 1
heights = uniform(1, 4)

def make_lego():
    # Adds a copy of orig lego mesh
    #bpy.context.scene.objects['lego'].copy()
    # References it to a new obj variable
    obj = bpy.context.scene.objects['lego'].copy()
    bpy.context.scene.collection.objects.link(obj)
    # Makes obj the current active object
    #obj = bpy.context.active_object

def lego_Man():
    legoMan = bpy.context.scene.objects['mrletsgo'].copy()
    bpy.context.scene.collection.objects.link(legoMan)

for x in range(count):
    for y in range(count):
        for z in range(2):
            # loc variable for x, y, and z axis
            loc = (x*1, y*1, random.random() * 2)
            bpy.context.scene.objects['lego'].copy()
            # References it to a new obj variable
            obj = bpy.context.scene.objects['lego'].copy()
            bpy.context.scene.collection.objects.link(obj)
            # Makes obj the current active object
            #obj = bpy.context.active_object
            obj.location = (loc)
                    
            
for x in range(2):
    for y in range(2):
        loc2 = (random.random()*15, random.random()*15, 3)
        legoMan = bpy.context.scene.objects['mrletsgo'].copy()
        bpy.context.scene.collection.objects.link(legoMan)
        legoMan.location = (loc2)

            
def add_plane():
    bpy.ops.mesh.primitive_plane_add()
    bpy.ops.transform.resize(value=(10.9284, 10.9284, 10.9284))
    bpy.ops.transform.translate(value=(0, 7.0845, 0))
    bpy.ops.transform.translate(value=(8.27971, 0, 0))

add_plane()

def wall_One():   
    bpy.context.scene.objects['Plane'].copy()
    wallOne = bpy.context.scene.objects['Plane'].copy()
    bpy.context.scene.collection.objects.link(wallOne)
    wallOne.location.x += -10.7
    wallOne.location.z += 5
    wallOne.rotation_euler = [0, math.radians(90), 0]

def wall_Two():   
    bpy.context.scene.objects['Plane'].copy()
    wallTwo = bpy.context.scene.objects['Plane'].copy()
    bpy.context.scene.collection.objects.link(wallTwo)
    wallTwo.location.y += 10.7
    wallTwo.location.z += 5
    wallTwo.rotation_euler = [math.radians(90), 0, 0]

wall_One()
wall_Two()

def scene_camera():
    camera_data = bpy.data.cameras.new(name='Camera')
    camera_object = bpy.data.objects.new('Camera', camera_data)
    bpy.context.scene.collection.objects.link(camera_object)

scene_camera()

Ideally, I still want lego pieces to be near enough where they are side by side, but not on top of each other. Is there anything I should do in my current code to avoid this or is there something I should've done prior to make sure this wouldn't happen?

Thank you!

enter image description here

$\endgroup$
3
  • 2
    $\begingroup$ Hello ! Unrelated to your question, but you can remove the first bpy.context.scene.objects['lego'].copy(), this will create unlinked object copies that will bloat your file $\endgroup$
    – Gorgious
    Commented Dec 7, 2022 at 8:17
  • $\begingroup$ can u pls copy the whole script in your question, so we don't have to type that on our own? thank you. $\endgroup$
    – Chris
    Commented Dec 7, 2022 at 10:56
  • $\begingroup$ My apologies, I've added the full script! It's a little more lengthy because I've played around a bit. $\endgroup$
    – Nana
    Commented Dec 7, 2022 at 22:04

1 Answer 1

0
$\begingroup$

i found this code snippet here on the internet:

def objectsIntersect(ob1, ob2):

    mesh_1 = ob1
    m_1 = mesh_1.matrix_world.copy()
    mesh_1_verts = [m_1 @ vertex.co for vertex in mesh_1.data.vertices]
    mesh_1_polys = [polygon.vertices for polygon in mesh_1.data.polygons]
     
    mesh_2 = ob2
    m_2 = mesh_2.matrix_world.copy()
    mesh_2_verts = [m_2 @ vertex.co for vertex in mesh_2.data.vertices] 
    mesh_2_polys = [polygon.vertices for polygon in mesh_2.data.polygons]

    mesh_1_bvh_tree = BVHTree.FromPolygons(mesh_1_verts, mesh_1_polys)
    mesh_2_bvh_tree = BVHTree.FromPolygons(mesh_2_verts, mesh_2_polys)

    intersections = mesh_1_bvh_tree.overlap(mesh_2_bvh_tree)

    if len(intersections) == 0:
        return False
    
    return True

but maybe this is a bit overkill for your task.

BVHTree might be the way to go, but

  1. i am not really experienced with it
  2. the data is cached to make it quicker, but if you are adding always 1 more mesh...i think you would have to rebuild the bvhtree again which could be very slow if you have a lot of objects
  3. maybe it would be easier (since it is lego) to think about an algorithm which just randoms the values in that way, that you just randomize the multiple of width, height and length. By this the lego would always fit (i assume here that they all have the same size since your picture suggests it)
$\endgroup$

You must log in to answer this question.

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