0

I'm generating lot's of cubes this was (code from the solution to one of my previous question: Low level fast way to create cube). I want to add different materials with colors to the cubes, so I've expanded the code that way, but this method seems to be slow. How can I make it faster? Full code that I'm running in a loop:

    name = "Cube"
    size = 2
s = size / 2
vertices = [(s, s, s),
            (s, s, -s),
            (s, -s, s),
            (s, -s, -s),
            (-s, s, s),
            (-s, s, -s),
            (-s, -s, s),
            (-s, -s, -s)]
faces = [(0, 2, 3, 1), (0, 1, 5, 4), (2, 0, 4, 6), (1, 3, 7, 5), (3, 2, 6, 7), (4, 5, 7, 6)]

mesh = bpy.data.meshes.new(name)
mesh.from_pydata(vertices, [], faces)

object = bpy.data.objects.new(name, mesh)
object.location = pos

mat = bpy.data.materials.new(name)
mat.use_nodes = True
nodes = mat.node_tree.nodes

nodes["Principled BSDF"].inputs[0].default_value = (0.8, 0.111491, 0.169871, 1)

bpy.data.objects[name].data.materials.append(mat)

bpy.context.collection.objects.link(object)

BroDude
  • 15
  • 2
  • may i ask why you don't use copy() for object & material? – Chris Nov 21 '23 at 16:37
  • and why creating many materials? Is it just to change the color or is it for other things? – lemon Nov 21 '23 at 16:40
  • @lemon I only want to set the color. The colors are going to be different for each cube. I only wrote the hard coded color for simplicity. You can imagine that they are generated randomly. – BroDude Nov 21 '23 at 16:45
  • but except the color, the materials are the same? – lemon Nov 21 '23 at 16:53
  • @lemon Yes, the materials only differ in color, everything else is the same. – BroDude Nov 21 '23 at 16:55
  • Is it possible in your context to define a material with a color based on vertex colors? To be tested, but assigning vertex colors should be faster than defining too many materials. – lemon Nov 21 '23 at 17:17
  • @lemon It's possible. I'm not familiar with vertex colors. I want the color of the cubes to be visible inside blender and in renders. – BroDude Nov 21 '23 at 19:21

1 Answers1

1

As you only want to change the color and not the material itself, you can use an object custom property to define the color.

Object custom props can be defined here (or by code):

enter image description here

And the material can look like this, using an attribute node:

enter image description here

The code can be the following (one mat for all objects and eventually one mesh for all objects):

import bpy

mat = bpy.data.materials.new("mat") mat.use_nodes = True

create an attribute node, set the attribute type to object level

and give it the name of the attribute

attribute_node = mat.node_tree.nodes.new('ShaderNodeAttribute') attribute_node.attribute_type = 'OBJECT' attribute_node.attribute_name = 'objColor'

get the principled bsdf and link its base color to the attribute node

p_bsdf = mat.node_tree.nodes['Principled BSDF'] mat.node_tree.links.new(attribute_node.outputs[0], p_bsdf.inputs[0])

create a base mesh with geometry and material

name = "Cube" size = 1 s = size / 2 vertices = [(s, s, s), (s, s, -s), (s, -s, s), (s, -s, -s), (-s, s, s), (-s, s, -s), (-s, -s, s), (-s, -s, -s)] faces = [(0, 2, 3, 1), (0, 1, 5, 4), (2, 0, 4, 6), (1, 3, 7, 5), (3, 2, 6, 7), (4, 5, 7, 6)]

mesh = bpy.data.meshes.new(name) mesh.from_pydata(vertices, [], faces) mesh.materials.append(mat)

create the objects

for i in range(1, 1000): object = bpy.data.objects.new(name, mesh) # or use a copy, depending on what you need #object = bpy.data.objects.new(name, mesh.copy())

# get and set some coordinates
x, y, z = i % 10, (i / 10) % 10, (i / 100) % 10
object.location = (x, y, z)
# set some color to the attribute (same name as for 'attribute_node.attribute_name')
object['objColor'] = (x / 10, y / 10, z / 10, 1)
bpy.context.collection.objects.link(object)

lemon
  • 60,295
  • 3
  • 66
  • 136