Update Logging
You can choose between errors, warning, info or full debug, errors will always log to ensure we don't have silent failures with debug on or off.
This commit is contained in:
@@ -0,0 +1,243 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2014 MMD Tools authors
|
||||
# This file was originally part of the MMD Tools add-on for Blender
|
||||
# You can find MMD Tools here: https://github.com/MMD-Blender/blender_mmd_tools
|
||||
# Neoneko has modified this file to work with Avatar Toolkit and may of made changes or improvements.
|
||||
# MMD Tools is licensed under the terms of the GNU General Public License version 3 (GPLv3) same as Avatar Toolkit.
|
||||
|
||||
from typing import Iterable, Optional
|
||||
|
||||
import bpy
|
||||
|
||||
from .core.shader import _NodeGroupUtils
|
||||
from .core.material import FnMaterial
|
||||
|
||||
|
||||
def __switchToCyclesRenderEngine():
|
||||
if bpy.context.scene.render.engine != "CYCLES":
|
||||
bpy.context.scene.render.engine = "CYCLES"
|
||||
|
||||
|
||||
def __exposeNodeTreeInput(in_socket, name, default_value, node_input, shader):
|
||||
_NodeGroupUtils(shader).new_input_socket(name, in_socket, default_value)
|
||||
|
||||
|
||||
def __exposeNodeTreeOutput(out_socket, name, node_output, shader):
|
||||
_NodeGroupUtils(shader).new_output_socket(name, out_socket)
|
||||
|
||||
|
||||
def __getMaterialOutput(nodes, bl_idname):
|
||||
o = next((n for n in nodes if n.bl_idname == bl_idname and n.is_active_output), None) or nodes.new(bl_idname)
|
||||
o.is_active_output = True
|
||||
return o
|
||||
|
||||
|
||||
def create_MMDAlphaShader():
|
||||
__switchToCyclesRenderEngine()
|
||||
|
||||
if "MMDAlphaShader" in bpy.data.node_groups:
|
||||
return bpy.data.node_groups["MMDAlphaShader"]
|
||||
|
||||
shader = bpy.data.node_groups.new(name="MMDAlphaShader", type="ShaderNodeTree")
|
||||
|
||||
node_input = shader.nodes.new("NodeGroupInput")
|
||||
node_output = shader.nodes.new("NodeGroupOutput")
|
||||
node_output.location.x += 250
|
||||
node_input.location.x -= 500
|
||||
|
||||
trans = shader.nodes.new("ShaderNodeBsdfTransparent")
|
||||
trans.location.x -= 250
|
||||
trans.location.y += 150
|
||||
mix = shader.nodes.new("ShaderNodeMixShader")
|
||||
|
||||
shader.links.new(mix.inputs[1], trans.outputs["BSDF"])
|
||||
|
||||
__exposeNodeTreeInput(mix.inputs[2], "Shader", None, node_input, shader)
|
||||
__exposeNodeTreeInput(mix.inputs["Fac"], "Alpha", 1.0, node_input, shader)
|
||||
__exposeNodeTreeOutput(mix.outputs["Shader"], "Shader", node_output, shader)
|
||||
|
||||
return shader
|
||||
|
||||
|
||||
def create_MMDBasicShader():
|
||||
__switchToCyclesRenderEngine()
|
||||
|
||||
if "MMDBasicShader" in bpy.data.node_groups:
|
||||
return bpy.data.node_groups["MMDBasicShader"]
|
||||
|
||||
shader: bpy.types.ShaderNodeTree = bpy.data.node_groups.new(name="MMDBasicShader", type="ShaderNodeTree")
|
||||
|
||||
node_input: bpy.types.NodeGroupInput = shader.nodes.new("NodeGroupInput")
|
||||
node_output: bpy.types.NodeGroupOutput = shader.nodes.new("NodeGroupOutput")
|
||||
node_output.location.x += 250
|
||||
node_input.location.x -= 500
|
||||
|
||||
dif: bpy.types.ShaderNodeBsdfDiffuse = shader.nodes.new("ShaderNodeBsdfDiffuse")
|
||||
dif.location.x -= 250
|
||||
dif.location.y += 150
|
||||
glo: bpy.types.ShaderNodeBsdfAnisotropic = shader.nodes.new("ShaderNodeBsdfAnisotropic")
|
||||
glo.location.x -= 250
|
||||
glo.location.y -= 150
|
||||
mix: bpy.types.ShaderNodeMixShader = shader.nodes.new("ShaderNodeMixShader")
|
||||
shader.links.new(mix.inputs[1], dif.outputs["BSDF"])
|
||||
shader.links.new(mix.inputs[2], glo.outputs["BSDF"])
|
||||
|
||||
__exposeNodeTreeInput(dif.inputs["Color"], "diffuse", [1.0, 1.0, 1.0, 1.0], node_input, shader)
|
||||
__exposeNodeTreeInput(glo.inputs["Color"], "glossy", [1.0, 1.0, 1.0, 1.0], node_input, shader)
|
||||
__exposeNodeTreeInput(glo.inputs["Roughness"], "glossy_rough", 0.0, node_input, shader)
|
||||
__exposeNodeTreeInput(mix.inputs["Fac"], "reflection", 0.02, node_input, shader)
|
||||
__exposeNodeTreeOutput(mix.outputs["Shader"], "shader", node_output, shader)
|
||||
|
||||
return shader
|
||||
|
||||
|
||||
def __enum_linked_nodes(node: bpy.types.Node) -> Iterable[bpy.types.Node]:
|
||||
yield node
|
||||
if node.parent:
|
||||
yield node.parent
|
||||
for n in set(l.from_node for i in node.inputs for l in i.links):
|
||||
yield from __enum_linked_nodes(n)
|
||||
|
||||
|
||||
def __cleanNodeTree(material: bpy.types.Material):
|
||||
nodes = material.node_tree.nodes
|
||||
node_names = set(n.name for n in nodes)
|
||||
for o in (n for n in nodes if n.bl_idname in {"ShaderNodeOutput", "ShaderNodeOutputMaterial"}):
|
||||
if any(i.is_linked for i in o.inputs):
|
||||
node_names -= set(linked.name for linked in __enum_linked_nodes(o))
|
||||
for name in node_names:
|
||||
nodes.remove(nodes[name])
|
||||
|
||||
|
||||
def convertToCyclesShader(obj: bpy.types.Object, use_principled=False, clean_nodes=False, subsurface=0.001):
|
||||
__switchToCyclesRenderEngine()
|
||||
convertToBlenderShader(obj, use_principled, clean_nodes, subsurface)
|
||||
|
||||
|
||||
def convertToBlenderShader(obj: bpy.types.Object, use_principled=False, clean_nodes=False, subsurface=0.001):
|
||||
for i in obj.material_slots:
|
||||
if not i.material:
|
||||
continue
|
||||
if not i.material.use_nodes:
|
||||
i.material.use_nodes = True
|
||||
__convertToMMDBasicShader(i.material)
|
||||
if use_principled:
|
||||
__convertToPrincipledBsdf(i.material, subsurface)
|
||||
if clean_nodes:
|
||||
__cleanNodeTree(i.material)
|
||||
|
||||
def convertToMMDShader(obj):
|
||||
"""BSDF -> MMDShaderDev conversion."""
|
||||
for i in obj.material_slots:
|
||||
if not i.material:
|
||||
continue
|
||||
if not i.material.use_nodes:
|
||||
i.material.use_nodes = True
|
||||
FnMaterial.convert_to_mmd_material(i.material)
|
||||
|
||||
def __convertToMMDBasicShader(material: bpy.types.Material):
|
||||
# TODO: test me
|
||||
mmd_basic_shader_grp = create_MMDBasicShader()
|
||||
mmd_alpha_shader_grp = create_MMDAlphaShader()
|
||||
|
||||
if not any(filter(lambda x: isinstance(x, bpy.types.ShaderNodeGroup) and x.node_tree.name in {"MMDBasicShader", "MMDAlphaShader"}, material.node_tree.nodes)):
|
||||
# Add nodes for Cycles Render
|
||||
shader: bpy.types.ShaderNodeGroup = material.node_tree.nodes.new("ShaderNodeGroup")
|
||||
shader.node_tree = mmd_basic_shader_grp
|
||||
shader.inputs[0].default_value[:3] = material.diffuse_color[:3]
|
||||
shader.inputs[1].default_value[:3] = material.specular_color[:3]
|
||||
shader.inputs["glossy_rough"].default_value = 1.0 / getattr(material, "specular_hardness", 50)
|
||||
outplug = shader.outputs[0]
|
||||
|
||||
location = shader.location.copy()
|
||||
location.x -= 1000
|
||||
|
||||
alpha_value = 1.0
|
||||
if len(material.diffuse_color) > 3:
|
||||
alpha_value = material.diffuse_color[3]
|
||||
|
||||
if alpha_value < 1.0:
|
||||
alpha_shader: bpy.types.ShaderNodeGroup = material.node_tree.nodes.new("ShaderNodeGroup")
|
||||
alpha_shader.location.x = shader.location.x + 250
|
||||
alpha_shader.location.y = shader.location.y - 150
|
||||
alpha_shader.node_tree = mmd_alpha_shader_grp
|
||||
alpha_shader.inputs[1].default_value = alpha_value
|
||||
material.node_tree.links.new(alpha_shader.inputs[0], outplug)
|
||||
outplug = alpha_shader.outputs[0]
|
||||
|
||||
material_output: bpy.types.ShaderNodeOutputMaterial = __getMaterialOutput(material.node_tree.nodes, "ShaderNodeOutputMaterial")
|
||||
material.node_tree.links.new(material_output.inputs["Surface"], outplug)
|
||||
material_output.location.x = shader.location.x + 500
|
||||
material_output.location.y = shader.location.y - 150
|
||||
|
||||
|
||||
def __convertToPrincipledBsdf(material: bpy.types.Material, subsurface: float):
|
||||
node_names = set()
|
||||
for s in (n for n in material.node_tree.nodes if isinstance(n, bpy.types.ShaderNodeGroup)):
|
||||
if s.node_tree.name == "MMDBasicShader":
|
||||
l: bpy.types.NodeLink
|
||||
for l in s.outputs[0].links:
|
||||
to_node = l.to_node
|
||||
# assuming there is no bpy.types.NodeReroute between MMDBasicShader and MMDAlphaShader
|
||||
if isinstance(to_node, bpy.types.ShaderNodeGroup) and to_node.node_tree.name == "MMDAlphaShader":
|
||||
__switchToPrincipledBsdf(material.node_tree, s, subsurface, node_alpha=to_node)
|
||||
node_names.add(to_node.name)
|
||||
else:
|
||||
__switchToPrincipledBsdf(material.node_tree, s, subsurface)
|
||||
node_names.add(s.name)
|
||||
elif s.node_tree.name == "MMDShaderDev":
|
||||
__switchToPrincipledBsdf(material.node_tree, s, subsurface)
|
||||
node_names.add(s.name)
|
||||
# remove MMD shader nodes
|
||||
nodes = material.node_tree.nodes
|
||||
for name in node_names:
|
||||
nodes.remove(nodes[name])
|
||||
|
||||
|
||||
def __switchToPrincipledBsdf(node_tree: bpy.types.NodeTree, node_basic: bpy.types.ShaderNodeGroup, subsurface: float, node_alpha: Optional[bpy.types.ShaderNodeGroup] = None):
|
||||
shader: bpy.types.ShaderNodeBsdfPrincipled = node_tree.nodes.new("ShaderNodeBsdfPrincipled")
|
||||
shader.parent = node_basic.parent
|
||||
shader.location.x = node_basic.location.x
|
||||
shader.location.y = node_basic.location.y
|
||||
|
||||
alpha_socket_name = "Alpha"
|
||||
if node_basic.node_tree.name == "MMDShaderDev":
|
||||
node_alpha, alpha_socket_name = node_basic, "Base Alpha"
|
||||
if "Base Tex" in node_basic.inputs and node_basic.inputs["Base Tex"].is_linked:
|
||||
node_tree.links.new(node_basic.inputs["Base Tex"].links[0].from_socket, shader.inputs["Base Color"])
|
||||
elif "Diffuse Color" in node_basic.inputs:
|
||||
shader.inputs["Base Color"].default_value[:3] = node_basic.inputs["Diffuse Color"].default_value[:3]
|
||||
elif "diffuse" in node_basic.inputs:
|
||||
shader.inputs["Base Color"].default_value[:3] = node_basic.inputs["diffuse"].default_value[:3]
|
||||
if node_basic.inputs["diffuse"].is_linked:
|
||||
node_tree.links.new(node_basic.inputs["diffuse"].links[0].from_socket, shader.inputs["Base Color"])
|
||||
|
||||
shader.inputs["IOR"].default_value = 1.0
|
||||
shader.inputs["Subsurface Weight"].default_value = subsurface
|
||||
|
||||
output_links = node_basic.outputs[0].links
|
||||
if node_alpha:
|
||||
output_links = node_alpha.outputs[0].links
|
||||
shader.parent = node_alpha.parent or shader.parent
|
||||
shader.location.x = node_alpha.location.x
|
||||
|
||||
if alpha_socket_name in node_alpha.inputs:
|
||||
if "Alpha" in shader.inputs:
|
||||
shader.inputs["Alpha"].default_value = node_alpha.inputs[alpha_socket_name].default_value
|
||||
if node_alpha.inputs[alpha_socket_name].is_linked:
|
||||
node_tree.links.new(node_alpha.inputs[alpha_socket_name].links[0].from_socket, shader.inputs["Alpha"])
|
||||
else:
|
||||
shader.inputs["Transmission"].default_value = 1 - node_alpha.inputs[alpha_socket_name].default_value
|
||||
if node_alpha.inputs[alpha_socket_name].is_linked:
|
||||
node_invert = node_tree.nodes.new("ShaderNodeMath")
|
||||
node_invert.parent = shader.parent
|
||||
node_invert.location.x = node_alpha.location.x - 250
|
||||
node_invert.location.y = node_alpha.location.y - 300
|
||||
node_invert.operation = "SUBTRACT"
|
||||
node_invert.use_clamp = True
|
||||
node_invert.inputs[0].default_value = 1
|
||||
node_tree.links.new(node_alpha.inputs[alpha_socket_name].links[0].from_socket, node_invert.inputs[1])
|
||||
node_tree.links.new(node_invert.outputs[0], shader.inputs["Transmission"])
|
||||
|
||||
for l in output_links:
|
||||
node_tree.links.new(shader.outputs[0], l.to_socket)
|
||||
Reference in New Issue
Block a user