4
$\begingroup$

I want to generate a grid of Objects based on an Image Texture.

  1. I want to read the pixel data from an image
  2. I want to generate an Object for every pixel (e.g. a plane) and colorize the object based on the pixel color

I want to use one single material for all objects and only change its color value.

Is this possible with python? Or is there another way? How can I store color data in an object?

The Final Look should be something like this: enter image description here

My code so far...

import bpy

cubeSize = 0.5

image = bpy.data.images["vangogh.jpg"]
width = image.size[0]
height = image.size[1]


for x in range(width):
    for y in range(height):
        plane = bpy.ops.mesh.primitive_plane_add(size=cubeSize, location=(x*cubeSize, y*cubeSize, 0.0))

        index = x + y * width

        r = image.pixels[index]
        g = image.pixels[index+1]
        b = image.pixels[index+2]
$\endgroup$
3
  • $\begingroup$ blender.stackexchange.com/questions/131607/… $\endgroup$
    – FFeller
    Commented Apr 14, 2019 at 18:37
  • 1
    $\begingroup$ There is a non python and non-animation-nodes method, which I'd do. Are you interested in an answer, or do you need a python solution? $\endgroup$
    – Leander
    Commented Apr 14, 2019 at 19:17
  • $\begingroup$ I'm interestedin a generated solution, because I want to do this action for several images. But I'm also interested in your solution ;) $\endgroup$ Commented Apr 14, 2019 at 20:18

2 Answers 2

6
$\begingroup$

You can do this easily with animation nodes in the blender 2.80.

Create a number of instances (with deep copy) and place them using the grid distribution node. Then use the same grid points or vectors to sample the texture with Texture Node, which gives you the color of texture at that point of the grid and by changing the scale of the grid points you can scale the texture mapping as you want.

Use these colors as input color for the vertex of the previously created objects. All the object has material but by using the attribute node in materials you can assign the color to individual objects based on their vertex colors. Here are screenshots of my node tree:

enter image description here

$\endgroup$
2
  • $\begingroup$ Thanks for answering! I think I'm on the right track now. But I have troubles with mapping the colors to the grid. I set up my node tree like yours, but everything is black. When changing the scale, some other colors are mapped to the grid, but I cant't figure out how to show the whole image. What's the math behind it? $\endgroup$ Commented Apr 14, 2019 at 20:16
  • $\begingroup$ Can you share a screenshot of your node tree? Scaling of grid points works similar to scaling the image in mapping node in materials and the Texture Node use world space for texture sampling. Here is a link for a tutorial to use Texture Node: youtu.be/0ot1CCy-MOg $\endgroup$
    – 3DSinghVFX
    Commented Apr 14, 2019 at 21:30
6
$\begingroup$

It worked with animation nodes. Now I made a Script, that does the job for me. The Script duplicates an object based on the pixel array and assigns the pixel color to the vertex color.

The object to clone has to be selected.

import bpy

# get image data
img = bpy.data.images["TEXTURE_NAME"]
width = img.size[0]
height = img.size[1]

#get object size for grid (has to be square)
size = bpy.context.active_object.dimensions[0]

#generate grid and match pixeldata to vertex color
countX = 0
countY = 0
countObj = 0
for y in range(height):
    countX=0
    for x in range(width):
        bpy.ops.object.duplicate()
        copy = bpy.context.active_object

        copy.location = countX*size,countY*size,0

        mesh = copy.data
        if not mesh.vertex_colors:
            mesh.vertex_colors.new()

        color_layer = mesh.vertex_colors["Col"]

        index = countObj * 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

        countObj+=1        
        countX+=1
    countY+=1

enter image description here

The material can be made like this: enter image description here

Now I would like to move the objects directly to a new collection, but I tried it without success. Can anybody help me to:

  • create a new collection, if there isn't one called "Artwork"
  • move the objects to that collection
$\endgroup$
1

You must log in to answer this question.

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