# Access Material Color

I have created a script to generate a grid of cubes based on an image. So if I input a 32x32 image, I get 1024 cubes as expected. It also assigns a material to each cube based on the pixel.

But, having a new material for each cube is not good, especially when my image is an image of Mega Man and only has 5 different colors in it.

So, how do I find out whether an identical material exists so I can avoid duplicate materials. I have been searching for a long time and I can't find a way to do it. By the way, I want to do this in Cycles.

bl_info = {
"name": "Pixel Maker",
"version": (1, 0),
"blender": (2, 71, 0),
"location": "In object mode on the tools tab of the tool shelf.",
"description": "Takes an image and converts each pixel to a cube.  If the pixel is transparent, no cube is created.",
"warning": "Work in progress",
"category": "Object"
}

import bpy

class pixelMakerPanel(bpy.types.Panel):
"""Pixel Maker Panel"""
bl_label = "Pixel Maker"
bl_space_type = 'VIEW_3D'
bl_region_type = 'TOOLS'
bl_category = "Tools"
tex_type = 'IMAGE'

def draw(self, context):
layout = self.layout

row = layout.row()
row.prop(context.scene, "pixel_file_import")

row = layout.row()
row.prop(context.scene, "pixel_join_cubes")

row = layout.row()
row.scale_y = 2.0
row.operator("object.make_pixel")

class pixelMaker(bpy.types.Operator):
bl_idname = "object.make_pixel"
bl_label = "Run Pixel Maker"
bl_options = {'REGISTER', 'UNDO'}

def execute(self, context):
importedImage = context.scene.pixel_file_import
joinCubes = context.scene.pixel_join_cubes

def setup(img):
bpy.ops.wm.console_toggle()
print("Creating", img)
iteration = 0

image = bpy.data.images[img]
width = image.size[0]
height = image.size[1]
numberPix = len(image.pixels)

for y in range(0, height):
for x in range(0, width):
currentCube = (y * width) + x
color = []
for colorRGBA in range(0, 4):
RGBA = (currentCube * 4) + colorRGBA
color.append(image.pixels[RGBA])
drawCube(x * 2, y * 2, color)
iteration += 1

print(round((iteration / (width * height)) * 100), "% completion")

if joinCubes:
bpy.ops.object.select_all(action='TOGGLE')
bpy.ops.object.select_all(action='TOGGLE')
bpy.ops.object.join()
bpy.ops.object.editmode_toggle()
bpy.ops.mesh.remove_doubles()
bpy.ops.object.editmode_toggle()
bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY')
bpy.context.object.name = "PixelMakerObject"
else:
bpy.ops.object.select_all(action='TOGGLE')
bpy.ops.object.select_all(action='TOGGLE')

bpy.ops.wm.console_toggle()

def drawCube(x, y, col):
a = col[3]
# Checks to see whether or not the pixel is transparent. If not, then it creates a material and creates the cube.
if a != 0:
material = makeMaterial(col)
bpy.ops.mesh.primitive_cube_add(location=(x - 1, y - 1, 1))
newObject = bpy.context.active_object
newObject.data.materials.append(material)

def makeMaterial(color):
alpha = 1.0
red, green, blue, alpha = color
colorName = "material"

color = bpy.data.materials.new(colorName)
color.use_nodes = True
Diffuse_BSDF = color.node_tree.nodes['Diffuse BSDF']
Diffuse_BSDF.inputs[0].default_value = [red, green, blue, alpha]
color.diffuse_color = [red, green, blue]
return color

setup(importedImage)

return {'FINISHED'}

def register():
bpy.utils.register_module(__name__)
bpy.types.Scene.pixel_file_import = bpy.props.StringProperty(name="Image", description="Name of the image to use in the Pixel Maker add on", default="image.png")
bpy.types.Scene.pixel_join_cubes = bpy.props.BoolProperty(name="Join Cubes", description="Join the cubes?", default = True)
bpy.types.Scene.pixel_depth = bpy.props.IntProperty(name="Depth", description="Number of layers", default = 1)

def unregister():
bpy.utils.unregister_module(__name__)
del bpy.types.Scene.file_import_pixel

if __name__ == "__main__":
register()

• Can you tell how many different materials there are and how the input looks? Aug 6 '14 at 20:01
• @CoDEmanX What do you mean? Aug 6 '14 at 20:03
• You're asking whether an identical material exists, but did not post any images. So you are the only one who knows that 32x32 input image. Thus, you should actually know how many different colors there are... If they are all different, then you can't reduce the material count (unless you can utilize the object color property). Aug 6 '14 at 20:10
• @CoDEmanX My image is 32x32 pixels. It is an image of Megaman and it only has 5 colors (not counting transparent). I have over 1000 materials created when I only need 5. Does that help? Aug 6 '14 at 20:12
• You get best results here when you post what you've done so far (script, example input, because this would provide a detailed context) , I guess you could create a lookup map (key:rgb, value:material) of already existing materials in order to re-use same the material when they have identical colors. Aug 6 '14 at 20:33

class pixelMaker(bpy.types.Operator):
bl_idname = "object.make_pixel"
bl_label = "Run Pixel Maker"
bl_options = {'REGISTER', 'UNDO'}
mat_map = dict() # <---- map


...

def makeMaterial(color):
key = repr(color)
if key in self.mat_map:
return self.mat_map[key]

alpha = 1.0
red, green, blue, alpha = color
colorName = "material"

material = bpy.data.materials.new(colorName)
material.use_nodes = True
Diffuse_BSDF = material.node_tree.nodes['Diffuse BSDF']
Diffuse_BSDF.inputs[0].default_value = [red, green, blue, alpha]
material.diffuse_color = [red, green, blue]
self.mat_map[ key ]=material
return material