From f2f5c3848d57bb1bc65984b54101440d7eb9b2e8 Mon Sep 17 00:00:00 2001 From: Liudvikas Lazauskas Date: Wed, 11 Oct 2023 13:42:26 +0200 Subject: [PATCH] Fixed world material export to support environmental maps without emission node --- mitsuba-blender/io/exporter/materials.py | 141 ++++++++++++----------- 1 file changed, 75 insertions(+), 66 deletions(-) diff --git a/mitsuba-blender/io/exporter/materials.py b/mitsuba-blender/io/exporter/materials.py index b3e5a15..1a53579 100644 --- a/mitsuba-blender/io/exporter/materials.py +++ b/mitsuba-blender/io/exporter/materials.py @@ -432,76 +432,85 @@ def convert_world(export_ctx, world, ignore_background): if not output_node.inputs["Surface"].is_linked: return surface_node = output_node.inputs["Surface"].links[0].from_node - if surface_node.inputs['Strength'].is_linked: - raise NotImplementedError("Only default emitter strength value is supported.")#TODO: value input - strength = surface_node.inputs['Strength'].default_value - - if strength == 0: # Don't add an emitter if it emits nothing - export_ctx.log('Ignoring envmap with zero strength.', 'INFO') - return - + # Perform environment map check at the start if surface_node.type in ['BACKGROUND', 'EMISSION']: + if surface_node.inputs['Strength'].is_linked: + raise NotImplementedError( + "Only default emitter strength value is supported.") # TODO: value input + strength = surface_node.inputs['Strength'].default_value + + if strength == 0: # Don't add an emitter if it emits nothing + export_ctx.log('Ignoring envmap with zero strength.', 'INFO') + return socket = surface_node.inputs["Color"] - if socket.is_linked: - color_node = socket.links[0].from_node - if color_node.type == 'TEX_ENVIRONMENT': - params.update({ - 'type': 'envmap', - 'filename': export_ctx.export_texture(color_node.image), - 'scale': strength - }) - coordinate_mat = Matrix(((0,0,1,0),(1,0,0,0),(0,1,0,0),(0,0,0,1))) - to_world = Matrix()#4x4 Identity - if color_node.inputs["Vector"].is_linked: - vector_node = color_node.inputs["Vector"].links[0].from_node - if vector_node.type != 'MAPPING': - raise NotImplementedError("Node: %s is not supported. Only a mapping node is supported" % vector_node.bl_idname) - if not vector_node.inputs["Vector"].is_linked: - raise NotImplementedError("The node %s should be linked with a Texture coordinate node." % vector_node.bl_idname) - coord_node = vector_node.inputs["Vector"].links[0].from_node - coord_socket = vector_node.inputs["Vector"].links[0].from_socket - if coord_node.type != 'TEX_COORD': - raise NotImplementedError("Unsupported node type: %s." % coord_node.bl_idname) - if coord_socket.name != 'Generated': - raise NotImplementedError("Link should come from 'Generated'.") - #only supported node setup for transform - if vector_node.vector_type != 'TEXTURE': - raise NotImplementedError("Only 'Texture' mapping mode is supported.") - if vector_node.inputs["Location"].is_linked or vector_node.inputs["Rotation"].is_linked or vector_node.inputs["Scale"].is_linked: - raise NotImplementedError("Transfrom inputs shouldn't be linked.") - - rotation = vector_node.inputs["Rotation"].default_value.to_matrix() - scale = vector_node.inputs["Scale"].default_value - location = vector_node.inputs["Location"].default_value - for i in range(3): - for j in range(3): - to_world[i][j] = rotation[i][j] - to_world[i][i] *= scale[i] - to_world[i][3] = location[i] - to_world = to_world - #TODO: support other types of mappings (vector, point...) - #change default position, apply transform and change coordinates - params['to_world'] = export_ctx.transform_matrix(to_world @ coordinate_mat) - elif color_node.type == 'RGB': - color = color_node.color - else: - raise NotImplementedError("Node type %s is not supported. Consider using an environment texture or RGB node instead." % color_node.bl_idname) + elif surface_node.type == 'TEX_ENVIRONMENT': + # Set to current node in next step we will get texEnvironment + socket = output_node.inputs["Surface"] + else: + raise NotImplementedError( + "Only Background and Emission nodes are supported as final nodes for World export, got '%s'" % surface_node.name) + + if socket.is_linked: + color_node = socket.links[0].from_node + if color_node.type == 'TEX_ENVIRONMENT': + envmap = { + 'type': 'envmap', + 'filename': export_ctx.export_texture(color_node.image), + } + # The default background texture does not require emitter strength + if surface_node.type != 'TEX_ENVIRONMENT': + envmap['scale'] = strength + params.update(envmap) + coordinate_mat = Matrix(((0,0,1,0),(1,0,0,0),(0,1,0,0),(0,0,0,1))) + to_world = Matrix()#4x4 Identity + if color_node.inputs["Vector"].is_linked: + vector_node = color_node.inputs["Vector"].links[0].from_node + if vector_node.type != 'MAPPING': + raise NotImplementedError("Node: %s is not supported. Only a mapping node is supported" % vector_node.bl_idname) + if not vector_node.inputs["Vector"].is_linked: + raise NotImplementedError("The node %s should be linked with a Texture coordinate node." % vector_node.bl_idname) + coord_node = vector_node.inputs["Vector"].links[0].from_node + coord_socket = vector_node.inputs["Vector"].links[0].from_socket + if coord_node.type != 'TEX_COORD': + raise NotImplementedError("Unsupported node type: %s." % coord_node.bl_idname) + if coord_socket.name != 'Generated': + raise NotImplementedError("Link should come from 'Generated'.") + #only supported node setup for transform + if vector_node.vector_type != 'TEXTURE': + raise NotImplementedError("Only 'Texture' mapping mode is supported.") + if vector_node.inputs["Location"].is_linked or vector_node.inputs["Rotation"].is_linked or vector_node.inputs["Scale"].is_linked: + raise NotImplementedError("Transfrom inputs shouldn't be linked.") + + rotation = vector_node.inputs["Rotation"].default_value.to_matrix() + scale = vector_node.inputs["Scale"].default_value + location = vector_node.inputs["Location"].default_value + for i in range(3): + for j in range(3): + to_world[i][j] = rotation[i][j] + to_world[i][i] *= scale[i] + to_world[i][3] = location[i] + to_world = to_world + #TODO: support other types of mappings (vector, point...) + #change default position, apply transform and change coordinates + params['to_world'] = export_ctx.transform_matrix(to_world @ coordinate_mat) + elif color_node.type == 'RGB': + color = color_node.color else: - color = socket.default_value - if 'type' not in params: # Not an envmap - radiance = [x * strength for x in color[:3]] - if ignore_background and radiance == [0.05087608844041824]*3: - export_ctx.log("Ignoring Blender's default background...", 'INFO') - return - if np.sum(radiance) == 0: - export_ctx.log("Ignoring background emitter with zero emission.", 'INFO') - return - params.update({ - 'type': 'constant', - 'radiance': export_ctx.spectrum(radiance) - }) + raise NotImplementedError("Node type %s is not supported. Consider using an environment texture or RGB node instead." % color_node.bl_idname) else: - raise NotImplementedError("Only Background and Emission nodes are supported as final nodes for World export, got '%s'" % surface_node.name) + color = socket.default_value + if 'type' not in params: # Not an envmap + radiance = [x * strength for x in color[:3]] + if ignore_background and radiance == [0.05087608844041824]*3: + export_ctx.log("Ignoring Blender's default background...", 'INFO') + return + if np.sum(radiance) == 0: + export_ctx.log("Ignoring background emitter with zero emission.", 'INFO') + return + params.update({ + 'type': 'constant', + 'radiance': export_ctx.spectrum(radiance) + }) else: # Single color field for emission, no nodes params.update({