Export ImageTexture node for an image identified in material node tree #39

Open
Vincent Marchetti wants to merge 7 commits from vmarchetti/io_scene_x3d:image-export into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
Showing only changes of commit 35fbe6c6f8 - Show all commits

View File

@ -0,0 +1,114 @@
# SPDX-FileCopyrightText: 2011-2024 Blender Foundation
Review

Not sure about the copyright. Technically this is no longer property of bf, so if you want, you can put in your name (or Web3D Consortium as you're a member there) and current year

Not sure about the copyright. Technically this is no longer property of bf, so if you want, you can put in your name (or Web3D Consortium as you're a member there) and current year
#
# SPDX-License-Identifier: GPL-3.0-or-later
import logging
_logger = logging.getLogger("export_x3d.material_node_search")
"""
functions implementing searching the node tree for Blender materials in search
of particular nodes enabling export of material properties into other formats
"""
# node based material identifiers
#BSDF_PRINCIPLED = 'BSDF_PRINCIPLED'
# IMAGE = 'image'
# values of bl_idname for shader nodes to be located
# reference Python API list of subclasses of ShaderNode
# at https://docs.blender.org/api/current/bpy.types.ShaderNode.html#bpy.types.ShaderNode
class _ShaderNodeTypes:
MATERIAL_OUTPUT= "ShaderNodeOutputMaterial"
BSDF_PRINCIPLED = "ShaderNodeBsdfPrincipled"
IMAGE_TEXTURE = "ShaderNodeTexImage"
# supported values of Image Texture Node extension property
# REPEAT="REPEAT"
# CLIP ="CLIP"
def _find_node_by_idname(nodes, idname):
"""
nodes a sequence of Nodes, idname a string
Review

a few typos here

a few typos here
Each node assumed to ne an instance of Node(bpy_struct)
https://docs.blender.org/api/current/bpy.types.Node.html
The idname is searched for in the Node instance member bl_idname
https://docs.blender.org/api/current/bpy.types.Node.html#bpy.types.Node.bl_idname
and is generally some string version of the name of the subclass
See https://docs.blender.org/api/current/bpy.types.ShaderNode.html for list of
ShaderNode subclasses
if 0 targets are found, returns None
Review

the output as code is not really needed in the docstring, but if you want simplify: Returns None if no targets are found or returns the first found target

the output as code is not really needed in the docstring, but if you want simplify: Returns None if no targets are found or returns the first found target
if 1 target is found returns that Node
if more than 1 targets are found prints warning string and returns first found
"""
_logger.debug("enter _find_node_by_idname search for %s in %r" % (idname, nodes))
nodelist = [nd for nd in nodes if nd.bl_idname == idname]
_logger.debug("result _find_node_by_idname found %i" % len(nodelist))
if len(nodelist) == 0:
return None
if len(nodelist) > 1:
_logger.warn("_find_node_by_idname : multiple (%i) nodes of type %s found" % (len(nodelist), idname))
return nodelist[0]
def imageTexture_in_material(material):
"""
argument material an instance of Material(ID)
https://docs.blender.org/api/current/bpy.types.Material.html
returns instance of ShaderNodeTexImage
https://docs.blender.org/api/current/bpy.types.ShaderNodeTexImage.html
"""
_logger.debug("evaluating image in material %s" % material.name)
material_output = _find_node_by_idname( material.node_tree.nodes, _ShaderNodeTypes.MATERIAL_OUTPUT)
if material_output is None:
_logger.warn("%s not found in material %s" % (_ShaderNodeTypes.MATERIAL_OUTPUT, material.name))
return None
SURFACE_ATTRIBUTE= "Surface"
bsdf_principled = _find_node_by_idname(
[ndlink.from_node for ndlink in material_output.inputs.get(SURFACE_ATTRIBUTE).links],
_ShaderNodeTypes.BSDF_PRINCIPLED)
if bsdf_principled is None : return None
Review

for better readability put the return into it's own line

for better readability put the return into it's own line
BASE_COLOR_ATTRIBUTE = 'Base Color'
image_texture = _find_node_by_idname(
[ndlink.from_node for ndlink in bsdf_principled.inputs.get(BASE_COLOR_ATTRIBUTE).links],
_ShaderNodeTypes.IMAGE_TEXTURE )
if image_texture is None: return None
Review

for better readability put the return into it's own line

for better readability put the return into it's own line
_logger.debug("located image texture node %r" % image_texture)
return image_texture
## x3d_supported_file_extension = {"PNG" : ".png","JPEG" : ".jpg"}
Review

dead code

dead code
## if image_texture.image.file_format not in x3d_supported_file_extension:
## logger.warn("images of format %s not supported" % image_texture.image.file_format)
## return None
##
## retVal = self.ImageExportRecord()
## retVal.image = image_texture.image
##
## # ref https://docs.blender.org/api/current/bpy.types.ShaderNodeTexImage.html#bpy.types.ShaderNodeTexImage.extension
## x3d_supported_extension = [CLIP, REPEAT]
## if image_texture.extension in x3d_supported_extension:
## retVal.extension = image_texture.extension
## else:
## logger.warn("image_texture.extension value %s unsupported in X3D" % image_texture.extension)
## retVal.extension=REPEAT
##
## packed_file = image_texture.image.packed_file
## if packed_file is not None and packed_file.size > 0:
## from os.path import splitext, basename
## name_base = splitext( basename(image_texture.image.name))[0]
## url_ext = x3d_supported_file_extension[image_texture.image.file_format]
## retVal.url = name_base +url_ext
##
## logger.info("ImageExportRecord : %s packed: %r url: %s : extension: %r" % \
## (retVal.image.name, retVal.is_packed,
## retVal.url , retVal.extension))
##
## return retVal