Mat ID/Obj ID color mask render (like in Maxwell)

Is there a plugin or built-in feature that can render automatic color masks like this:

http://support.nextlimit.com/download/attachments/1475731/matidcar.jpg?version=1&modificationDate=1315617785000

Blender’s Object Id and Mat Id passes are completely different thing, than ObjID channel in Maxwell of V-Ray. There’s to much settings in compositor needed to get result i need.

I know I can set each material unique diffuse color and then disable textures in render (render->Shading->textures checkbox) and enable color pass (result in this case is just like need) but:

  1. it takes to much time to assign those unique colors
  2. have to consider materials without textures (diffuse color of which is important for the actual render) - I’ll have to change it to unique, and then change it back for final render (with texture and stuff)
  3. No way to have object masks, except of duplicating materials (for example two objects with same material are intersecting in render)

There is no other way at the moment.
In fact it is THE ONLY way. I strongly discourage to use Blender’s ID masks (both object and material) as they are not properly antialiased.
It is far better to devote some time to set everything up manually in another layer and render layer giving your materials unique colors.
I know - it hurts, but that’s how it is right now. I am fighting with it on a daily basis :slight_smile:

Thank you Bartek. I don’t like manual labor so I devoted some time today to learn basics of python scripting in blender. So here’s a simple add-on which sets random diffuse colors to all the textured materials in the scene. Well, actually it checks only the first texture slot(the one at the top), but in 95% of cases thats enough. If anyone would ever need to change diffuse colors for all materials, just remove or comment the following line

if mat.texture_slots[0]:

Usage:
Paste and execute following code in blender’s 2.6.2 text editor (Alt+P)

import bpy, random

for mat in bpy.data.materials:
	if mat.texture_slots[0]:
		for i in range(3):
			mat.diffuse_color[i] = random.random()

Or download, unpack, import and enable following plugin in Add-ons tab of blender’s users preferences

object_random_diffuse.py.zip (1.18 KB) (updated)

You’ll find it under 3D View > Object > Random Diffuse
Its not perfect, but it’ll do for now



Credits
Thomas Larsson - I used his pdf book “Code snippets…” as a reference, because blender’s docs are helpful but so confusing to me (and mostly written for 2.4 version)
Brian Hinton (Nichod) - I used his add chain script as reference to make an add-on from simple script

This is very useful option for quick selection with magic (fuzzy) selection tool if you work postpro in PS or Gimp. But material must be without any shadows options with “shadless” only.


Thanks B65ISP, but still you’ll have to go through all the materials and turn on shadeless option, and turn it off again for a real render, luckily there’s a simpler way :



P.S I’ve also added this screenshot to my reply above to save other people time digging through forum threads
P.S.S I’ve updated add-on file, because I accidentally uploaded Brian’s add_chain add-on from credits

Hi all,

I’m triying to get the same type of mask as EugeneKiever but in Cycles.

The easiest way I’ve found is to change the renderer to Blender Internal and (as EugeneKiever say) render a pass of Color without the textures. Sadly, that makes me have to erase all my Cycles materials and set BI ones… too much work.

Does anyone if it possible to render a pass with the Viewport Color, for example? (this would make things much more easy) or any other easier way of creating a similar mask?
@EugeneKiver

Under Layers
Enable the diffuse color pass

Thanks ldh1109, but that way I still have to change the Cycles materials because if I’ve applied a texture it doesn’t works as the material doesn’t have any color…

My idea is to make the render in Cycles and use Blender Internal for the masks, because it’s much quicker and I don’t have to finish the render to have them.
I’m triying to apply this method to this kind of visualization http://vimeo.com/35341467, so I depend a lot in having a good masks to select the different objects in the scene.

I have Inspired in your script:



'''
Copyright (c) 2012 Jorge Hernandez - Melendez


This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.


This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.


You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.


'''


 import bpy, random

for ob in bpy.data.objects:
    if ob.type == 'MESH' or ob.type == 'SURFACE' or ob.type == 'META':
       
        # creando materiales para quien no tenga:        
        ######## materiales ############
        mat = bpy.data.materials.new("standar")
        mat.use_shadeless = True
        mat.diffuse_color = (random.random(),random.random(),random.random())
        if ob.data.materials == '' or len(ob.material_slots.items()) == 0:
            ob.data.materials.append(mat)
            ob.data.materials[0] = mat
        ######## fin materiales ########

