"""
This script copies an object based on an image input and sets the vertex color to the corresponding pixels.
Make sure that the image is already scaled down and is loaded into the blend file.
One side of the image should not be larger than 20px. It takes some time ;)
But if you have time feel free to go larger.
1. Change the image name to your image input
2. Make sure the object you want to clone is selected
3. Run the Script!
4. In the shader network you can access the color with the attribute node.
"""
import bpy
# get image data, image has to be loaded into the blend-file
img = bpy.data.images["image.jpg"]
width = img.size[0]
height = img.size[1]
#get object-size for grid (has to be square)
obj = bpy.context.active_object
size = obj.dimensions[0]
#create new collection if necessary
if bpy.data.collections.get("LegoGrid") is None:
grid_coll = bpy.data.collections.new("LegoGrid")
bpy.context.scene.collection.children.link(grid_coll)
else:
grid_coll = bpy.data.collections["LegoGrid"]
#generate grid and match pixeldata to vertex color
for y in range(height):
for x in range(width):
copy = obj.copy()
copy.data = obj.data.copy()
copy.location = x*size,y*size,0
mesh = copy.data
if not mesh.vertex_colors:
mesh.vertex_colors.new()
color_layer = mesh.vertex_colors["Col"]
index = (y * width + x) * 4
r = img.pixels[index + 0]
g = img.pixels[index + 1]
b = img.pixels[index + 2]
a = img.pixels[index + 3]
i = 0
for poly in mesh.polygons:
for idx in poly.loop_indices:
rgb = [r,g,b,a]
color_layer.data[i].color = rgb
i += 1
grid_coll.objects.link(copy)
Thanks for releasing the script! I was really interested in how you were reading color data from an image. I’m definitely gonna play around with it when I get some spare time!!
A little suggestion though (which would have a huge impact actually), try to make instances instead of duplicates.
I guess vertex color is linked to the mesh so you would still have to create duplicates for each new color. But still, that would drastically reduce the object data load.
Summary
If instead of duplicating, you make instances for same color objects, you end up storing only as much duplicates as the number of color you use (and it’s quite low on low def pictures, especially if you use black and white pictures : only two colors/meshes to use).
Let’s say we have a 20px² image with 8 colors, and a lego mesh of 100 triangles.
If you duplicate every lego piece, that’s 400 lego pieces of 100 triangles each, so you actually create and store in memory 40 000 triangles.
If you generate only duplicates for each new color, and make instances for the same colored objects, you still generate 400 objects, but they share the geometry of 8 “true” objects, which brings the polycount to 3 200. It’s 12,5 less.
Hi five! I saw your work on FB shared by Blender Artist. I developed a similar script, but not nearly as elegant. Mine cross-checked each RGB with a Lego part color list and used an X-Y-Z distance formula to find the closest Lego color, in case I actually wanted to order parts.
I like the artistic effect of minimal pixels so that it could actually be built. Brute force coding on a large image is impractical unless you have thousands of dollars and an entire wall.
My post was flagged as off-topic here. Sorry all.
I moved it here - if somone want to see faster version of that script, translated to Animation Nodes.
I thought we can change only transformations (loc,rot,scale) for instances. Can we really change somehow instance properties/attributes like vertex color? When I change ‘Col’ for one instance - all objects using the same mesh changes as well… Give me some hint, please
EDIT: Ups, I missed you wrote about instances for same color. I see optimalization now .