import bpy
[docs]def set_material(bobj_or_mesh, material, protect=True):
"""
Assigns a material to a Blender object or mesh.
If a `material` is not a `bpy.types.Material` but rather its name,
then it will assign the material with that name.
A new material is creates if it did not exist before!
Parameters
----------
bobj_or_mesh: bpy.types.Object or bpy.types.Mesh
The Blender object the material is assigned to.
material: str or bpy.types.Material
Name of the material or actual material object
protect: bool (default=True)
If True, the material is protected from being deleted when unused.
Is only applied if the material did not exist before!
Returns
-------
bobj_or_mesh : bpy.types.Object or bpy.types.Mesh
"""
from ddg.visualization.blender.object import get_data
mesh = get_data(bobj_or_mesh)
if isinstance(material, str):
mat_name = material
material = bpy.data.materials.get(mat_name)
if material is None:
material = bpy.data.materials.new(name=mat_name)
if protect:
material.use_fake_user = protect
if mesh.materials:
mesh.materials[0] = material
else:
mesh.materials.append(material)
return bobj_or_mesh
[docs]def protect_material(material):
"""
Protects given material from being deleted after reloading the file if not in use.
Parameters
----------
material : str or bpy.types.Material
Name of the material or actual material object. Must exist.
"""
if isinstance(material, str):
material = bpy.data.materials.get(material)
material.use_fake_user = True
[docs]def material(
name="DDG Material",
color=(1, 1, 1),
specular=1.0,
roughness=0.5,
alpha=1.0,
):
"""
Create a Principled BSDF material.
Parameters
----------
name : str (default="DDG Material")
The name of the material.
color : 3-tuple (default=(1,1,1))
The color in RGB base.
specular : float (default=1.0)
The specular value in [0,1]
roughness : float (default=0.5)
The roughness value in [0,1]
alpha : float (default=1.0)
The alpha value in [0,1]
Returns
-------
bpy.types.Material
"""
mat = bpy.data.materials.new(name)
mat.use_nodes = True
base_color = list(color) + [1] # add alpha
# Setup BSDF node
set_value(mat, "Base Color", base_color)
set_value(mat, "Specular", specular)
set_value(mat, "Roughness", roughness)
set_value(mat, "Alpha", alpha)
# Setup rendering in Viewport
mat.diffuse_color = base_color
mat.specular_intensity = specular
mat.roughness = roughness
# Setup transparency
set_transparency(mat, alpha=alpha)
return mat
[docs]def clear(materials=None, only_unused=False):
"""
Delete all given materials.
Parameters
----------
materials : Iterable of bpy.types.Material (default=None)
Materials to be deleted. If argument is not provided or None,
all materials will be deleted.
only_unused : bool (default=False)
Removes all unused material.
If an Iterable of materials is given as first parameter,
only those are effected, otherwise all materials.
"""
if materials is None:
materials = bpy.data.materials
materials = list(materials)
if only_unused:
while materials:
material = materials.pop()
if not material.users:
bpy.data.materials.remove(material)
else:
while materials:
bpy.data.materials.remove(materials.pop())
[docs]def set_transparency(mat, alpha=0.5, blend_method="HASHED"):
"""Setup a BSDF material for transparent rendering.
The oppacity then corresponds to the 'alpha' value of the material.
It can be set using `~ddg.visualization.blender.material.set_value`.
The default alpha value is 0.5, which corresponds to 50% opacity.
Parameters
----------
mat: bpy.tyes.Material with a BSDF node.
Material to make transparent.
alpha: float between 0 and 1 (default=0.5)
Opacity of the material. 0 is transparent, 1 is opaque.
blend_method: valid string for bpy.types.Material.blend_method (default="HASHED")
Method used by real-time renderers, i.e. Eevee,
to blend the transparent material with its background.
Returns
-------
bpy.types.Material
See Also
--------
ddg.visualization.blender.material.transparent_material
"""
mat.blend_method = blend_method
mat.use_backface_culling = False
mat.shadow_method = "HASHED"
mat.show_transparent_back = False
set_value(mat, "alpha", alpha)
return mat
def _capitalize(s):
return " ".join(map(str.capitalize, s.split()))
[docs]def set_value(mat, name, value):
"""Set a value for an input of a BSDF material.
Parameters
----------
mat: bpy.types.Material
name: str
Name of the input. (For example alpha)
value: Any
Value to set for the input.
Returns
-------
bpy.types.Material
"""
name_capital = _capitalize(name)
mat.node_tree.nodes["Principled BSDF"].inputs[name_capital].default_value = value
return mat