# para materiales existentes:
for mat in bpy.data.materials:
    mat.use_shadeless = True
    for i in range(3):
        mat.diffuse_color[i] = random.random()

# desactivamos AA        
bpy.data.scenes[0].render.use_antialiasing = False

# bg black
bpy.data.worlds[0].horizon_color = [0,0,0]

Thanks for sharing )
I thought about similar implementation, to store there original colors and restore them after rendering and set some prefs like you did with shadeless and anitialiasing to put everything back together like nothing happen. Also set 2x resolution for this map rendering but it doesn’t looks like It’ll be a huge time saver (at least for me). So great job. Im glad to get someone inspired.

I to be easier, simply would save the scene first, then apply the script and would save the scene with another name, such name_scene_ids.blend

To keep the two scenes.
name_scene_color.blend
name_scene_ids.blend

Having two separate blend files is a solution, but lately I use one blend file for all the scenes. And for that purpose all the above scrips are useless, because they mess up with blend file’s root data, not only the scenes data.
So here’s an updated version of the script
object_random_diffuse_v03.py.zip (1.35 KB)
So my workflow looks like this right now:

  1. Create base scene
  2. Make full copy of the scene when its final (pres + near scene selector and select full copy, this way all the materials in this scene will be duplicated, and script won’t mess up your base scene, which is used for all the fancy renders.
  3. Go to 3D view header -> Object -> Random Diffuse (you’ll have to install and enable the add-on first, of course)

The working code is following (you can create text file in blender end execute it if you don’t need this add-on installed)


import bpy, random
# Tweak render settings   
render = bpy.context.scene.render
render.use_textures = False
render.use_shadows = False
render.use_sss = False
render.use_envmaps = False
render.use_raytrace = False
render.use_color_management = False

wset = bpy.context.scene.world.light_settings
wset.use_environment_light = False
wset.use_ambient_occlusion = False
wset.use_indirect_light = False

#Update diffuse color on meshes, turn on Shadeless and turn off transparency
for obj in bpy.context.scene.objects:
    if obj.type == 'MESH': 
        for slot in obj.material_slots:
            if slot.material:
                mat = slot.material
                mat.use_shadeless = True
                mat.use_transparency = False
                for i in range(3):
                    mat.diffuse_color[i] = random.random()

P.S. There’s an option to set object object color active (material.use_object_color = True), but it works only for materials, and visible only in viewport. That would be great if there was a option in RenderSettings whether use material’s diffuse color for rendering or object’s color. This way we could’ve just setup new render layer, turn on this option and run a random obj color script. But I didn’t find a way to do that (if its possible). So for now - scene duplicates (or blend duplicates) are the only way to go if you want to have a mat ID map. But I would be so awesome if we could implement it just with another render layer and just have one scene.

I’m writing a script, adapting it could be helpful.
this is to render it in wireframe mode. Only need apply the color shaders in edit mode to objects…



'''
Copyright (c) 2012 Jorge Hernandez - Melendez


This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.


This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.


You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.


'''


import bpy

#current_scene = bpy.data.scenes

escenas = bpy.data.scenes
if "Wireframe" not in escenas:
    bpy.ops.scene.new(type='FULL_COPY')
    bpy.context.scene.name = "Wireframe"

    bpy.ops.object.select_all(action='DESELECT')

    def MakeMaterial_wire():
        mat = bpy.data.materials.new("Wire")
        mat.diffuse_color = (0.0, 0.0, 0.0)
        mat.type = 'WIRE'
        mat.specular_intensity = 0
        mat.use_shadeless = True
        mat.use_transparency = True
        mat.offset_z = 0.03
        return mat

    scn = bpy.context.scene
    for obj in bpy.data.scenes[scn.name].objects:
        if obj.type == 'MESH' or obj.type == 'SURFACE' or obj.type == 'META':

            def selecciona_objeto():
                scn.objects.active = obj
                obj.select = True

            con = int(len(obj.material_slots))

            # con material es 1 sin material es 0
            if int(len(obj.material_slots)) < int(1): # SIN MATERIALES
                selecciona_objeto()
                bpy.ops.object.material_slot_add() #<-- append de material
                obj.material_slots[con - 1].material = MakeMaterial_wire()

            else: # CON MATERIALES
                selecciona_objeto()
                bpy.ops.object.material_slot_add() #<-- append de material
                existentes = obj.material_slots # todos los materiales del objeto


                array_mats = [] # array vacio
                for a in range(len(existentes)):
                    array_mats.append("")

                for i in range(len(array_mats)):
                    if i == 0:
                        array_mats[0] = MakeMaterial_wire()
                    else:
                        array_mats[i] = obj.material_slots[i-1].material


                for i in range(len(existentes)):
                    obj.material_slots[i].material = array_mats[i]


            bpy.ops.object.select_all(action='DESELECT')
            obj.select = False 


Well, I modified/adapted this:
Recall that makes full copy from the current scene in which we are.

Object ID:



'''
Copyright (c) 2012 Jorge Hernandez - Melendez


This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.


This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.


You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.


'''


##################################################
# Object ID
##################################################
import bpy, random

escenas = bpy.data.scenes
if "Object_ID" not in escenas:
    bpy.ops.scene.new(type='FULL_COPY')
    bpy.context.scene.name = "Object_ID"
    

    bpy.ops.object.select_all(action='DESELECT')


    def Object_ID():
        mat = bpy.data.materials.new("Object_ID")
        mat.specular_intensity = 0
        mat.use_shadeless = True
        mat.diffuse_color = (random.random(),random.random(),random.random())
        return mat
    
    scn = bpy.context.scene
    for obj in bpy.data.scenes[scn.name].objects:
        if obj.type == 'MESH' or obj.type == 'SURFACE' or obj.type == 'META':
       
            def selecciona_objeto():
                scn.objects.active = obj
                obj.select = True
       
            if obj.data.materials == '' or len(obj.material_slots.items()) == 0:
                selecciona_objeto()
                #obj.data.materials.append(mat)
                bpy.ops.object.material_slot_add()
                obj.data.materials[0] = Object_ID()
                
            else:
                selecciona_objeto()
                bpy.ops.object.material_slot_add() #<-- append de material
                existentes = obj.material_slots # todos los materiales del objeto


                array_mats = [] # array vacio
                for a in range(len(existentes)):
                    array_mats.append("")

                for i in range(len(array_mats)):
                    if i == 0:
                        array_mats[0] = Object_ID()
                    else:
                        array_mats[i] = obj.material_slots[i-1].material


                for i in range(len(existentes)):
                    obj.material_slots[i].material = array_mats[i]
                                    
            bpy.ops.object.select_all(action='DESELECT')
            obj.select = False     
               
            # desactivamos AA        
            #bpy.data.scenes[0].render.use_antialiasing = False
            bpy.context.scene.render.use_antialiasing = False
            
            # bg black
            #bpy.data.worlds[0].horizon_color = [0,0,0]
            bpy.context.scene.world.horizon_color = [0,0,0] 

Material ID: https://github.com/zebus3d/material_id

Excuse my intromission in this solved thread, but i tried the script 2 days ago with last blender release (2.64) and i riceive an error about the color management system, so it doesn’t generate nothing. Am I making some mistake or this script is not working anymore? Could you give some suggestion, because this object/material id color pass is extremely useful for post. thank you very much

Hi Zio, yeah, you’re right. There actually was one useless line for setting color management, and due to latest updates in blender color management it screwed up the script for 2.64 (and above) users
So I just removed it, here’s the link to updated script (v 0.4) https://dl.dropbox.com/u/2903027/scripts/object_random_diffuse.py.zip

thank you very much Eugene, the script is executed correctly with this new version, now I just need to spend some time understanding how it works correctly. thanks a lot for the correction and sharing, it will be very useful!

glad that my work is useful to others.
here’s a quick guide.




Steps with duplicating, rendering, saving result and deleting could be automated too, but I’m not using this script that often to deal with it yet

My new method script (node-based): https://github.com/zebus3d/automatic_material_id_nodal
This method only use 3 steps.

For precaution, first make a backup of your scene.

great, thanks for sharing, I’ll give it a try in few days, when I’ll need some id maps