return (color_input, None)
return (None, None)
+def get_splat_layers(node_tree, node):
+ from .util import get_linked_node_and_socket
+
+ if node.type!='MIX_SHADER':
+ return
+
+ layers = []
+ while True:
+ factor_from, factor_sock = get_linked_node_and_socket(node_tree, node.inputs["Fac"])
+ if factor_from.type!='SEPRGB':
+ return
+
+ factor_from, _ = get_linked_node_and_socket(node_tree, factor_from.inputs["Image"])
+ if factor_from.type!='VERTEX_COLOR':
+ return
+
+ shader1, _ = get_linked_node_and_socket(node_tree, node.inputs[1])
+ shader2, _ = get_linked_node_and_socket(node_tree, node.inputs[2])
+ layers.append((shader2, factor_from.layer_name, factor_sock.name[0]))
+ if shader1.type=='MIX_SHADER':
+ node = shader1
+ else:
+ layers.append((shader1, None, None))
+ break
+
+ return layers
+
class MaterialProperty:
def __init__(self, keyword, tex_keyword, value):
self.keyword = keyword
else:
raise Exception("Unsupported property input node type "+from_node.type)
+class SubMaterial:
+ def __init__(self):
+ self.properties = []
+ self.weight_source = (None, None)
+
class Material:
def __init__(self, material):
self.name = material.name
self.type = None
self.properties = []
+ self.sub_materials = []
+ self.array_storage = {}
self.render_mode = material.render_mode
self.technique = material.technique
if from_node.type=='BSDF_PRINCIPLED':
self.type = "pbr"
-
- base_color = self.create_property("base_color", (0.8, 0.8, 0.8, 1.0))
- tint = self.create_property("tint", (1.0, 1.0, 1.0, 1.0))
- metalness = self.create_property("metalness", 0.0)
- roughness = self.create_property("roughness", 0.5)
- normal = self.create_property("normal_map")
- emission = self.create_property("emission", (0.0, 0.0, 0.0))
-
- base_color.set_from_input(material.node_tree, from_node.inputs["Base Color"], from_node.inputs["Alpha"])
- if base_color.tint:
- tint.value = base_color.tint
- metalness.set_from_input(material.node_tree, from_node.inputs["Metallic"])
- roughness.set_from_input(material.node_tree, from_node.inputs["Roughness"])
- normal.set_from_input(material.node_tree, from_node.inputs["Normal"])
- emission.set_from_input(material.node_tree, from_node.inputs["Emission"])
+ self.init_pbr_properties(material.node_tree, from_node)
elif from_node.type=='EMISSION' or from_node.type=='MIX_SHADER':
- color_input, alpha_input = get_unlit_inputs(material.node_tree, from_node, self.blend_type=='ADDITIVE')
- if not color_input:
- raise Exception("Unsupported configuration for unlit material {}".format(self.name))
+ splat_layers = get_splat_layers(material.node_tree, from_node)
+ if splat_layers:
+ for s in splat_layers:
+ if s[0].type!='BSDF_PRINCIPLED':
+ raise Exception("Unsupported splat layer type {} on splat material {}".format(s[0].type, self.name))
+
+ from .texture import Texture
+
+ self.type = "splat"
+ self.sub_materials = []
+ for l in splat_layers:
+ self.init_pbr_properties(material.node_tree, l[0])
+ sub = SubMaterial()
+ sub.properties = self.properties
+ sub.weight_source = l[1:]
+ self.sub_materials.append(sub)
+ self.properties = []
+
+ for p in sub.properties:
+ if p.texture:
+ texture = Texture(p.texture, p.tex_channels)
+ storage = (texture.pixelformat, texture.width, texture.height)
+ existing = self.array_storage.setdefault(p.tex_keyword, storage)
+ if storage!=existing:
+ raise Exception("Inconsistent storage for {} on splat material {}".format(p.tex_keyword, self.name))
+ else:
+ color_input, alpha_input = get_unlit_inputs(material.node_tree, from_node, self.blend_type=='ADDITIVE')
+ if not color_input:
+ raise Exception("Unsupported configuration for unlit material {}".format(self.name))
- self.type = "unlit"
+ self.type = "unlit"
- color = self.create_property("color", "texture", (1.0, 1.0, 1.0, 1.0))
+ color = self.create_property("color", "texture", (1.0, 1.0, 1.0, 1.0))
- color.set_from_input(material.node_tree, color_input, alpha_input)
- if self.blend_type=='ADDITIVE' and alpha_input:
- self.blend_type = 'ADDITIVE_ALPHA'
+ color.set_from_input(material.node_tree, color_input, alpha_input)
+ if self.blend_type=='ADDITIVE' and alpha_input:
+ self.blend_type = 'ADDITIVE_ALPHA'
else:
raise Exception("Unsupported surface node type {} on material {}".format(from_node.type, self.name))
prop = MaterialProperty(*args)
self.properties.append(prop)
return prop
+
+ def init_pbr_properties(self, node_tree, from_node):
+ base_color = self.create_property("base_color", (0.8, 0.8, 0.8, 1.0))
+ tint = self.create_property("tint", (1.0, 1.0, 1.0, 1.0))
+ metalness = self.create_property("metalness", 0.0)
+ roughness = self.create_property("roughness", 0.5)
+ normal = self.create_property("normal_map")
+ emission = self.create_property("emission", (0.0, 0.0, 0.0))
+
+ base_color.set_from_input(node_tree, from_node.inputs["Base Color"], from_node.inputs["Alpha"])
+ if base_color.tint:
+ tint.value = base_color.tint
+ metalness.set_from_input(node_tree, from_node.inputs["Metallic"])
+ roughness.set_from_input(node_tree, from_node.inputs["Roughness"])
+ normal.set_from_input(node_tree, from_node.inputs["Normal"])
+ emission.set_from_input(node_tree, from_node.inputs["Emission"])