Martin Builds
  • Home
  • About/Contact
  • Privacy Policy
9 October 2019 by Martin
Find My Bricks

Creating Blender Objects Programmatically with Python

Creating Blender Objects Programmatically with Python
9 October 2019 by Martin
Find My Bricks

TL;DR?

Full code here (this post is a bit silly)

And now for something completely different.

This site’s chief weapon is R. R and SQL. Two, this sites two chief weapons are R, SQL, and JavaScript. THREE! OUR THREE chief weapons are R, SQL, JavaScript and an almost fanatical devotion to Monty Python.

I’ll start again shall I. I wasn’t expecting the Spanish Inquisition.

That’s gona cause some confusion. Mind if we call you Bruce?

Lego bricks can be difficult to describe. I remember as a kid building with friends, that the word I used to describe pieces being different to those they used. It is easy enough to settle on a common set of terms, or a schema for part names however I want my app to be as frictionless as possible. I decided that to avoid ambiguity any description of a piece must be accompanied by a picture.

Python

In modern projects it’s difficult to not use Python. In this project I use Python to generate 3D models of Lego pieces in Blender.  I have used Blender a lot for creating video game assets. It is a 3D modelling application written in Python and highly extensible with it. It has a large active community and importantly, is free!

By programmatically generating piece geometry, I am able to create a set of consistent professional looking renders. At the same time, as the images are at a consistent scale I can take automated measurements of the pieces to generate some relative size metadata which may be valuable in the model training step.

What… is your name? What… is your quest? What… is the air-speed velocity of an unladen swallow?

Blender includes the “bpy” python module to allow user scripts to interface with the 3D workspace. With this we can define a function to add geometry to a new mesh object to add to the workspace.

I want one function to consistently generate pieces of different sizes. I take the class, OBJECT_OT_add_object, containing these variables to allow the user to easily change these in Blender’s GUI

studs_x = bpy.props.IntProperty(default=3)
studs_y = bpy.props.IntProperty(default=2)
plates_high = bpy.props.IntProperty(default=3)
plate_verts = bpy.props.BoolProperty(default=False)
tile = bpy.props.BoolProperty(default=False)

Creating meshes in Blender is as simple as creating a list of vertices, and then specifying lists of edges and/or faces by which vertices make up the edge/face. This is simple when defining a single primitive but becomes complicated when you want to programmatically generate geometry from a number of user-controllable inputs.

Ministry of Silly Walks

An un-ambiguous method for calculating the position of a vertex in the list is required. For repeatability I choose to “walk” around the mesh a layer at a time. We can then walk around again adding faces.

It’s not particularly silly, is it? I mean, the right leg isn’t silly at all and the left leg merely does a forward aerial half turn every alternate step. This is represented in the below code snippets:

    #add verts
    for lyr_n in range(0, layers_to_do):
        #walk the perimiter
        for stu_y in range(0, self.studs_y):
            verts.append(Vector((
            (offs_x),
            (offs_y+stu_y*width_per_stud), 
            (lyr_n*plate_height))))
            
        for stu_x in range(0, self.studs_x):
            verts.append(Vector((
            (offs_x+stu_x*width_per_stud), 
            (offs_y+width_per_stud*self.studs_y), 
            (lyr_n*plate_height))))
                    
        for stu_y in reversed(range(0, self.studs_y)):
            verts.append(Vector((
            (offs_x+width_per_stud*self.studs_x), 
            (offs_y+(stu_y+1)*width_per_stud), 
            (lyr_n*plate_height))))
            
        for stu_x in reversed(range(0, self.studs_x)):
            verts.append(Vector((
            (offs_x+(stu_x+1)*width_per_stud), 
            #(offs_y+width_per_stud*self.studs_y), 
            (offs_y), 
            (lyr_n*plate_height))))

    #add faces
    #if this is the 2nd or higher layer, add faces to layer below
    for lyr_n in range(1, layers_to_do):
        for v_n in range(0, verts_per_layer):
            tl = lyr_n*verts_per_layer+v_n
            tr = tl+1
            bl = (lyr_n-1)*verts_per_layer+v_n
            br = bl+1
            
            #if this is the end of the layer, need to adjust to wrap round
            if (v_n+1) % verts_per_layer == 0:
                tr = tr - verts_per_layer
                br = br - verts_per_layer 
            faces.append([tl, tr, br, bl]) 

The full script creates consistent starting points, from there a small amount of 3D modelling can be done to create less-basic parts.

I’d like to have an argument please.

A subtlety easily miss-able using Blender’s built-in script editor is that the Vector type form bpy does not take three inputs but instead one tuple which itself contains the x,y,z inputs. If you get the error:

TypeError: mathutils.Vector(): more than a single arg given

then the constructor is looking for a good argument. It isn’t just saying “no it isn’t”. yes it is. No it isn’t. To fix, put the x,y,z arguments in a tuple by placing a set of brackets around them.

Example:

#this will fail, three arguments:
verts.append(Vector(1,2,3))
#this will work, one argument which has three elements:
verts.append(Vector((1,2,3)))

Go on, go on. Do the punchline.

No, no this is silly. No, the whole premise is silly and it’s very badly written. I’m the senior officer here and I haven’t had a funny line yet. So I’m stopping it.

blatant copyright infringement blender contains code lego python silly

Previous articleOpinion: Five Percent AccuracyNext article R & Multi-Platform Woes
  • Fake it ’till you make it
    In AI / ML, Find My Bricks, Lego, Technology
  • Fooling the Mind – Lessons Learned in VR
    In Game Dev, Gaming, VR
  • Re-visiting NHL Data
    In Data, Hockey
  • Starting Game Dev 10 Years Later
    In Game Dev, Gaming
  • Going Serverless
    In AWS, Site News
  • Cold Start
    In Find My Bricks, Opinion
This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish. Cookie settingsACCEPT
Privacy & Cookies Policy

Privacy Overview

This website uses cookies to improve your experience while you navigate through the website. Out of these cookies, the cookies that are categorized as necessary are stored on your browser as they are essential for the working of basic functionalities of the website. We also use third-party cookies that help us analyze and understand how you use this website. These cookies will be stored in your browser only with your consent. You also have the option to opt-out of these cookies. But opting out of some of these cookies may have an effect on your browsing experience.
Necessary Always Enabled

Necessary cookies are absolutely essential for the website to function properly. This category only includes cookies that ensures basic functionalities and security features of the website. These cookies do not store any personal information.

Non-necessary

Any cookies that may not be particularly necessary for the website to function and is used specifically to collect user personal data via analytics, ads, other embedded contents are termed as non-necessary cookies. It is mandatory to procure user consent prior to running these cookies on your website.