Deleting all Materials in script

I have written a script that produces mesh cubes to form a city. I have a pop up window that asks for amount of cubes and number of materials(grey scale shades to be randomly applied to cubes). Each time the script is ran, the previous cubes are deleted and replaced with different ones. Problem I am having is I don’t know a way to delete my materials and its causing me poblems. Its not reading the amount of materials correctly and I’m not sure why.

Heres my script:


import bpy
import random
import mathutils
from itertools import product
from math import pi, sin,cos


from bpy.props import *
 
class DialogOperator(bpy.types.Operator):
    bl_idname = "object.dialog_operator"
    bl_label = "City Creator"
 
    buildings= IntProperty(name="Number of Buildings", 
        min=0, max=100)
        
    materials = IntProperty(name="Number of Materials", 
        min=0, max= 100)
        
    x_block=IntProperty(name="Size of X city block", min=1, max = 100)
    
    y_block=IntProperty(name="Size of Y city block", min=1, max =100) 
        
    def invoke(self, context, event):  
        return context.window_manager.invoke_props_dialog(self)
     
    def execute(self, context):
        message = "%.3f, %.3f, %.3f, %.3f" % (self.buildings,self.materials, self.x_block, self.y_block)
        self.report({'INFO'}, message)
        print(message)
        functionCalled(self.buildings, self.materials, self.x_block, self.y_block)
        return {'FINISHED'}
 


 
bpy.utils.register_class(DialogOperator)
 
# Invoke the dialog when loading
bpy.ops.object.dialog_operator('INVOKE_DEFAULT')


class DialogPanel(bpy.types.Panel):
    bl_label = "Dialog"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
 
    def draw(self, context):
        self.layout.operator("object.dialog_operator")
 
bpy.utils.register_module(__name__)


def functionCalled(range_of_product, range_of_materials, x_cityblock, y_cityblock):
    
        #city
    
    x_divide=x_cityblock +1
    y_divide=y_cityblock +1
    randint_x=1
    randint_y=3
    loc_offset_x=10
    loc_offset_y=10
    resize_x=.4
    resize_y=.4


    #Variables
    #Plane
    location_x=0
    location_y=0
    location_z=0
    value_x=10
    value_y=10
    value_z=0
    
    #render
    render_x=1024
    render_y=720
    
    #Lamp
    energy_level=5
    
    #Camera and Lamp
    angle_start=0
    angle_end=91
    angle_intervals=15
    distance_away=10


    edge_thickness=150
            
    bpy.ops.object.select_by_type(type='MESH')
    bpy.ops.object.delete()
    
    bpy.ops.mesh.primitive_plane_add(location=(location_x,location_y,location_z))
    bpy.ops.transform.resize(value=(value_x,value_y,value_z))
    
    xy=product(range(range_of_product+1), repeat=2)
   
    
    for i in range(range_of_materials):
        bpy.ops.material.new()
  
    for material in bpy.data.materials.values():   
        greyscale_value=random.random()
        red=greyscale_value
        blue=greyscale_value
        green=greyscale_value
        material.diffuse_color=(red,blue,green)
    
  
    for i,j in xy:   
        if i % x_divide !=0 and j % y_divide != 0:               
            z=random.randint(randint_x,randint_y)
            b=z/2+z
            bpy.ops.mesh.primitive_cube_add(location=(i-loc_offset_x,j-loc_offset_y,b/2))             
            bpy.ops.transform.resize(value=(resize_x,resize_y,b/2))
    


    
    for cube in bpy.data.objects.values():
        cube.active_material=bpy.data.materials.values()[random.randint(0, range_of_materials)]
          
        
    lamp=bpy.data.objects['Lamp']
    bpy.data.lamps["Lamp"].type='SUN'
    bpy.data.worlds["World"].light_settings.use_environment_light=True
    bpy.data.worlds["World"].light_settings.environment_energy=energy_level
    
    
    fov=50.0        
    scene=bpy.data.scenes["Scene"]
    #set render resolution
    scene.render.resolution_x=render_x
    scene.render.resolution_y=render_y
    
   
    
    for c in range(angle_start, angle_end, angle_intervals):
        ic=c
        c=(c*pi)/180.0
        ctx=(cos(c)*10)*distance_away
        cty=0
        ctz=(sin(c)*10)*distance_away
        
        crx=(pi/2)-c
        cry=0
        crz=pi/2    


        #set camera fov in degrees
        scene.camera.data.angle=fov*(pi/180.0)
       
        #set camera roation in euler angles
        scene.camera.rotation_mode='XYZ'
        scene.camera.rotation_euler[0]=crx
        scene.camera.rotation_euler[1]=cry
        scene.camera.rotation_euler[2]=crz
       
        #set camera translation 
        scene.camera.location.x=ctx
        scene.camera.location.y=cty
        scene.camera.location.z=ctz
         
        for l in range(angle_start, angle_end, angle_intervals):
            il=l
            l=(l*pi)/180.0
            ltx=((cos(l))*10)*distance_away
            lty=0
            ltz=((sin(l))*10)*distance_away
            
            lrx=(pi/2)-l
            lry=0
            lrz=pi/2    
             
            #set lamp rotation 
            lamp.rotation_euler[0]=lrx
            lamp.rotation_euler[1]=lry
            lamp.rotation_euler[2]=lrz
           
            #set camera translation
            lamp.location.x=ltx
            lamp.location.y=lty
            lamp.location.z=ltz
 
            scene.render.use_edge_enhance=True
            scene.render.edge_threshold=edge_thickness       
            scene.render.filepath="///outputs/camera=%d light=%d.png"%(ic,il)
            the_file = "///outputs/camera=%d light=%d.png"%(ic,il)
            data_context={"blender_data": bpy.context.blend_data, "scene": scene}
            bpy.ops.render.render(data_context, write_still=True)

Hi Cass,

Wrap your code in tags

It’s a little difficult to decipher where to indent in some areas.
[noparse]


Your code here

[/noparse]

To delete materials in a brute force way

>>> m = bpy.data.materials.get('Material')
>>> m
bpy.data.materials['Material']


>>> m.users
1


>>> m.user_clear()
>>> bpy.data.materials.remove(m)
>>> m
<bpy_struct, Material invalid>


>>> m = bpy.data.materials.get('Material')
>>> m
>>> m == None
True

When a material is in use it is given a user count, a safety feature to stop mistakenly deleting materials. Materials (or most objects for that matter ) that have a user count of zero will also be lost on saving reopening a file.

You could do this after you remove all the mesh objects


for m in bpy.data.materials:
    bpy.data.materials.remove(m)

Sometimes it pays to flag your materials some way an ID prop is a handy way


# add an ID prop "city" to material m
m['city'] = 1
city_mats = [ m for m in bpy.data.materials if 'city' in m.keys()]

Some other things I noticed.

You create a mesh for each object, you could get away with only one mesh and
assigning materials to the object rather than the mesh. …tried whacking up all the sliders to max and it took forever.

After adding a cube once you can


>>>bpy.ops.object.duplicate(linked=True)
{'FINISHED'}

>>> bpy.ops.object.material_slot_add()
{'FINISHED'}


>>> C.object.material_slots[0].link = 'OBJECT'
>>> 

** actually assign the slot to the primitive

There is also a duplicate_move operator where you can put in the transform vector.

then run thru them and apply materials, or even stick to one material and use object color for simple materials. (material.use_object_color = True, and set object.color (rgba) )

another thing.


from math import radians

angle = radians(180)

to avoid all the pi conversions.


Will this delete multiple materials at once?