WIP: MaterialX addon #104594
@ -32,13 +32,13 @@ class Id:
|
||||
class NodeItem:
|
||||
"""This class is a wrapper used for doing operations on MaterialX nodes, floats, and tuples"""
|
||||
|
||||
def __init__(self, id: Id, ng: [mx.Document, mx.NodeGraph], data: [tuple, float, mx.Node]):
|
||||
def __init__(self, id: Id, ng: [mx.Document, mx.NodeGraph], data: [tuple, float, mx.Node], prefix=''):
|
||||
self.id = id
|
||||
self.nodegraph = ng
|
||||
self.data = data
|
||||
self.nodedef = None
|
||||
if isinstance(data, mx.Node):
|
||||
MxNode_cls, _ = get_mx_node_cls(data)
|
||||
MxNode_cls, _ = get_mx_node_cls(data, prefix)
|
||||
self.nodedef = MxNode_cls.get_nodedef(self.type)
|
||||
|
||||
def node_item(self, value):
|
||||
@ -370,10 +370,14 @@ class NodeParser:
|
||||
|
||||
return self.get_input_default(in_key)
|
||||
|
||||
def create_node(self, node_name, nd_type, inputs=None):
|
||||
def create_node(self, node_name, nd_type, *, prefix='', inputs=None):
|
||||
nodegraph = utils.get_nodegraph_by_path(self.doc, self.nodegraph_path, True)
|
||||
node = nodegraph.addNode(node_name, f"{node_name}_{self.id()}", nd_type)
|
||||
node_item = NodeItem(self.id, nodegraph, node)
|
||||
node_item = NodeItem(self.id, nodegraph, node, prefix)
|
||||
|
||||
mx_type = node_item.nodedef.getType()
|
||||
if mx_type != nd_type:
|
||||
node.setType(mx_type)
|
||||
|
||||
if inputs:
|
||||
node_item.set_inputs(inputs)
|
||||
|
@ -23,7 +23,7 @@ class ShaderNodeOutputMaterial(NodeParser):
|
||||
|
||||
return None
|
||||
|
||||
result = self.create_node('surfacematerial', 'material', {
|
||||
result = self.create_node('surfacematerial', 'material', inputs={
|
||||
'surfaceshader': surface,
|
||||
})
|
||||
|
||||
|
@ -31,6 +31,10 @@ def enabled(val):
|
||||
return True
|
||||
|
||||
|
||||
def get_node_type(node):
|
||||
return node.getType() if isinstance(node, mx.Node) else node.nodedef.getType()
|
||||
|
||||
|
||||
class ShaderNodeBsdfPrincipled(NodeParser):
|
||||
nodegraph_path = ""
|
||||
|
||||
@ -89,7 +93,7 @@ class ShaderNodeBsdfPrincipled(NodeParser):
|
||||
tangent = self.get_input_link('Tangent')
|
||||
|
||||
# CREATING STANDARD SURFACE
|
||||
result = self.create_node('standard_surface', 'surfaceshader', {
|
||||
result = self.create_node('standard_surface', 'surfaceshader', prefix='BXDF', inputs={
|
||||
'base': 1.0,
|
||||
'base_color': base_color,
|
||||
'diffuse_roughness': roughness,
|
||||
@ -162,7 +166,7 @@ class ShaderNodeBsdfDiffuse(NodeParser):
|
||||
|
||||
# Also tried burley_diffuse_bsdf and oren_nayar_diffuse_bsdf here, but Blender crashes with them
|
||||
# CREATING STANDARD SURFACE
|
||||
result = self.create_node('standard_surface', 'surfaceshader', {
|
||||
result = self.create_node('standard_surface', 'surfaceshader', prefix='BXDF', inputs={
|
||||
'base_color': color,
|
||||
'diffuse_roughness': 1.0 - roughness,
|
||||
'normal': normal,
|
||||
@ -179,7 +183,7 @@ class ShaderNodeBsdfGlass(NodeParser):
|
||||
normal = self.get_input_link('Normal')
|
||||
|
||||
# CREATING STANDARD SURFACE
|
||||
result = self.create_node('standard_surface', 'surfaceshader', {
|
||||
result = self.create_node('standard_surface', 'surfaceshader', prefix='BXDF', inputs={
|
||||
'base': 0.0,
|
||||
'normal': normal,
|
||||
'specular': 1.0,
|
||||
@ -200,7 +204,7 @@ class ShaderNodeEmission(NodeParser):
|
||||
nodegraph_path = ""
|
||||
|
||||
def export(self):
|
||||
result = self.create_node('standard_surface', 'surfaceshader')
|
||||
result = self.create_node('standard_surface', 'surfaceshader', prefix='BXDF')
|
||||
|
||||
color = self.get_input_value('Color')
|
||||
strength = self.get_input_value('Strength')
|
||||
@ -222,23 +226,46 @@ class ShaderNodeMixShader(NodeParser):
|
||||
shader1 = self.get_input_link(1)
|
||||
shader2 = self.get_input_link(2)
|
||||
|
||||
mix = None
|
||||
|
||||
if shader1 is None and shader2 is None:
|
||||
return None
|
||||
|
||||
if shader1 is None:
|
||||
return shader2
|
||||
|
||||
if shader2 is None:
|
||||
return shader1
|
||||
mix = self.create_node('mix', get_node_type(shader1).lower(), prefix='PBR', inputs={
|
||||
'fg': shader1,
|
||||
'mix': factor
|
||||
})
|
||||
|
||||
result = self.create_node('STD_mix', 'surfaceshader', {
|
||||
'fg': shader1,
|
||||
'bg': shader2,
|
||||
'mix': factor
|
||||
if shader1 is None:
|
||||
mix = self.create_node('mix', get_node_type(shader2).lower(), prefix='PBR', inputs={
|
||||
'bg': shader2,
|
||||
'mix': factor
|
||||
})
|
||||
|
||||
if shader1 is not None and shader2 is not None:
|
||||
shader1_type = get_node_type(shader1)
|
||||
shader2_type = get_node_type(shader2)
|
||||
if shader1_type != shader2_type:
|
||||
log.warn(f'Types of input shaders must be the same.'
|
||||
f' First shader type: {shader1_type}, second shader type: {shader2_type}')
|
||||
|
||||
return None
|
||||
|
||||
mix = self.create_node('mix', shader1_type.lower(), prefix='PBR', inputs={
|
||||
'fg': shader1,
|
||||
'bg': shader2,
|
||||
'mix': factor
|
||||
})
|
||||
|
||||
if not mix:
|
||||
return None
|
||||
|
||||
result = self.create_node('surface', 'surfaceshader', prefix='PBR', inputs={
|
||||
mix.nodedef.getType().lower(): mix,
|
||||
'opacity': 1.0
|
||||
})
|
||||
|
||||
log.warn(f"Known issue: node doesn't work correctly with {result.nodedef.getName()}", self.material, self.node)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@ -249,20 +276,41 @@ class ShaderNodeAddShader(NodeParser):
|
||||
shader1 = self.get_input_link(0)
|
||||
shader2 = self.get_input_link(1)
|
||||
|
||||
add = None
|
||||
|
||||
if shader1 is None and shader2 is None:
|
||||
return None
|
||||
|
||||
if shader1 is None:
|
||||
return shader2
|
||||
|
||||
if shader2 is None:
|
||||
return shader1
|
||||
add = self.create_node('add', get_node_type(shader1).lower(), prefix='PBR', inputs={
|
||||
'in1': shader1
|
||||
})
|
||||
|
||||
result = self.create_node('STD_add', 'surfaceshader', {
|
||||
'in1': shader1,
|
||||
'in2': shader2
|
||||
if shader1 is None:
|
||||
add = self.create_node('add', get_node_type(shader2).lower(), prefix='PBR', inputs={
|
||||
'in2': shader2
|
||||
})
|
||||
|
||||
if shader1 is not None and shader2 is not None:
|
||||
shader1_type = get_node_type(shader1)
|
||||
shader2_type = get_node_type(shader2)
|
||||
if shader1_type != shader2_type:
|
||||
log.warn(f'Types of input shaders must be the same.'
|
||||
f' First shader type: {shader1_type}, second shader type: {shader2_type}')
|
||||
|
||||
return None
|
||||
|
||||
add = self.create_node('add', shader1_type.lower(), prefix='PBR', inputs={
|
||||
'in1': shader1,
|
||||
'in2': shader2
|
||||
})
|
||||
|
||||
if not add:
|
||||
return None
|
||||
|
||||
result = self.create_node('surface', 'surfaceshader', prefix='PBR', inputs={
|
||||
add.nodedef.getType().lower(): add,
|
||||
'opacity': 1.0
|
||||
})
|
||||
|
||||
log.warn(f"Known issue: node doesn't work correctly with {result.nodedef.getName()}", self.material, self.node)
|
||||
|
||||
return result
|
||||
|
@ -22,9 +22,9 @@ class ShaderNodeTexImage(NodeParser):
|
||||
return image_error_result
|
||||
|
||||
# TODO use Vector input for UV
|
||||
uv = self.create_node('texcoord', 'vector2', {})
|
||||
uv = self.create_node('texcoord', 'vector2')
|
||||
|
||||
result = self.create_node('image', self.out_type, {
|
||||
result = self.create_node('image', self.out_type, inputs={
|
||||
'file': img_path,
|
||||
'texcoord': uv,
|
||||
})
|
||||
|
@ -23,7 +23,7 @@ class ShaderNodeNormalMap(NodeParser):
|
||||
log.warn("Ignoring unsupported UV Map", space, self.node, self.material,
|
||||
"No UV Map will be used")
|
||||
|
||||
result = self.create_node('normalmap', 'vector3', {
|
||||
result = self.create_node('normalmap', 'vector3', inputs={
|
||||
'in': color ,
|
||||
'scale': strength,
|
||||
'space': space.lower(),
|
||||
|
@ -47,17 +47,19 @@ def unregister():
|
||||
unregister_sockets()
|
||||
|
||||
|
||||
def get_mx_node_cls(mx_node):
|
||||
def get_mx_node_cls(mx_node, prefix=''):
|
||||
node_name = mx_node.getCategory()
|
||||
|
||||
suffix = f'_{node_name}'
|
||||
if prefix:
|
||||
suffix = prefix + suffix
|
||||
classes = tuple(cls for cls in mx_node_classes if cls.__name__.endswith(suffix))
|
||||
|
||||
if not classes:
|
||||
raise KeyError(f"Unable to find MxNode class for {mx_node}")
|
||||
|
||||
def params_set(node, out_type):
|
||||
return {f"in_{p.getName()}:{p.getType()}" for p in node.getActiveInputs()} | \
|
||||
{out_type}
|
||||
{out_type.lower()}
|
||||
|
||||
node_params_set = params_set(mx_node, mx_node.getType())
|
||||
|
||||
|
@ -314,7 +314,7 @@ def generate_basic_classes():
|
||||
gen_code_dir.mkdir(exist_ok=True)
|
||||
|
||||
files = [
|
||||
('PBR', "PBR", utils.MX_LIBS_DIR / "bxdf/standard_surface.mtlx"),
|
||||
('BXDF', "PBR", utils.MX_LIBS_DIR / "bxdf/standard_surface.mtlx"),
|
||||
('USD', "USD", utils.MX_LIBS_DIR / "bxdf/usd_preview_surface.mtlx"),
|
||||
('STD', None, utils.MX_LIBS_DIR / "stdlib/stdlib_defs.mtlx"),
|
||||
('PBR', "PBR", utils.MX_LIBS_DIR / "pbrlib/pbrlib_defs.mtlx"),
|
||||
|
Loading…
Reference in New Issue
Block a user