Materials and lighting

Content:
materials
We will not go into creating complex textures – this is a whole art, which can be devoted to a separate series of articles. On the contrary, we will create a simple material and focus on how to work with it through the API.
Materials in Blender allow you to influence the appearance of objects. For example, we can change the color, transparency, roughness, etc. In this article, we will look at how to work with these properties through the API.

We have just moved to the material editing section – “shading”. Now let’s create a simple material called “custom material” and install it on our cube.

Let’s try to change the color of the new material.

Excellent! Our cube has acquired a purple color. But now let’s figure out how to access stuff through the API.
material = bpy.data.materials['custom material']
Before moving on, let’s take a look at what the material is.

The material is made up of knots that affect the appearance. This creates a slight complication: we need to access not the material itself, but the specific node whose property we want to change. But there is a way to avoid this confusion. To do this, we need to consider “custom properties” (aka. custom properties) and “drivers”.
Custom properties
AT first part we worked with basic object properties: location, scale, etc.
cube = bpy.data.objects[‘Cube’]
cube.scale.x = 2
Lucky for us, Blender provides the ability to create custom properties that can be accessed in a similar way.

We have just created a property that will be responsible for changing the color of the object. Let’s try to access it.
cube = bpy.data.objects[‘Cube’]
list(cube[‘color’]) # Получим [0, 0, 0]
However, if we now try to change the color, nothing will happen. We haven’t told blender what it should do when we change a property.
Drivers
In Blender, drivers allow you to create relationships between two or more properties. We can now bind the color (material property) to the custom cube property we created in the previous block. First of all, we need to get the path of the property to which the binding will occur.

Now let’s move on to the property that we will bind, create a driver for it and open the driver editor.

In the editor, we will carry out a simple binding of one property to another. For a better understanding of the drivers, I advise you to read this article.

Now, when we change the custom cube property, the bound material property will automatically change along with it. Just note that the color property consists of three values: red, green, blue. At the moment, we have tied only the r-channel. g and b channels can be linked in a similar way.
cube = bpy.data.objects[‘Cube’]
cube[‘color’] = 0.5
It is important that if you try to apply the code from the example above in the Blender console, then outwardly nothing will happen. The changes will be visible on the image after rendering.
Lighting
Let’s move on to an equally interesting topic – light sources. There are four types of emitters in Blender: “Spot”, “Point”, “Area”, “Sun”. To get an idea of how each of them works, I suggest you look at this video. We will move on to their consideration from the point of view of the API. And first of all, we will get access to the light source.
light = bpy.data.lights['Light']
color
By default, any light source uses white light. With the help of the color property, we can change this. For example, let’s make the color of the lamp glow more purple.
light = bpy.data.lights['Light']
light.color = (0.33, 0.01, 1.0)

Energy
This property is responsible for the power of the emitter. The unit of measure is watt.
light = bpy.data.lights['Light']
light.energy = 100

Procedural generation of emitters
Blender provides the ability to create new objects through an API. Let’s try to create a new conical light source.
spot = bpy.data.objects.new(
'SpotLight',
bpy.data.lights.new('SpotLight', 'SPOT')
)
In the example above, we created an object of type bpy.types.Object called SpotLight and placed in it (in the data property) a light source with a similar name and type bpy.types.SpotLight
However, if we now look at the list of objects located on the stage, it turns out that our object does not exist. In Blender, you can’t just take and create an object, you still need to place it in some kind of collection in order for it to be added to the stage.

collection = bpy.context.scene.collection
collection.objects.link(spot)
Thus, we have added our lamp to the main collection of the scene and now we can interact with it.

rotation
To change the direction of the glow, just turn the emitter on the stage. To do this, we will use the standard property of objects – “rotation_euler”.
spot = bpy.data.objects['SpotLight']
spot.rotation_euler = (1, 1, 1)

Targeting an object
Let’s say we want to point the lamp created in the previous step at our cube. To do this, we can use the function discussed in article about working with cameras.
def point_ligth_at(
ligth: bpy.types.Object,
target: mathutils.Vector,
track_axis: str="Z",
up_axis: str="Y"
):
vector = ligth.location - target
ligth.rotation_euler = vector.to_track_quat(
track_axis,
up_axis
).to_euler()
light = bpy.data.objects['Light']
cube = bpy.data.objects['Cube']
point_ligth_at(light, cube.location)
The end
If you have worked with blender and want to discuss what you read or share your experience and knowledge, I am waiting for you in the comments! Let’s make the article more complete and useful for beginners.