From d962add24cb7e55fa30b63763b4dbf7f37af0079 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Tue, 13 Apr 2021 11:33:13 +0300 Subject: [PATCH] Recognize a certain configuration of nodes as inverting Y for normals Models made for DirectX treat the normal map values as having positive Y pointing toward the bottom of the image, which is opposite to what my engine and Blender expect. This allows fixing that without modifying the original texture. --- blender/io_mspgl/export_material.py | 2 +- blender/io_mspgl/export_texture.py | 12 +++++++++-- blender/io_mspgl/material.py | 32 +++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/blender/io_mspgl/export_material.py b/blender/io_mspgl/export_material.py index 10be7dcb..1323737f 100644 --- a/blender/io_mspgl/export_material.py +++ b/blender/io_mspgl/export_material.py @@ -50,7 +50,7 @@ class MaterialExporter: if p.texture: tex_name = p.texture.image.name+".tex2d" if tex_name not in resources: - resources[tex_name] = texture_export.export_texture(p.texture, p.tex_usage) + resources[tex_name] = texture_export.export_texture(p.texture, p.tex_usage, invert_green=p.invert_green) samp_name = sampler_export.get_sampler_name(p.texture) if samp_name not in resources: diff --git a/blender/io_mspgl/export_texture.py b/blender/io_mspgl/export_texture.py index 6ec13ead..8e3872b5 100644 --- a/blender/io_mspgl/export_texture.py +++ b/blender/io_mspgl/export_texture.py @@ -15,6 +15,12 @@ def pixels_to_rgb(pixels): yield int(pixels[i+1]*255) yield int(pixels[i+2]*255) +def pixels_to_rgb_invert_green(pixels): + for i in range(0, len(pixels), 4): + yield int(pixels[i]*255) + yield 255-int(pixels[i+1]*255) + yield int(pixels[i+2]*255) + def pixels_to_gray(pixels): for i in range(0, len(pixels), 4): yield int((pixels[i]+pixels[i+1]+pixels[i+2])*255/3) @@ -23,7 +29,7 @@ class TextureExporter: def __init__(self): self.inline_data = True - def export_texture(self, tex_node, usage='RGB'): + def export_texture(self, tex_node, usage='RGB', *, invert_green=False): image = tex_node.image from .datafile import Resource, Statement, Token tex_res = Resource(image.name+".tex2d", "texture2d") @@ -37,7 +43,7 @@ class TextureExporter: from .util import basename fn = basename(image.filepath) - if not self.inline_data and fn: + if not self.inline_data and not invert_green and fn: srgb = "_srgb" if colorspace=='sRGB' else "" tex_res.statements.append(Statement("external_image"+srgb, fn)) else: @@ -56,6 +62,8 @@ class TextureExporter: texdata = encode_pixels(pixels_to_rgba(pixels)) elif usage=='GRAY': texdata = encode_pixels(pixels_to_gray(pixels)) + elif invert_green: + texdata = encode_pixels(pixels_to_rgb_invert_green(pixels)) else: texdata = encode_pixels(pixels_to_rgb(pixels)) tex_res.statements.append(Statement("raw_data", texdata)) diff --git a/blender/io_mspgl/material.py b/blender/io_mspgl/material.py index e69cab84..cadfe75e 100644 --- a/blender/io_mspgl/material.py +++ b/blender/io_mspgl/material.py @@ -8,6 +8,33 @@ def get_linked_node_and_socket(node_tree, socket): return (l.to_node, l.to_socket) return (None, None) +def check_group(node_tree, group, func): + output = group.node_tree.nodes["Group Output"] + from_node, _ = get_linked_node_and_socket(group.node_tree, output.inputs[0]) + if from_node: + from_node, _ = func(group.node_tree, from_node) + if from_node and from_node.type=='GROUP_INPUT': + return get_linked_node_and_socket(node_tree, group.inputs[0]) + return (None, None) + +def check_invert_green(node_tree, node): + if node.type=='GROUP': + return check_group(node_tree, node, check_invert_green) + elif node.type!='COMBRGB': + return (None, None) + + green, g_sock = get_linked_node_and_socket(node_tree, node.inputs["G"]) + if not green or green.type!='MATH' or green.operation!='SUBTRACT': + return (None, None) + green, g_sock = get_linked_node_and_socket(node_tree, green.inputs[1]) + + red, r_sock = get_linked_node_and_socket(node_tree, node.inputs["R"]) + blue, b_sock = get_linked_node_and_socket(node_tree, node.inputs["B"]) + if not red or red.type!='SEPRGB' or blue!=red or green!=red: + return (None, None) + + return get_linked_node_and_socket(node_tree, red.inputs["Image"]) + class MaterialProperty: def __init__(self, keyword, tex_keyword, value): self.keyword = keyword @@ -15,6 +42,7 @@ class MaterialProperty: self.value = value self.texture = None self.tex_usage = None + self.invert_green = False def set_from_input(self, node_tree, input_socket, alpha_socket=None): if self.keyword: @@ -33,6 +61,10 @@ class MaterialProperty: usage = None if from_node.type=='NORMAL_MAP': from_node, _ = get_linked_node_and_socket(node_tree, from_node.inputs["Color"]) + invert, _ = check_invert_green(node_tree, from_node) + if invert: + from_node = invert + self.invert_green = True usage = 'RGB' elif from_node.type=='RGBTOBW': from_node, _ = get_linked_node_and_socket(node_tree, from_node.inputs["Color"]) -- 2.45.2