Nodes: remove "Use Nodes" in Shader Editor for Object Materials

"Use Nodes" was removed in the compositor to simplify the compositing
workflow. This introduced a slight inconsistency with the Shader Node
Editor.

This PR removes "Use Nodes" for object materials.

For Line Style, no changes are planned (not sure how to preserve
compatibility yet).
This simplifies the state of objects; either they have a material or
they don't.

Backward compatibility:
- If Use Nodes is turned Off, new nodes are added to the node tree to
simulate the same material:
- DNA: Only `use_nodes` is marked deprecated
- Python API:
  - `material.use_nodes` is marked deprecated and will be removed in
6.0. Reading it always returns `True` and setting it has no effect.
  - `material.diffuse_color`, `material.specular` etc.. Are not used by
EEVEE anymore but are kept because they are used by Workbench.

Forward compatibility:
Always enable 'Use Nodes' when writing blend files.

Known Issues:
Some UI tests are failing on macOS

Pull Request: https://projects.blender.org/blender/blender/pulls/141278
This commit is contained in:
Habib Gahbiche
2025-09-14 17:53:54 +02:00
parent 62d791c8d6
commit 1b4daf9d2e
44 changed files with 363 additions and 297 deletions

View File

@@ -320,11 +320,11 @@ class USDHookExample(bpy.types.USDHook):
return False
# Create the node tree
bl_material.use_nodes = True
node_tree = bl_material.node_tree
nodes = node_tree.nodes
bsdf = nodes.get("Principled BSDF")
assert bsdf
nodes = bl_material.node_tree.nodes
output = nodes.new(type="ShaderNodeOutputMaterial")
bsdf = nodes.new(type="ShaderNodeBsdfPrincipled")
bsdf.location[0] -= 1.5 * bsdf.width
bl_material.node_tree.links.new(output.inputs["Surface"], bsdf.outputs["BSDF"])
bsdf_base_color_input = bsdf.inputs['Base Color']
# Try to set the default color value.

View File

@@ -12,18 +12,16 @@ from bpy.app.translations import pgettext_tip as tip_
class CYCLES_OT_use_shading_nodes(Operator):
"""Enable nodes on a material or light"""
"""Enable nodes on a light"""
bl_idname = "cycles.use_shading_nodes"
bl_label = "Use Nodes"
@classmethod
def poll(cls, context):
return (getattr(context, "material", False) or getattr(context, "light", False))
return getattr(context, "light", False)
def execute(self, context):
if context.material:
context.material.use_nodes = True
elif context.light:
if context.light:
context.light.use_nodes = True
return {'FINISHED'}

View File

@@ -1475,12 +1475,15 @@ class CYCLES_OBJECT_PT_visibility_culling(CyclesButtonsPanel, Panel):
def panel_node_draw(layout, id_data, output_type, input_name):
from bpy_extras.node_utils import find_node_input
if output_type != 'OUTPUT_WORLD' and not id_data.use_nodes:
if output_type not in ('OUTPUT_WORLD', 'OUTPUT_MATERIAL') and not id_data.use_nodes:
layout.operator("cycles.use_shading_nodes", icon='NODETREE')
return False
ntree = id_data.node_tree
if ntree is None:
return False
node = ntree.get_output_node('CYCLES')
if node:
input = find_node_input(node, input_name)

View File

@@ -1594,7 +1594,7 @@ void BlenderSync::sync_materials(BL::Depsgraph &b_depsgraph, bool update_all)
shader->set_pass_id(b_mat.pass_index());
/* create nodes */
if (b_mat.use_nodes() && b_mat.node_tree()) {
if (b_mat.node_tree()) {
BL::ShaderNodeTree b_ntree(b_mat.node_tree());
add_nodes(scene, b_engine, b_data, b_scene, graph.get(), b_ntree);

View File

@@ -94,7 +94,7 @@ def object_material_colors(ob):
for slot in ob.material_slots:
material = slot.material
color = color_default
if material is not None and material.use_nodes:
if material is not None:
node_tree = material.node_tree
if node_tree is not None:
color = next((

View File

@@ -207,7 +207,12 @@ def SVGGetMaterial(color, context):
return materials[color]
mat = bpy.data.materials.new(name='SVGMat')
mat.diffuse_color = (*diffuse_color, 1.0)
node_tree = mat.node_tree
bsdf = node_tree.nodes.new("ShaderNodeBsdfDiffuse")
output = node_tree.nodes.new("ShaderNodeOutputMaterial")
output.location[0] += bsdf.width + 20.0
node_tree.links.new(bsdf.outputs["BSDF"], output.inputs["Surface"])
bsdf.inputs["Color"].default_value = (*diffuse_color, 0.0)
materials[color] = mat

View File

@@ -2064,7 +2064,7 @@ def blen_read_material(fbx_tmpl, fbx_obj, settings):
elem_find_first(fbx_tmpl, b'Properties70', fbx_elem_nil))
fbx_props_no_template = (fbx_props[0], fbx_elem_nil)
ma_wrap = node_shader_utils.PrincipledBSDFWrapper(ma, is_readonly=False, use_nodes=True)
ma_wrap = node_shader_utils.PrincipledBSDFWrapper(ma, is_readonly=False)
ma_wrap.base_color = elem_props_get_color_rgb(fbx_props, b'DiffuseColor', const_color_white)
# No specular color in Principled BSDF shader, assumed to be either white or take some tint from diffuse one...
# TODO: add way to handle tint option (guesstimate from spec color + intensity...)?

View File

@@ -102,11 +102,9 @@ class ShaderWrapper:
dst_node.width = min(dst_node.width, self._col_size - 20)
return loc
def __init__(self, material, is_readonly=True, use_nodes=True):
def __init__(self, material, is_readonly=True):
self.is_readonly = is_readonly
self.material = material
if not is_readonly:
self.use_nodes = use_nodes
self.update()
def update(self): # Should be re-implemented by children classes...
@@ -115,19 +113,7 @@ class ShaderWrapper:
self._textures = {}
self._grid_locations = set()
def use_nodes_get(self):
return self.material.use_nodes
@_set_check
def use_nodes_set(self, val):
self.material.use_nodes = val
self.update()
use_nodes = property(use_nodes_get, use_nodes_set)
def node_texcoords_get(self):
if not self.use_nodes:
return None
if self._node_texcoords is ...:
# Running only once, trying to find a valid texcoords node.
for n in self.material.node_tree.nodes:
@@ -173,17 +159,13 @@ class PrincipledBSDFWrapper(ShaderWrapper):
NODES_LIST = ShaderWrapper.NODES_LIST + NODES_LIST
def __init__(self, material, is_readonly=True, use_nodes=True):
super(PrincipledBSDFWrapper, self).__init__(material, is_readonly, use_nodes)
def __init__(self, material, is_readonly=True):
super(PrincipledBSDFWrapper, self).__init__(material, is_readonly)
def update(self):
super(PrincipledBSDFWrapper, self).update()
if not self.use_nodes:
return
tree = self.material.node_tree
nodes = tree.nodes
links = tree.links
@@ -237,7 +219,7 @@ class PrincipledBSDFWrapper(ShaderWrapper):
self._node_texcoords = ...
def node_normalmap_get(self):
if not self.use_nodes or self.node_principled_bsdf is None:
if self.node_principled_bsdf is None:
return None
node_principled = self.node_principled_bsdf
if self._node_normalmap is ...:
@@ -268,7 +250,7 @@ class PrincipledBSDFWrapper(ShaderWrapper):
# Base Color.
def base_color_get(self):
if not self.use_nodes or self.node_principled_bsdf is None:
if self.node_principled_bsdf is None:
return self.material.diffuse_color
return rgba_to_rgb(self.node_principled_bsdf.inputs["Base Color"].default_value)
@@ -277,13 +259,13 @@ class PrincipledBSDFWrapper(ShaderWrapper):
color = values_clamp(color, 0.0, 1.0)
color = rgb_to_rgba(color)
self.material.diffuse_color = color
if self.use_nodes and self.node_principled_bsdf is not None:
if self.node_principled_bsdf is not None:
self.node_principled_bsdf.inputs["Base Color"].default_value = color
base_color = property(base_color_get, base_color_set)
def base_color_texture_get(self):
if not self.use_nodes or self.node_principled_bsdf is None:
if self.node_principled_bsdf is None:
return None
return ShaderImageTextureWrapper(
self, self.node_principled_bsdf,
@@ -297,7 +279,7 @@ class PrincipledBSDFWrapper(ShaderWrapper):
# Specular.
def specular_get(self):
if not self.use_nodes or self.node_principled_bsdf is None:
if self.node_principled_bsdf is None:
return self.material.specular_intensity
return self.node_principled_bsdf.inputs["Specular IOR Level"].default_value
@@ -305,14 +287,14 @@ class PrincipledBSDFWrapper(ShaderWrapper):
def specular_set(self, value):
value = values_clamp(value, 0.0, 1.0)
self.material.specular_intensity = value
if self.use_nodes and self.node_principled_bsdf is not None:
if self.node_principled_bsdf is not None:
self.node_principled_bsdf.inputs["Specular IOR Level"].default_value = value
specular = property(specular_get, specular_set)
# Will only be used as gray-scale one...
def specular_texture_get(self):
if not self.use_nodes or self.node_principled_bsdf is None:
if self.node_principled_bsdf is None:
return None
return ShaderImageTextureWrapper(
self, self.node_principled_bsdf,
@@ -327,7 +309,7 @@ class PrincipledBSDFWrapper(ShaderWrapper):
# Specular Tint.
def specular_tint_get(self):
if not self.use_nodes or self.node_principled_bsdf is None:
if self.node_principled_bsdf is None:
return Color((0.0, 0.0, 0.0))
return rgba_to_rgb(self.node_principled_bsdf.inputs["Specular Tint"].default_value)
@@ -335,13 +317,13 @@ class PrincipledBSDFWrapper(ShaderWrapper):
def specular_tint_set(self, color):
color = values_clamp(color, 0.0, 1.0)
color = rgb_to_rgba(color)
if self.use_nodes and self.node_principled_bsdf is not None:
if self.node_principled_bsdf is not None:
self.node_principled_bsdf.inputs["Specular Tint"].default_value = color
specular_tint = property(specular_tint_get, specular_tint_set)
def specular_tint_texture_get(self):
if not self.use_nodes or self.node_principled_bsdf is None:
if self.node_principled_bsdf is None:
return None
return ShaderImageTextureWrapper(
self, self.node_principled_bsdf,
@@ -355,7 +337,7 @@ class PrincipledBSDFWrapper(ShaderWrapper):
# Roughness (also sort of inverse of specular hardness...).
def roughness_get(self):
if not self.use_nodes or self.node_principled_bsdf is None:
if self.node_principled_bsdf is None:
return self.material.roughness
return self.node_principled_bsdf.inputs["Roughness"].default_value
@@ -363,14 +345,14 @@ class PrincipledBSDFWrapper(ShaderWrapper):
def roughness_set(self, value):
value = values_clamp(value, 0.0, 1.0)
self.material.roughness = value
if self.use_nodes and self.node_principled_bsdf is not None:
if self.node_principled_bsdf is not None:
self.node_principled_bsdf.inputs["Roughness"].default_value = value
roughness = property(roughness_get, roughness_set)
# Will only be used as gray-scale one...
def roughness_texture_get(self):
if not self.use_nodes or self.node_principled_bsdf is None:
if self.node_principled_bsdf is None:
return None
return ShaderImageTextureWrapper(
self, self.node_principled_bsdf,
@@ -385,7 +367,7 @@ class PrincipledBSDFWrapper(ShaderWrapper):
# Metallic (a.k.a reflection, mirror).
def metallic_get(self):
if not self.use_nodes or self.node_principled_bsdf is None:
if self.node_principled_bsdf is None:
return self.material.metallic
return self.node_principled_bsdf.inputs["Metallic"].default_value
@@ -393,14 +375,14 @@ class PrincipledBSDFWrapper(ShaderWrapper):
def metallic_set(self, value):
value = values_clamp(value, 0.0, 1.0)
self.material.metallic = value
if self.use_nodes and self.node_principled_bsdf is not None:
if self.node_principled_bsdf is not None:
self.node_principled_bsdf.inputs["Metallic"].default_value = value
metallic = property(metallic_get, metallic_set)
# Will only be used as gray-scale one...
def metallic_texture_get(self):
if not self.use_nodes or self.node_principled_bsdf is None:
if self.node_principled_bsdf is None:
return None
return ShaderImageTextureWrapper(
self, self.node_principled_bsdf,
@@ -415,21 +397,21 @@ class PrincipledBSDFWrapper(ShaderWrapper):
# Transparency settings.
def ior_get(self):
if not self.use_nodes or self.node_principled_bsdf is None:
if self.node_principled_bsdf is None:
return 1.0
return self.node_principled_bsdf.inputs["IOR"].default_value
@_set_check
def ior_set(self, value):
value = values_clamp(value, 0.0, 1000.0)
if self.use_nodes and self.node_principled_bsdf is not None:
if self.node_principled_bsdf is not None:
self.node_principled_bsdf.inputs["IOR"].default_value = value
ior = property(ior_get, ior_set)
# Will only be used as gray-scale one...
def ior_texture_get(self):
if not self.use_nodes or self.node_principled_bsdf is None:
if self.node_principled_bsdf is None:
return None
return ShaderImageTextureWrapper(
self, self.node_principled_bsdf,
@@ -441,21 +423,21 @@ class PrincipledBSDFWrapper(ShaderWrapper):
ior_texture = property(ior_texture_get)
def transmission_get(self):
if not self.use_nodes or self.node_principled_bsdf is None:
if self.node_principled_bsdf is None:
return 0.0
return self.node_principled_bsdf.inputs["Transmission Weight"].default_value
@_set_check
def transmission_set(self, value):
value = values_clamp(value, 0.0, 1.0)
if self.use_nodes and self.node_principled_bsdf is not None:
if self.node_principled_bsdf is not None:
self.node_principled_bsdf.inputs["Transmission Weight"].default_value = value
transmission = property(transmission_get, transmission_set)
# Will only be used as gray-scale one...
def transmission_texture_get(self):
if not self.use_nodes or self.node_principled_bsdf is None:
if self.node_principled_bsdf is None:
return None
return ShaderImageTextureWrapper(
self, self.node_principled_bsdf,
@@ -467,21 +449,21 @@ class PrincipledBSDFWrapper(ShaderWrapper):
transmission_texture = property(transmission_texture_get)
def alpha_get(self):
if not self.use_nodes or self.node_principled_bsdf is None:
if self.node_principled_bsdf is None:
return 1.0
return self.node_principled_bsdf.inputs["Alpha"].default_value
@_set_check
def alpha_set(self, value):
value = values_clamp(value, 0.0, 1.0)
if self.use_nodes and self.node_principled_bsdf is not None:
if self.node_principled_bsdf is not None:
self.node_principled_bsdf.inputs["Alpha"].default_value = value
alpha = property(alpha_get, alpha_set)
# Will only be used as gray-scale one...
def alpha_texture_get(self):
if not self.use_nodes or self.node_principled_bsdf is None:
if self.node_principled_bsdf is None:
return None
return ShaderImageTextureWrapper(
self, self.node_principled_bsdf,
@@ -497,13 +479,13 @@ class PrincipledBSDFWrapper(ShaderWrapper):
# Emission color.
def emission_color_get(self):
if not self.use_nodes or self.node_principled_bsdf is None:
if self.node_principled_bsdf is None:
return Color((0.0, 0.0, 0.0))
return rgba_to_rgb(self.node_principled_bsdf.inputs["Emission Color"].default_value)
@_set_check
def emission_color_set(self, color):
if self.use_nodes and self.node_principled_bsdf is not None:
if self.node_principled_bsdf is not None:
color = values_clamp(color, 0.0, 1000000.0)
color = rgb_to_rgba(color)
self.node_principled_bsdf.inputs["Emission Color"].default_value = color
@@ -511,7 +493,7 @@ class PrincipledBSDFWrapper(ShaderWrapper):
emission_color = property(emission_color_get, emission_color_set)
def emission_color_texture_get(self):
if not self.use_nodes or self.node_principled_bsdf is None:
if self.node_principled_bsdf is None:
return None
return ShaderImageTextureWrapper(
self, self.node_principled_bsdf,
@@ -522,20 +504,20 @@ class PrincipledBSDFWrapper(ShaderWrapper):
emission_color_texture = property(emission_color_texture_get)
def emission_strength_get(self):
if not self.use_nodes or self.node_principled_bsdf is None:
if self.node_principled_bsdf is None:
return 1.0
return self.node_principled_bsdf.inputs["Emission Strength"].default_value
@_set_check
def emission_strength_set(self, value):
value = values_clamp(value, 0.0, 1000000.0)
if self.use_nodes and self.node_principled_bsdf is not None:
if self.node_principled_bsdf is not None:
self.node_principled_bsdf.inputs["Emission Strength"].default_value = value
emission_strength = property(emission_strength_get, emission_strength_set)
def emission_strength_texture_get(self):
if not self.use_nodes or self.node_principled_bsdf is None:
if self.node_principled_bsdf is None:
return None
return ShaderImageTextureWrapper(
self, self.node_principled_bsdf,
@@ -550,20 +532,20 @@ class PrincipledBSDFWrapper(ShaderWrapper):
# Normal map.
def normalmap_strength_get(self):
if not self.use_nodes or self.node_normalmap is None:
if self.node_normalmap is None:
return 0.0
return self.node_normalmap.inputs["Strength"].default_value
@_set_check
def normalmap_strength_set(self, value):
value = values_clamp(value, 0.0, 10.0)
if self.use_nodes and self.node_normalmap is not None:
if self.node_normalmap is not None:
self.node_normalmap.inputs["Strength"].default_value = value
normalmap_strength = property(normalmap_strength_get, normalmap_strength_set)
def normalmap_texture_get(self):
if not self.use_nodes or self.node_normalmap is None:
if self.node_normalmap is None:
return None
return ShaderImageTextureWrapper(
self, self.node_normalmap,

View File

@@ -425,14 +425,12 @@ def create_cycles_material(self, context, img_spec, name):
if material is None:
material = bpy.data.materials.new(name=name)
material.use_nodes = True
material.surface_render_method = self.render_method
material.use_backface_culling = self.use_backface_culling
material.use_transparency_overlap = self.show_transparent_back
node_tree = material.node_tree
out_node = clean_node_tree(node_tree)
out_node = node_tree.nodes.new("ShaderNodeOutputMaterial")
tex_image = create_cycles_texnode(self, node_tree, img_spec)

View File

@@ -326,21 +326,18 @@ class QuickExplode(ObjectModeOperator, Operator):
mat = object_ensure_material(obj, data_("Explode Fade"))
mat.surface_render_method = 'DITHERED'
if not mat.use_nodes:
mat.use_nodes = True
nodes = mat.node_tree.nodes
for node in nodes:
if node.type == 'OUTPUT_MATERIAL':
node_out_mat = node
break
node_surface = node_out_mat.inputs["Surface"].links[0].from_node
node_out_mat = nodes.new("ShaderNodeOutputMaterial")
node_surface = nodes.new("ShaderNodeBsdfPrincipled")
nodes.active = node_out_mat
node_x = node_surface.location[0]
node_y = node_surface.location[1] - 400
offset_x = 200
node_out_mat.location[0] = node_x + node_surface.width + offset_x
node_mix = nodes.new('ShaderNodeMixShader')
node_mix.location = (node_x - offset_x, node_y)
mat.node_tree.links.new(node_surface.outputs[0], node_mix.inputs[1])
@@ -515,9 +512,6 @@ class QuickSmoke(ObjectModeOperator, Operator):
mat = bpy.data.materials.new(data_("Smoke Domain Material"))
obj.material_slots[0].material = mat
# Make sure we use nodes
mat.use_nodes = True
# Set node variables and clear the default nodes
tree = mat.node_tree
nodes = tree.nodes
@@ -650,9 +644,6 @@ class QuickLiquid(Operator):
mat = bpy.data.materials.new(data_("Liquid Domain Material"))
obj.material_slots[0].material = mat
# Make sure we use nodes
mat.use_nodes = True
# Set node variables and clear the default nodes
tree = mat.node_tree
nodes = tree.nodes

View File

@@ -53,11 +53,8 @@ class WORLD_OT_convert_volume_to_mesh(bpy.types.Operator):
material = bpy.data.materials.new(name)
mesh.materials.append(material)
material.use_nodes = True
volume_tree = material.node_tree
for node in volume_tree.nodes:
if node.type != 'OUTPUT_MATERIAL':
volume_tree.nodes.remove(node)
volume_tree.nodes.new("ShaderNodeOutputMaterial")
volume_output = volume_tree.get_output_node('EEVEE')
links_to_add = []

View File

@@ -169,16 +169,8 @@ class EEVEE_MATERIAL_PT_surface(MaterialButtonsPanel, Panel):
mat = context.material
if mat.use_nodes:
layout.use_property_split = True
panel_node_draw(layout, mat.node_tree, 'OUTPUT_MATERIAL', "Surface")
else:
layout.prop(mat, "use_nodes", icon='NODETREE')
layout.use_property_split = True
layout.prop(mat, "diffuse_color", text="Base Color")
layout.prop(mat, "metallic")
layout.prop(mat, "specular_intensity", text="Specular")
layout.prop(mat, "roughness")
layout.use_property_split = True
panel_node_draw(layout, mat.node_tree, 'OUTPUT_MATERIAL', "Surface")
class EEVEE_MATERIAL_PT_volume(MaterialButtonsPanel, Panel):
@@ -192,7 +184,7 @@ class EEVEE_MATERIAL_PT_volume(MaterialButtonsPanel, Panel):
def poll(cls, context):
engine = context.engine
mat = context.material
return mat and mat.use_nodes and (engine in cls.COMPAT_ENGINES) and not mat.grease_pencil
return mat and (engine in cls.COMPAT_ENGINES) and not mat.grease_pencil
def draw(self, context):
layout = self.layout
@@ -214,7 +206,7 @@ class EEVEE_MATERIAL_PT_displacement(MaterialButtonsPanel, Panel):
def poll(cls, context):
engine = context.engine
mat = context.material
return mat and mat.use_nodes and (engine in cls.COMPAT_ENGINES) and not mat.grease_pencil
return mat and (engine in cls.COMPAT_ENGINES) and not mat.grease_pencil
def draw(self, context):
layout = self.layout
@@ -237,7 +229,7 @@ class EEVEE_MATERIAL_PT_thickness(MaterialButtonsPanel, Panel):
def poll(cls, context):
engine = context.engine
mat = context.material
return mat and mat.use_nodes and (engine in cls.COMPAT_ENGINES) and not mat.grease_pencil
return mat and (engine in cls.COMPAT_ENGINES) and not mat.grease_pencil
def draw(self, context):
layout = self.layout

View File

@@ -65,16 +65,17 @@ class NODE_HT_header(Header):
ob_type = ob.type
NODE_MT_editor_menus.draw_collapsible(context, layout)
if snode_id:
row = layout.row()
row.prop(snode_id, "use_nodes")
layout.separator_spacer()
types_that_support_material = {
'MESH', 'CURVE', 'SURFACE', 'FONT', 'META', 'GPENCIL', 'VOLUME', 'CURVES', 'POINTCLOUD',
}
if snode_id:
row = layout.row()
if ob_type not in types_that_support_material:
row.prop(snode_id, "use_nodes")
layout.separator_spacer()
# disable material slot buttons when pinned, cannot find correct slot within id_from (#36589)
# disable also when the selected object does not support materials
has_material_slots = not snode.pin and ob_type in types_that_support_material

View File

@@ -27,7 +27,7 @@
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 80
#define BLENDER_FILE_SUBVERSION 81
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and cancel loading the file, showing a warning to

View File

@@ -2870,7 +2870,7 @@ static void image_walk_id_all_users(
}
case ID_MA: {
Material *ma = (Material *)id;
if (ma->nodetree && ma->use_nodes && !skip_nested_nodes) {
if (ma->nodetree && !skip_nested_nodes) {
image_walk_ntree_all_users(ma->nodetree, &ma->id, customdata, callback);
}
image_walk_gpu_materials(id, &ma->gpumaterial, customdata, callback);

View File

@@ -206,6 +206,9 @@ static void material_blend_write(BlendWriter *writer, ID *id, const void *id_add
ma->texpaintslot = nullptr;
BLI_listbase_clear(&ma->gpumaterial);
/* Set deprecated #use_nodes for forward compatibility. */
ma->use_nodes = true;
/* write LibData */
BLO_write_id_struct(writer, Material, id_address, &ma->id);
BKE_id_blend_write(writer, &ma->id);
@@ -2071,7 +2074,6 @@ static void material_default_surface_init(Material **ma_p)
bNodeTree *ntree = blender::bke::node_tree_add_tree_embedded(
nullptr, &ma->id, "Shader Nodetree", ntreeType_Shader->idname);
ma->use_nodes = true;
bNode *principled = blender::bke::node_add_static_node(nullptr, *ntree, SH_NODE_BSDF_PRINCIPLED);
bNodeSocket *base_color = blender::bke::node_find_socket(*principled, SOCK_IN, "Base Color");
@@ -2099,7 +2101,6 @@ static void material_default_volume_init(Material **ma_p)
bNodeTree *ntree = blender::bke::node_tree_add_tree_embedded(
nullptr, &ma->id, "Shader Nodetree", ntreeType_Shader->idname);
ma->use_nodes = true;
bNode *principled = blender::bke::node_add_static_node(
nullptr, *ntree, SH_NODE_VOLUME_PRINCIPLED);
@@ -2125,7 +2126,6 @@ static void material_default_holdout_init(Material **ma_p)
bNodeTree *ntree = blender::bke::node_tree_add_tree_embedded(
nullptr, &ma->id, "Shader Nodetree", ntreeType_Shader->idname);
ma->use_nodes = true;
bNode *holdout = blender::bke::node_add_static_node(nullptr, *ntree, SH_NODE_HOLDOUT);
bNode *output = blender::bke::node_add_static_node(nullptr, *ntree, SH_NODE_OUTPUT_MATERIAL);

View File

@@ -16,6 +16,7 @@
#include "DNA_brush_types.h"
#include "DNA_curves_types.h"
#include "DNA_grease_pencil_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_modifier_types.h"
#include "DNA_node_types.h"
@@ -2010,6 +2011,127 @@ static void initialize_missing_closure_and_bundle_node_storage(bNodeTree &ntree)
}
}
static void do_version_material_remove_use_nodes(Main *bmain, Material *material)
{
if (material->use_nodes) {
return;
}
/* Users defined a material node tree, but deactivated it by disabling "Use Nodes". So we
* simulate the same effect by creating a new Material Output node and setting it to active. */
bNodeTree *ntree = material->nodetree;
if (ntree == nullptr) {
/* In case the material was created in Python API it might have been missing a node tree. */
ntree = blender::bke::node_tree_add_tree_embedded(
bmain, &material->id, "Material Node Tree Versioning", "ShaderNodeTree");
}
bNode *old_output = nullptr;
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (STREQ(node->idname, "ShaderNodeOutputMaterial") && (node->flag & NODE_DO_OUTPUT)) {
old_output = node;
old_output->flag &= ~NODE_DO_OUTPUT;
}
}
bNode *frame = blender::bke::node_add_static_node(nullptr, *ntree, NODE_FRAME);
STRNCPY(frame->label, RPT_("Versioning: Use Nodes was removed"));
{
/* For EEVEE, we use a principled BSDF shader because we need to recreate the metallic,
* specular and roughness properties of the material for use_nodes = false.*/
bNode &new_output_eevee = version_node_add_empty(*ntree, "ShaderNodeOutputMaterial");
bNodeSocket &output_surface_input = version_node_add_socket(
*ntree, new_output_eevee, SOCK_IN, "NodeSocketShader", "Surface");
version_node_add_socket(*ntree, new_output_eevee, SOCK_IN, "NodeSocketShader", "Volume");
version_node_add_socket(*ntree, new_output_eevee, SOCK_IN, "NodeSocketVector", "Displacement");
version_node_add_socket(*ntree, new_output_eevee, SOCK_IN, "NodeSocketFloat", "Thickness");
version_node_add_socket(*ntree, new_output_eevee, SOCK_IN, "NodeSocketShader", "Volume");
new_output_eevee.flag |= NODE_DO_OUTPUT;
new_output_eevee.custom1 = SHD_OUTPUT_EEVEE;
bNode &shader_eevee = *blender::bke::node_add_static_node(
nullptr, *ntree, SH_NODE_BSDF_PRINCIPLED);
bNodeSocket &shader_bsdf_output = *blender::bke::node_find_socket(
shader_eevee, SOCK_OUT, "BSDF");
bNodeSocket &shader_color_input = *blender::bke::node_find_socket(
shader_eevee, SOCK_IN, "Base Color");
bNodeSocket &specular_input = *blender::bke::node_find_socket(
shader_eevee, SOCK_IN, "Specular IOR Level");
bNodeSocket &metallic_input = *blender::bke::node_find_socket(
shader_eevee, SOCK_IN, "Metallic");
bNodeSocket &roughness_input = *blender::bke::node_find_socket(
shader_eevee, SOCK_IN, "Roughness");
version_node_add_link(
*ntree, shader_eevee, shader_bsdf_output, new_output_eevee, output_surface_input);
bNodeSocketValueRGBA *rgba = shader_color_input.default_value_typed<bNodeSocketValueRGBA>();
rgba->value[0] = material->r;
rgba->value[1] = material->g;
rgba->value[2] = material->b;
rgba->value[3] = material->a;
roughness_input.default_value_typed<bNodeSocketValueFloat>()->value = material->roughness;
metallic_input.default_value_typed<bNodeSocketValueFloat>()->value = material->metallic;
specular_input.default_value_typed<bNodeSocketValueFloat>()->value = material->spec;
if (old_output != nullptr) {
/* Position the newly created node after the old output. Assume the old output node is at
* the far right of the node tree. */
shader_eevee.location[0] = old_output->location[0] + 1.5f * old_output->width;
shader_eevee.location[1] = old_output->location[1];
}
new_output_eevee.location[0] = shader_eevee.location[0] + 2.0f * shader_eevee.width;
new_output_eevee.location[1] = shader_eevee.location[1];
shader_eevee.parent = frame;
new_output_eevee.parent = frame;
}
{
/* For Cycles, a simple diffuse BSDF is sufficient. */
bNode &new_output_cycles = version_node_add_empty(*ntree, "ShaderNodeOutputMaterial");
bNodeSocket &output_surface_input = version_node_add_socket(
*ntree, new_output_cycles, SOCK_IN, "NodeSocketShader", "Surface");
version_node_add_socket(*ntree, new_output_cycles, SOCK_IN, "NodeSocketShader", "Volume");
version_node_add_socket(
*ntree, new_output_cycles, SOCK_IN, "NodeSocketVector", "Displacement");
version_node_add_socket(*ntree, new_output_cycles, SOCK_IN, "NodeSocketFloat", "Thickness");
/* We don't activate the output explicitly to avoid having two active outputs. We assume
* `node_tree.get_output_node('Cycles')` will return this node. */
new_output_cycles.custom1 = SHD_OUTPUT_CYCLES;
bNode &shader_cycles = *blender::bke::node_add_static_node(
nullptr, *ntree, SH_NODE_BSDF_DIFFUSE);
bNodeSocket &shader_bsdf_output = *blender::bke::node_find_socket(
shader_cycles, SOCK_OUT, "BSDF");
bNodeSocket &shader_color_input = *blender::bke::node_find_socket(
shader_cycles, SOCK_IN, "Color");
version_node_add_link(
*ntree, shader_cycles, shader_bsdf_output, new_output_cycles, output_surface_input);
bNodeSocketValueRGBA *rgba = shader_color_input.default_value_typed<bNodeSocketValueRGBA>();
rgba->value[0] = material->r;
rgba->value[1] = material->g;
rgba->value[2] = material->b;
rgba->value[3] = material->a;
if (old_output != nullptr) {
shader_cycles.location[0] = old_output->location[0] + 1.5f * old_output->width;
shader_cycles.location[1] = old_output->location[1] + 2.0f * old_output->height;
}
new_output_cycles.location[0] = shader_cycles.location[0] + 3.0f * shader_cycles.width;
new_output_cycles.location[1] = shader_cycles.location[1];
shader_cycles.parent = frame;
new_output_cycles.parent = frame;
}
}
void do_versions_after_linking_500(FileData *fd, Main *bmain)
{
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 500, 9)) {
@@ -3047,6 +3169,12 @@ void blo_do_versions_500(FileData *fd, Library * /*lib*/, Main *bmain)
FOREACH_NODETREE_END;
}
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 500, 81)) {
LISTBASE_FOREACH (Material *, material, &bmain->materials) {
do_version_material_remove_use_nodes(bmain, material);
}
}
/**
* Always bump subversion in BKE_blender_version.h when adding versioning
* code here, and wrap it inside a MAIN_VERSION_FILE_ATLEAST check.

View File

@@ -21,52 +21,6 @@
namespace blender::eevee {
/* -------------------------------------------------------------------- */
/** \name Default Material
*
* \{ */
DefaultSurfaceNodeTree::DefaultSurfaceNodeTree()
{
bNodeTree *ntree = bke::node_tree_add_tree(nullptr, "Shader Nodetree", ntreeType_Shader->idname);
bNode *bsdf = bke::node_add_static_node(nullptr, *ntree, SH_NODE_BSDF_PRINCIPLED);
bNode *output = bke::node_add_static_node(nullptr, *ntree, SH_NODE_OUTPUT_MATERIAL);
bNodeSocket *bsdf_out = bke::node_find_socket(*bsdf, SOCK_OUT, "BSDF");
bNodeSocket *output_in = bke::node_find_socket(*output, SOCK_IN, "Surface");
bke::node_add_link(*ntree, *bsdf, *bsdf_out, *output, *output_in);
bke::node_set_active(*ntree, *output);
color_socket_ =
(bNodeSocketValueRGBA *)bke::node_find_socket(*bsdf, SOCK_IN, "Base Color")->default_value;
metallic_socket_ =
(bNodeSocketValueFloat *)bke::node_find_socket(*bsdf, SOCK_IN, "Metallic")->default_value;
roughness_socket_ =
(bNodeSocketValueFloat *)bke::node_find_socket(*bsdf, SOCK_IN, "Roughness")->default_value;
specular_socket_ = (bNodeSocketValueFloat *)bke::node_find_socket(
*bsdf, SOCK_IN, "Specular IOR Level")
->default_value;
ntree_ = ntree;
}
DefaultSurfaceNodeTree::~DefaultSurfaceNodeTree()
{
bke::node_tree_free_embedded_tree(ntree_);
MEM_SAFE_FREE(ntree_);
}
bNodeTree *DefaultSurfaceNodeTree::nodetree_get(::Material *ma)
{
/* WARNING: This function is not threadsafe. Which is not a problem for the moment. */
copy_v3_fl3(color_socket_->value, ma->r, ma->g, ma->b);
metallic_socket_->value = ma->metallic;
roughness_socket_->value = ma->roughness;
specular_socket_->value = ma->spec;
return ntree_;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Material
*
@@ -78,7 +32,6 @@ MaterialModule::MaterialModule(Instance &inst) : inst_(inst)
diffuse_mat = BKE_id_new_nomain<::Material>("EEVEE default diffuse");
bNodeTree *ntree = bke::node_tree_add_tree_embedded(
nullptr, &diffuse_mat->id, "Shader Nodetree", ntreeType_Shader->idname);
diffuse_mat->use_nodes = true;
diffuse_mat->surface_render_method = MA_SURFACE_METHOD_FORWARD;
/* Use 0.18 as it is close to middle gray. Middle gray is typically defined as 18% reflectance
@@ -101,7 +54,6 @@ MaterialModule::MaterialModule(Instance &inst) : inst_(inst)
metallic_mat = BKE_id_new_nomain<::Material>("EEVEE default metal");
bNodeTree *ntree = bke::node_tree_add_tree_embedded(
nullptr, &metallic_mat->id, "Shader Nodetree", ntreeType_Shader->idname);
metallic_mat->use_nodes = true;
metallic_mat->surface_render_method = MA_SURFACE_METHOD_FORWARD;
bNode *bsdf = bke::node_add_static_node(nullptr, *ntree, SH_NODE_BSDF_GLOSSY);
@@ -130,7 +82,6 @@ MaterialModule::MaterialModule(Instance &inst) : inst_(inst)
error_mat_ = BKE_id_new_nomain<::Material>("EEVEE default error");
bNodeTree *ntree = bke::node_tree_add_tree_embedded(
nullptr, &error_mat_->id, "Shader Nodetree", ntreeType_Shader->idname);
error_mat_->use_nodes = true;
/* Use emission and output material to be compatible with both World and Material. */
bNode *bsdf = bke::node_add_static_node(nullptr, *ntree, SH_NODE_EMISSION);
@@ -251,9 +202,8 @@ MaterialPass MaterialModule::material_pass_get(Object *ob,
eMaterialGeometry geometry_type,
eMaterialProbe probe_capture)
{
bNodeTree *ntree = (blender_mat->use_nodes && blender_mat->nodetree != nullptr) ?
blender_mat->nodetree :
default_surface_ntree_.nodetree_get(blender_mat);
bNodeTree *ntree = (blender_mat->nodetree != nullptr) ? blender_mat->nodetree :
default_surface->nodetree;
/* We can't defer compilation in viewport image render, since we can't re-sync.(See #130235) */
bool use_deferred_compilation = !inst_.is_viewport_image_render;

View File

@@ -297,33 +297,6 @@ struct ShaderKey {
/** \} */
/* -------------------------------------------------------------------- */
/** \name Default Material Node-Tree
*
* In order to support materials without nodetree we reuse and configure a standalone nodetree that
* we pass for shader generation. The GPUMaterial is still stored inside the Material even if
* it does not use the same nodetree.
*
* \{ */
class DefaultSurfaceNodeTree {
private:
bNodeTree *ntree_;
bNodeSocketValueRGBA *color_socket_;
bNodeSocketValueFloat *metallic_socket_;
bNodeSocketValueFloat *roughness_socket_;
bNodeSocketValueFloat *specular_socket_;
public:
DefaultSurfaceNodeTree();
~DefaultSurfaceNodeTree();
/** Configure a default node-tree with the given material. */
bNodeTree *nodetree_get(::Material *ma);
};
/** \} */
/* -------------------------------------------------------------------- */
/** \name Material
*
@@ -378,8 +351,6 @@ class MaterialModule {
MaterialArray material_array_;
DefaultSurfaceNodeTree default_surface_ntree_;
::Material *error_mat_;
uint64_t gpu_pass_last_update_ = 0;

View File

@@ -854,7 +854,6 @@ static wmOperatorStatus new_material_exec(bContext *C, wmOperator * /*op*/)
ma = BKE_gpencil_material_add(bmain, name);
}
ED_node_shader_default(C, &ma->id);
ma->use_nodes = true;
}
if (prop) {
@@ -2900,7 +2899,6 @@ static wmOperatorStatus paste_material_exec(bContext *C, wmOperator *op)
SWAP_MEMBER(spec);
SWAP_MEMBER(roughness);
SWAP_MEMBER(metallic);
SWAP_MEMBER(use_nodes);
SWAP_MEMBER(index);
SWAP_MEMBER(nodetree);
SWAP_MEMBER(line_col);

View File

@@ -6751,8 +6751,6 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op)
ntree = ma->nodetree;
}
ma->use_nodes = true;
const ePaintCanvasSource slot_type = ob->mode == OB_MODE_SCULPT ?
(ePaintCanvasSource)RNA_enum_get(op->ptr,
"slot_type") :

View File

@@ -785,9 +785,7 @@ void ED_node_set_active(
if (node->flag & NODE_ACTIVE_TEXTURE) {
/* If active texture changed, free GLSL materials. */
LISTBASE_FOREACH (Material *, ma, &bmain->materials) {
if (ma->nodetree && ma->use_nodes &&
blender::bke::node_tree_contains_tree(*ma->nodetree, *ntree))
{
if (ma->nodetree && blender::bke::node_tree_contains_tree(*ma->nodetree, *ntree)) {
GPU_material_free(&ma->gpumaterial);
/* Sync to active texpaint slot, otherwise we can end up painting on a different slot

View File

@@ -124,7 +124,7 @@ bool ED_object_get_active_image(Object *ob,
{
Material *ma = DEG_is_evaluated(ob) ? BKE_object_material_get_eval(ob, mat_nr) :
BKE_object_material_get(ob, mat_nr);
bNodeTree *ntree = (ma && ma->use_nodes) ? ma->nodetree : nullptr;
bNodeTree *ntree = ma ? ma->nodetree : nullptr;
bNode *node = (ntree) ? bke::node_get_active_texture(*ntree) : nullptr;
if (node && is_image_texture_node(node)) {
@@ -170,7 +170,7 @@ bool ED_object_get_active_image(Object *ob,
void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *ima)
{
Material *ma = BKE_object_material_get(ob, mat_nr);
bNode *node = (ma && ma->use_nodes) ? bke::node_get_active_texture(*ma->nodetree) : nullptr;
bNode *node = ma ? bke::node_get_active_texture(*ma->nodetree) : nullptr;
if (node && is_image_texture_node(node)) {
node->id = &ima->id;

View File

@@ -233,7 +233,6 @@ Material *BlenderStrokeRenderer::GetStrokeShader(Main *bmain,
ntree = blender::bke::node_tree_add_tree_embedded(
nullptr, &ma->id, "stroke_shader", "ShaderNodeTree");
}
ma->use_nodes = true;
ma->blend_method = MA_BM_HASHED;
bNode *input_attr_color = blender::bke::node_add_static_node(nullptr, *ntree, SH_NODE_ATTRIBUTE);

View File

@@ -445,7 +445,6 @@ Material *import_material(Main *bmain, const std::string &base_dir, const ufbx_m
Material *mat = BKE_material_add(bmain, fmat.name.data);
id_us_min(&mat->id);
mat->use_nodes = true;
bNodeTree *ntree = blender::bke::node_tree_add_tree_embedded(
nullptr, &mat->id, "Shader Nodetree", ntreeType_Shader->idname);
bNode *bsdf = add_node(ntree, SH_NODE_BSDF_PRINCIPLED, node_locx_bsdf, node_locy_top);

View File

@@ -330,6 +330,8 @@ static void set_viewport_material_props(Material *mtl, const pxr::UsdShadeShader
diffuse_color_input.GetAttr().Get(&val) && val.IsHolding<pxr::GfVec3f>())
{
pxr::GfVec3f color = val.UncheckedGet<pxr::GfVec3f>();
/* Note: The material is expected to be rendered by the Workbench render engine (Viewport
* Display), so no need to define a material node tree. */
mtl->r = color[0];
mtl->g = color[1];
mtl->b = color[2];
@@ -454,7 +456,9 @@ Material *USDMaterialReader::add_material(const pxr::UsdShadeMaterial &usd_mater
/* Create the material. */
Material *mtl = BKE_material_add(&bmain_, mtl_name.c_str());
id_us_min(&mtl->id);
mtl->nodetree = blender::bke::node_tree_add_tree_embedded(
&bmain_, &mtl->id, "USD Material Node Tree", "ShaderNodeTree");
// id_us_min(&mtl->id);
if (read_usd_preview) {
import_usd_preview(mtl, usd_material);
@@ -495,9 +499,11 @@ void USDMaterialReader::import_usd_preview_nodes(Material *mtl,
* and output shaders. */
/* Add the node tree. */
bNodeTree *ntree = blender::bke::node_tree_add_tree_embedded(
nullptr, &mtl->id, "Shader Nodetree", "ShaderNodeTree");
mtl->use_nodes = true;
bNodeTree *ntree = mtl->nodetree;
if (mtl->nodetree == nullptr) {
ntree = blender::bke::node_tree_add_tree_embedded(
nullptr, &mtl->id, "Shader Nodetree", "ShaderNodeTree");
}
/* Create the Principled BSDF shader node. */
bNode *principled = add_node(ntree, SH_NODE_BSDF_PRINCIPLED, {0.0f, 300.0f});

View File

@@ -1702,7 +1702,7 @@ pxr::UsdShadeMaterial create_usd_material(const USDExporterContext &usd_export_c
pxr::UsdShadeMaterial usd_material = pxr::UsdShadeMaterial::Define(usd_export_context.stage,
usd_path);
if (material->use_nodes && usd_export_context.export_params.generate_preview_surface) {
if (usd_export_context.export_params.generate_preview_surface) {
create_usd_preview_surface_material(
usd_export_context, material, usd_material, active_uvmap_name, reports);
}
@@ -1711,7 +1711,7 @@ pxr::UsdShadeMaterial create_usd_material(const USDExporterContext &usd_export_c
}
#ifdef WITH_MATERIALX
if (material->use_nodes && usd_export_context.export_params.generate_materialx_network) {
if (usd_export_context.export_params.generate_materialx_network) {
create_usd_materialx_material(
usd_export_context, usd_path, material, active_uvmap_name, usd_material);
}

View File

@@ -387,7 +387,6 @@ static Material *get_or_create_material(Main *bmain,
Material *mat = BKE_material_add(bmain, name.c_str());
id_us_min(&mat->id);
mat->use_nodes = true;
mat->nodetree = create_mtl_node_tree(bmain, mtl, mat, relative_paths);
BKE_ntree_update_after_single_tree_change(*bmain, *mat->nodetree);

View File

@@ -188,7 +188,7 @@ typedef struct Material {
float metallic;
/** Nodes */
char use_nodes;
char use_nodes DNA_DEPRECATED;
/** Preview render. */
char pr_type;

View File

@@ -262,12 +262,15 @@ static Material *rna_Main_materials_new(Main *bmain, const char *name)
char safe_name[MAX_ID_NAME - 2];
rna_idname_validate(name, safe_name);
ID *id = (ID *)BKE_material_add(bmain, safe_name);
id_us_min(id);
Material *material = BKE_material_add(bmain, safe_name);
id_us_min(&material->id);
material->nodetree = blender::bke::node_tree_add_tree_embedded(
bmain, &material->id, "Material Node Tree", "ShaderNodeTree");
WM_main_add_notifier(NC_ID | NA_ADDED, nullptr);
return (Material *)id;
return material;
}
static void rna_Main_materials_gpencil_data(Main * /*bmain*/, PointerRNA *id_ptr)

View File

@@ -152,7 +152,7 @@ static void rna_Material_active_paint_texture_index_update(bContext *C, PointerR
Main *bmain = CTX_data_main(C);
Material *ma = (Material *)ptr->owner_id;
if (ma->use_nodes && ma->nodetree) {
if (ma->nodetree) {
bNode *node = BKE_texpaint_slot_material_find_node(ma, ma->paint_active_slot);
if (node) {
@@ -237,18 +237,18 @@ static void rna_Material_transparent_shadow_set(PointerRNA *ptr, bool new_value)
material->blend_shadow = new_value ? MA_BS_HASHED : MA_BS_SOLID;
}
static void rna_Material_use_nodes_update(bContext *C, PointerRNA *ptr)
static bool rna_Material_use_nodes_get(PointerRNA * /*ptr*/)
{
Material *ma = (Material *)ptr->data;
Main *bmain = CTX_data_main(C);
/* #use_nodes is deprecated. All materials now use nodes. */
return true;
}
if (ma->use_nodes && ma->nodetree == nullptr) {
ED_node_shader_default(C, &ma->id);
}
DEG_id_tag_update(&ma->id, ID_RECALC_SYNC_TO_EVAL);
DEG_relations_tag_update(bmain);
rna_Material_draw_update(bmain, CTX_data_scene(C), ptr);
static void rna_Material_use_nodes_set(PointerRNA * /*ptr*/, bool /*new_value*/)
{
/* #use_nodes is deprecated. Setting the property has no effect.
* Note: Users will get a warning through the RNA deprecation warning, so no need to log a
* warning here. */
return;
}
MTex *rna_mtex_texture_slots_add(ID *self_id, bContext *C, ReportList *reports)
@@ -1108,9 +1108,9 @@ void RNA_def_material(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_nodes", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "use_nodes", 1);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_ui_text(prop, "Use Nodes", "Use shader nodes to render the material");
RNA_def_property_update(prop, 0, "rna_Material_use_nodes_update");
RNA_def_property_boolean_funcs(prop, "rna_Material_use_nodes_get", "rna_Material_use_nodes_set");
RNA_def_property_deprecated(prop, "Unused", 500, 600);
/* common */
rna_def_animdata_common(srna);

View File

@@ -62,31 +62,24 @@ MaterialX::DocumentPtr export_to_materialx(Depsgraph *depsgraph,
NodeGraph graph(depsgraph, material, export_params, doc);
if (material->use_nodes) {
bNodeTree *local_tree = bke::node_tree_add_tree(
nullptr, "Inlined Tree", material->nodetree->idname);
BLI_SCOPED_DEFER([&]() { BKE_id_free(nullptr, &local_tree->id); });
bNodeTree *local_tree = bke::node_tree_add_tree(
nullptr, "Inlined Tree", material->nodetree->idname);
BLI_SCOPED_DEFER([&]() { BKE_id_free(nullptr, &local_tree->id); });
InlineShaderNodeTreeParams params;
inline_shader_node_tree(*material->nodetree, *local_tree, params);
InlineShaderNodeTreeParams params;
inline_shader_node_tree(*material->nodetree, *local_tree, params);
local_tree->ensure_topology_cache();
bNode *output_node = ntreeShaderOutputNode(local_tree, SHD_OUTPUT_ALL);
if (output_node && output_node->typeinfo->materialx_fn) {
NodeParserData data = {graph, NodeItem::Type::Material, nullptr, graph.empty_node()};
output_node->typeinfo->materialx_fn(&data, output_node, nullptr);
output_item = data.result;
}
else {
output_item = DefaultMaterialNodeParser(
graph, nullptr, nullptr, NodeItem::Type::Material, nullptr)
.compute_error();
}
local_tree->ensure_topology_cache();
bNode *output_node = ntreeShaderOutputNode(local_tree, SHD_OUTPUT_ALL);
if (output_node && output_node->typeinfo->materialx_fn) {
NodeParserData data = {graph, NodeItem::Type::Material, nullptr, graph.empty_node()};
output_node->typeinfo->materialx_fn(&data, output_node, nullptr);
output_item = data.result;
}
else {
output_item = DefaultMaterialNodeParser(
graph, nullptr, nullptr, NodeItem::Type::Material, nullptr)
.compute();
.compute_error();
}
/* This node is expected to have a specific name to link up to USD. */

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,54 @@
==== Meshes: 1
- Mesh 'Cube.001' vtx:8 face:6 loop:24 edge:12
- 0 1 3 2 2 ... 0 7 3 1 5
- 0/1 1/3 2/3 0/2 3/7 ... 5/7 4/5 4/6 1/5 0/4
- attr 'position' FLOAT_VECTOR POINT
- (-1.000, -1.000, -1.000)
- (-1.000, -1.000, 1.000)
- (-1.000, 1.000, -1.000)
...
- (1.000, -1.000, 1.000)
- (1.000, 1.000, -1.000)
- (1.000, 1.000, 1.000)
- attr 'sharp_edge' BOOLEAN EDGE
- 1 1 1 1 1 ... 1 1 1 1 1
- attr 'material_index' INT FACE
- 0 0 0 0 0 0
- attr 'custom_normal' INT16_2D CORNER
- (0, 0)
- (0, 0)
- (0, 0)
...
- (0, 0)
- (0, 0)
- (0, 0)
- attr 'UVMap' FLOAT2 CORNER
- (0.375, 0.000)
- (0.625, 0.000)
- (0.625, 0.250)
...
- (0.875, 0.500)
- (0.875, 0.750)
- (0.625, 0.750)
- 1 materials
- 'Material.001'
==== Objects: 1
- Obj 'Cube' MESH data:'Cube.001'
- pos 0.000, 0.000, 0.000
- rot 0.000, 0.000, 0.000 (XYZ)
- scl 1.000, 1.000, 1.000
==== Materials: 1
- Mat 'Material.001'
- base color (0.000, 0.042, 0.800)
- specular ior 0.500
- specular tint (1.000, 1.000, 1.000)
- roughness 0.300
- metallic 0.700
- ior 1.500
- viewport diffuse (0.000, 0.042, 0.800, 1.000)
- viewport specular (1.000, 1.000, 1.000), intensity 0.500
- viewport metallic 0.700, roughness 0.300
- backface False probe True shadow False

View File

@@ -7,7 +7,7 @@ Ka 1.000000 1.000000 1.000000
Kd 0.000000 0.000000 1.000000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
Ni 1.450000
d 1.000000
illum 2
@@ -17,7 +17,7 @@ Ka 1.000000 1.000000 1.000000
Kd 0.000000 0.000000 0.500000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
Ni 1.450000
d 1.000000
illum 2
@@ -27,7 +27,7 @@ Ka 1.000000 1.000000 1.000000
Kd 0.000000 1.000000 0.000000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
Ni 1.450000
d 1.000000
illum 2
@@ -37,7 +37,7 @@ Ka 1.000000 1.000000 1.000000
Kd 0.000000 0.500000 0.000000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
Ni 1.450000
d 1.000000
illum 2
@@ -47,7 +47,7 @@ Ka 1.000000 1.000000 1.000000
Kd 0.800000 0.800000 0.800000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
Ni 1.450000
d 1.000000
illum 2
@@ -57,7 +57,7 @@ Ka 1.000000 1.000000 1.000000
Kd 1.000000 0.000000 0.000000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
Ni 1.450000
d 1.000000
illum 2
@@ -67,6 +67,6 @@ Ka 1.000000 1.000000 1.000000
Kd 0.500000 0.000000 0.000000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
Ni 1.450000
d 1.000000
illum 2

View File

@@ -7,7 +7,7 @@ Ka 1.000000 1.000000 1.000000
Kd 0.000000 0.000000 1.000000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
Ni 1.450000
d 1.000000
illum 2
@@ -17,7 +17,7 @@ Ka 1.000000 1.000000 1.000000
Kd 0.000000 0.000000 0.500000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
Ni 1.450000
d 1.000000
illum 2
@@ -27,7 +27,7 @@ Ka 1.000000 1.000000 1.000000
Kd 0.000000 1.000000 0.000000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
Ni 1.450000
d 1.000000
illum 2
@@ -37,7 +37,7 @@ Ka 1.000000 1.000000 1.000000
Kd 0.000000 0.500000 0.000000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
Ni 1.450000
d 1.000000
illum 2
@@ -47,7 +47,7 @@ Ka 1.000000 1.000000 1.000000
Kd 0.800000 0.800000 0.800000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
Ni 1.450000
d 1.000000
illum 2
@@ -57,7 +57,7 @@ Ka 1.000000 1.000000 1.000000
Kd 1.000000 0.000000 0.000000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
Ni 1.450000
d 1.000000
illum 2
@@ -67,6 +67,6 @@ Ka 1.000000 1.000000 1.000000
Kd 0.500000 0.000000 0.000000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.000000
Ni 1.450000
d 1.000000
illum 2

View File

@@ -590,7 +590,7 @@
- specular tint (1.000, 1.000, 1.000)
- roughness 0.500
- metallic 0.000
- ior 1.000
- ior 1.450
- viewport diffuse (0.000, 0.000, 1.000, 1.000)
- viewport specular (1.000, 1.000, 1.000), intensity 0.500
- viewport metallic 0.000, roughness 0.500
@@ -602,7 +602,7 @@
- specular tint (1.000, 1.000, 1.000)
- roughness 0.500
- metallic 0.000
- ior 1.000
- ior 1.450
- viewport diffuse (0.000, 0.000, 0.500, 1.000)
- viewport specular (1.000, 1.000, 1.000), intensity 0.500
- viewport metallic 0.000, roughness 0.500
@@ -614,7 +614,7 @@
- specular tint (1.000, 1.000, 1.000)
- roughness 0.500
- metallic 0.000
- ior 1.000
- ior 1.450
- viewport diffuse (0.000, 1.000, 0.000, 1.000)
- viewport specular (1.000, 1.000, 1.000), intensity 0.500
- viewport metallic 0.000, roughness 0.500
@@ -626,7 +626,7 @@
- specular tint (1.000, 1.000, 1.000)
- roughness 0.500
- metallic 0.000
- ior 1.000
- ior 1.450
- viewport diffuse (0.000, 0.500, 0.000, 1.000)
- viewport specular (1.000, 1.000, 1.000), intensity 0.500
- viewport metallic 0.000, roughness 0.500
@@ -638,7 +638,7 @@
- specular tint (1.000, 1.000, 1.000)
- roughness 0.500
- metallic 0.000
- ior 1.000
- ior 1.450
- viewport diffuse (0.800, 0.800, 0.800, 1.000)
- viewport specular (1.000, 1.000, 1.000), intensity 0.500
- viewport metallic 0.000, roughness 0.500
@@ -650,7 +650,7 @@
- specular tint (1.000, 1.000, 1.000)
- roughness 0.500
- metallic 0.000
- ior 1.000
- ior 1.450
- viewport diffuse (1.000, 0.000, 0.000, 1.000)
- viewport specular (1.000, 1.000, 1.000), intensity 0.500
- viewport metallic 0.000, roughness 0.500
@@ -662,7 +662,7 @@
- specular tint (1.000, 1.000, 1.000)
- roughness 0.500
- metallic 0.000
- ior 1.000
- ior 1.450
- viewport diffuse (0.500, 0.000, 0.000, 1.000)
- viewport specular (1.000, 1.000, 1.000), intensity 0.500
- viewport metallic 0.000, roughness 0.500

View File

@@ -582,7 +582,7 @@
- specular tint (1.000, 1.000, 1.000)
- roughness 0.500
- metallic 0.000
- ior 1.000
- ior 1.450
- viewport diffuse (0.000, 0.000, 1.000, 1.000)
- viewport specular (1.000, 1.000, 1.000), intensity 0.500
- viewport metallic 0.000, roughness 0.500
@@ -594,7 +594,7 @@
- specular tint (1.000, 1.000, 1.000)
- roughness 0.500
- metallic 0.000
- ior 1.000
- ior 1.450
- viewport diffuse (0.000, 0.000, 0.500, 1.000)
- viewport specular (1.000, 1.000, 1.000), intensity 0.500
- viewport metallic 0.000, roughness 0.500
@@ -606,7 +606,7 @@
- specular tint (1.000, 1.000, 1.000)
- roughness 0.500
- metallic 0.000
- ior 1.000
- ior 1.450
- viewport diffuse (0.000, 1.000, 0.000, 1.000)
- viewport specular (1.000, 1.000, 1.000), intensity 0.500
- viewport metallic 0.000, roughness 0.500
@@ -618,7 +618,7 @@
- specular tint (1.000, 1.000, 1.000)
- roughness 0.500
- metallic 0.000
- ior 1.000
- ior 1.450
- viewport diffuse (0.000, 0.500, 0.000, 1.000)
- viewport specular (1.000, 1.000, 1.000), intensity 0.500
- viewport metallic 0.000, roughness 0.500
@@ -630,7 +630,7 @@
- specular tint (1.000, 1.000, 1.000)
- roughness 0.500
- metallic 0.000
- ior 1.000
- ior 1.450
- viewport diffuse (0.800, 0.800, 0.800, 1.000)
- viewport specular (1.000, 1.000, 1.000), intensity 0.500
- viewport metallic 0.000, roughness 0.500
@@ -642,7 +642,7 @@
- specular tint (1.000, 1.000, 1.000)
- roughness 0.500
- metallic 0.000
- ior 1.000
- ior 1.450
- viewport diffuse (1.000, 0.000, 0.000, 1.000)
- viewport specular (1.000, 1.000, 1.000), intensity 0.500
- viewport metallic 0.000, roughness 0.500
@@ -654,7 +654,7 @@
- specular tint (1.000, 1.000, 1.000)
- roughness 0.500
- metallic 0.000
- ior 1.000
- ior 1.450
- viewport diffuse (0.500, 0.000, 0.000, 1.000)
- viewport specular (1.000, 1.000, 1.000), intensity 0.500
- viewport metallic 0.000, roughness 0.500

View File

@@ -77,10 +77,11 @@ class TestBlendLibLinkHelper(TestHelper):
ma = bpy.data.materials.new("LibMaterial")
ma.use_fake_user = True
ma.use_nodes = True
out_node = ma.node_tree.nodes.new("ShaderNodeOutputMaterial")
bsdf_node = ma.node_tree.nodes.new("ShaderNodeBsdfPrincipled")
ma.node_tree.links.new(bsdf_node.outputs["BSDF"], out_node.inputs["Surface"])
teximage_node = ma.node_tree.nodes.new("ShaderNodeTexImage")
teximage_node.image = im
bsdf_node = ma.node_tree.nodes["Principled BSDF"]
ma.node_tree.links.new(bsdf_node.inputs["Base Color"], teximage_node.outputs["Color"])
def gen_library_data_(self):

View File

@@ -384,7 +384,6 @@ class ShaderNodeGroupInterfaceTest(AbstractNodeGroupInterfaceTest, NodeGroupInte
def setUp(self):
super().setUp()
self.material = bpy.data.materials.new("test")
self.material.use_nodes = True
self.main_tree = self.material.node_tree
def test_invalid_socket_type(self):
@@ -476,7 +475,6 @@ class NodeTreeItemsIteratorTest(AbstractNodeGroupInterfaceTest, NodeGroupInterfa
def setUp(self):
super().setUp()
self.material = bpy.data.materials.new("test")
self.material.use_nodes = True
self.main_tree = self.material.node_tree
# Regression test for changes while iterating over tree interface items (#143551).

View File

@@ -1257,7 +1257,10 @@ class USDExportTest(AbstractUSDTest):
# Create a simple scene with 1 object and 1 material
bpy.ops.wm.open_mainfile(filepath=str(self.testdir / "empty.blend"))
material = bpy.data.materials.new(name="test_material")
material.use_nodes = True
node_tree = material.node_tree
bsdf = node_tree.nodes.new("ShaderNodeBsdfPrincipled")
output = node_tree.nodes.new("ShaderNodeOutputMaterial")
node_tree.links.new(bsdf.outputs["BSDF"], output.inputs["Surface"])
bpy.ops.mesh.primitive_plane_add()
bpy.data.objects[0].data.materials.append(material)

View File

@@ -1937,7 +1937,6 @@ class USDImportTest(AbstractUSDTest):
def test_material_import_usd_hook(self):
"""Test importing color from an mtlx shader."""
bpy.utils.register_class(ImportMtlxColorUSDHook)
bpy.ops.wm.usd_import(filepath=str(self.testdir / "usd_simple_mtlx.usda"))
bpy.utils.unregister_class(ImportMtlxColorUSDHook)
@@ -1949,7 +1948,6 @@ class USDImportTest(AbstractUSDTest):
# Check that a Principled BSDF shader with the expected Base Color input.
# was created.
mtl = bpy.data.materials["Material"]
self.assertTrue(mtl.use_nodes)
bsdf = mtl.node_tree.nodes.get("Principled BSDF")
self.assertIsNotNone(bsdf)
base_color_input = bsdf.inputs['Base Color']
@@ -2112,11 +2110,12 @@ class ImportMtlxColorUSDHook(bpy.types.USDHook):
# Add a Principled BSDF shader and set its 'Base Color' input to
# the color we read from mtlx.
bl_material.use_nodes = True
node_tree = bl_material.node_tree
assert node_tree
nodes = node_tree.nodes
bsdf = nodes.get("Principled BSDF")
assert bsdf
bsdf = nodes.new("ShaderNodeBsdfPrincipled")
output = nodes.new("ShaderNodeOutputMaterial")
node_tree.links.new(bsdf.outputs["BSDF"], output.inputs["Surface"])
color4 = [color[0], color[1], color[2], 1]
ImportMtlxColorUSDHook.imported_color = color4
bsdf.inputs['Base Color'].default_value = color4

View File

@@ -1080,15 +1080,14 @@ def main():
# Setup materials.
material = bpy.data.materials.new("Flat Black")
material.use_nodes = False
material.specular_intensity = 0.0
material.diffuse_color = (0.0, 0.0, 0.0, 1.0)
MATERIAL_FROM_COLOR["black"] = material
del material
material = bpy.data.materials.new("Flat Grey")
material.use_nodes = False
material.specular_intensity = 0.0
material.diffuse_color = (0.4, 0.4, 0.4, 1.0)
nodes = material.node_tree.nodes
bsdf = nodes.new("ShaderNodeBsdfPrincipled")
output = nodes.new("ShaderNodeOutputMaterial")
material.node_tree.links.new(bsdf.outputs["BSDF"], output.inputs["Surface"])
bsdf.inputs['Base Color'].default_value = (0.4, 0.4, 0.4, 1.0)
MATERIAL_FROM_COLOR["grey"] = material
del material