123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804 |
- # ##### BEGIN GPL LICENSE BLOCK #####
- #
- # This program is free software; you can redistribute it and/or
- # modify it under the terms of the GNU General Public License
- # as published by the Free Software Foundation; either version 2
- # of the License, or (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program; if not, write to the Free Software Foundation,
- # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- #
- # ##### END GPL LICENSE BLOCK #####
- # <pep8 compliant>
- from mathutils import Color, Vector
- __all__ = (
- "PrincipledBSDFWrapper",
- )
- def _set_check(func):
- from functools import wraps
- @wraps(func)
- def wrapper(self, *args, **kwargs):
- if self.is_readonly:
- assert(not "Trying to set value to read-only shader!")
- return
- return func(self, *args, **kwargs)
- return wrapper
- def rgb_to_rgba(rgb):
- return list(rgb) + [1.0]
- def rgba_to_rgb(rgba):
- return Color((rgba[0], rgba[1], rgba[2]))
- class ShaderWrapper():
- """
- Base class with minimal common ground for all types of shader interfaces we may want/need to implement.
- """
- # The two mandatory nodes any children class should support.
- NODES_LIST = (
- "node_out",
- "_node_texcoords",
- )
- __slots__ = (
- "is_readonly",
- "material",
- "_textures",
- "_grid_locations",
- *NODES_LIST,
- )
- _col_size = 300
- _row_size = 300
- def _grid_to_location(self, x, y, dst_node=None, ref_node=None):
- if ref_node is not None: # x and y are relative to this node location.
- nx = round(ref_node.location.x / self._col_size)
- ny = round(ref_node.location.y / self._row_size)
- x += nx
- y += ny
- loc = None
- while True:
- loc = (x * self._col_size, y * self._row_size)
- if loc not in self._grid_locations:
- break
- loc = (x * self._col_size, (y - 1) * self._row_size)
- if loc not in self._grid_locations:
- break
- loc = (x * self._col_size, (y - 2) * self._row_size)
- if loc not in self._grid_locations:
- break
- x -= 1
- self._grid_locations.add(loc)
- if dst_node is not None:
- dst_node.location = loc
- dst_node.width = min(dst_node.width, self._col_size - 20)
- return loc
- def __init__(self, material, is_readonly=True, use_nodes=True):
- self.is_readonly = is_readonly
- self.material = material
- if not is_readonly:
- self.use_nodes = use_nodes
- self.update()
- def update(self): # Should be re-implemented by children classes...
- for node in self.NODES_LIST:
- setattr(self, node, None)
- self._textures = {}
- self._grid_locations = set()
- def use_nodes_get(self):
- return self.material.use_nodes
- @_set_check
- def use_nodes_set(self, val):
- self.material.use_nodes = val
- self.update()
- use_nodes = property(use_nodes_get, use_nodes_set)
- def node_texcoords_get(self):
- if not self.use_nodes:
- return None
- if self._node_texcoords is ...:
- # Running only once, trying to find a valid texcoords node.
- for n in self.material.node_tree.nodes:
- if n.bl_idname == 'ShaderNodeTexCoord':
- self._node_texcoords = n
- self._grid_to_location(0, 0, ref_node=n)
- break
- if self._node_texcoords is ...:
- self._node_texcoords = None
- if self._node_texcoords is None and not self.is_readonly:
- tree = self.material.node_tree
- nodes = tree.nodes
- # links = tree.links
- node_texcoords = nodes.new(type='ShaderNodeTexCoord')
- node_texcoords.label = "Texture Coords"
- self._grid_to_location(-5, 1, dst_node=node_texcoords)
- self._node_texcoords = node_texcoords
- return self._node_texcoords
- node_texcoords = property(node_texcoords_get)
- class PrincipledBSDFWrapper(ShaderWrapper):
- """
- Hard coded shader setup, based in Principled BSDF.
- Should cover most common cases on import, and gives a basic nodal shaders support for export.
- Supports basic: diffuse/spec/reflect/transparency/normal, with texturing.
- """
- NODES_LIST = (
- "node_out",
- "node_principled_bsdf",
- "_node_normalmap",
- "_node_texcoords",
- )
- __slots__ = (
- "is_readonly",
- "material",
- *NODES_LIST,
- )
- NODES_LIST = ShaderWrapper.NODES_LIST + NODES_LIST
- def __init__(self, material, is_readonly=True, use_nodes=True):
- super(PrincipledBSDFWrapper, self).__init__(material, is_readonly, use_nodes)
- def update(self):
- super(PrincipledBSDFWrapper, self).update()
- if not self.use_nodes:
- return
- tree = self.material.node_tree
- nodes = tree.nodes
- links = tree.links
- # --------------------------------------------------------------------
- # Main output and shader.
- node_out = None
- node_principled = None
- for n in nodes:
- if n.bl_idname == 'ShaderNodeOutputMaterial' and n.inputs[0].is_linked:
- node_out = n
- node_principled = n.inputs[0].links[0].from_node
- elif n.bl_idname == 'ShaderNodeBsdfPrincipled' and n.outputs[0].is_linked:
- node_principled = n
- for lnk in n.outputs[0].links:
- node_out = lnk.to_node
- if node_out.bl_idname == 'ShaderNodeOutputMaterial':
- break
- if (
- node_out is not None and node_principled is not None and
- node_out.bl_idname == 'ShaderNodeOutputMaterial' and
- node_principled.bl_idname == 'ShaderNodeBsdfPrincipled'
- ):
- break
- node_out = node_principled = None # Could not find a valid pair, let's try again
- if node_out is not None:
- self._grid_to_location(0, 0, ref_node=node_out)
- elif not self.is_readonly:
- node_out = nodes.new(type='ShaderNodeOutputMaterial')
- node_out.label = "Material Out"
- node_out.target = 'ALL'
- self._grid_to_location(1, 1, dst_node=node_out)
- self.node_out = node_out
- if node_principled is not None:
- self._grid_to_location(0, 0, ref_node=node_principled)
- elif not self.is_readonly:
- node_principled = nodes.new(type='ShaderNodeBsdfPrincipled')
- node_principled.label = "Principled BSDF"
- self._grid_to_location(0, 1, dst_node=node_principled)
- # Link
- links.new(node_principled.outputs["BSDF"], self.node_out.inputs["Surface"])
- self.node_principled_bsdf = node_principled
- # --------------------------------------------------------------------
- # Normal Map, lazy initialization...
- self._node_normalmap = ...
- # --------------------------------------------------------------------
- # Tex Coords, lazy initialization...
- self._node_texcoords = ...
- def node_normalmap_get(self):
- if not self.use_nodes or self.node_principled_bsdf is None:
- return None
- node_principled = self.node_principled_bsdf
- if self._node_normalmap is ...:
- # Running only once, trying to find a valid normalmap node.
- if node_principled.inputs["Normal"].is_linked:
- node_normalmap = node_principled.inputs["Normal"].links[0].from_node
- if node_normalmap.bl_idname == 'ShaderNodeNormalMap':
- self._node_normalmap = node_normalmap
- self._grid_to_location(0, 0, ref_node=node_normalmap)
- if self._node_normalmap is ...:
- self._node_normalmap = None
- if self._node_normalmap is None and not self.is_readonly:
- tree = self.material.node_tree
- nodes = tree.nodes
- links = tree.links
- node_normalmap = nodes.new(type='ShaderNodeNormalMap')
- node_normalmap.label = "Normal/Map"
- self._grid_to_location(-1, -2, dst_node=node_normalmap, ref_node=node_principled)
- # Link
- links.new(node_normalmap.outputs["Normal"], node_principled.inputs["Normal"])
- self._node_normalmap = node_normalmap
- return self._node_normalmap
- node_normalmap = property(node_normalmap_get)
- # --------------------------------------------------------------------
- # Base Color.
- def base_color_get(self):
- if not self.use_nodes or self.node_principled_bsdf is None:
- return self.material.diffuse_color
- return rgba_to_rgb(self.node_principled_bsdf.inputs["Base Color"].default_value)
- @_set_check
- def base_color_set(self, color):
- color = rgb_to_rgba(color)
- self.material.diffuse_color = color
- if self.use_nodes and self.node_principled_bsdf is not None:
- self.node_principled_bsdf.inputs["Base Color"].default_value = color
- base_color = property(base_color_get, base_color_set)
- def base_color_texture_get(self):
- if not self.use_nodes or self.node_principled_bsdf is None:
- return None
- return ShaderImageTextureWrapper(
- self, self.node_principled_bsdf,
- self.node_principled_bsdf.inputs["Base Color"],
- grid_row_diff=1,
- )
- base_color_texture = property(base_color_texture_get)
- # --------------------------------------------------------------------
- # Specular.
- def specular_get(self):
- if not self.use_nodes or self.node_principled_bsdf is None:
- return self.material.specular_intensity
- return self.node_principled_bsdf.inputs["Specular"].default_value
- @_set_check
- def specular_set(self, value):
- self.material.specular_intensity = value
- if self.use_nodes and self.node_principled_bsdf is not None:
- self.node_principled_bsdf.inputs["Specular"].default_value = value
- specular = property(specular_get, specular_set)
- def specular_tint_get(self):
- if not self.use_nodes or self.node_principled_bsdf is None:
- return 0.0
- return self.node_principled_bsdf.inputs["Specular Tint"].default_value
- @_set_check
- def specular_tint_set(self, value):
- if self.use_nodes and self.node_principled_bsdf is not None:
- self.node_principled_bsdf.inputs["Specular Tint"].default_value = value
- specular_tint = property(specular_tint_get, specular_tint_set)
- # Will only be used as gray-scale one...
- def specular_texture_get(self):
- if not self.use_nodes or self.node_principled_bsdf is None:
- print("NO NODES!")
- return None
- return ShaderImageTextureWrapper(
- self, self.node_principled_bsdf,
- self.node_principled_bsdf.inputs["Specular"],
- grid_row_diff=0,
- )
- specular_texture = property(specular_texture_get)
- # --------------------------------------------------------------------
- # Roughness (also sort of inverse of specular hardness...).
- def roughness_get(self):
- if not self.use_nodes or self.node_principled_bsdf is None:
- return self.material.roughness
- return self.node_principled_bsdf.inputs["Roughness"].default_value
- @_set_check
- def roughness_set(self, value):
- self.material.roughness = value
- if self.use_nodes and self.node_principled_bsdf is not None:
- self.node_principled_bsdf.inputs["Roughness"].default_value = value
- roughness = property(roughness_get, roughness_set)
- # Will only be used as gray-scale one...
- def roughness_texture_get(self):
- if not self.use_nodes or self.node_principled_bsdf is None:
- return None
- return ShaderImageTextureWrapper(
- self, self.node_principled_bsdf,
- self.node_principled_bsdf.inputs["Roughness"],
- grid_row_diff=0,
- )
- roughness_texture = property(roughness_texture_get)
- # --------------------------------------------------------------------
- # Metallic (a.k.a reflection, mirror).
- def metallic_get(self):
- if not self.use_nodes or self.node_principled_bsdf is None:
- return self.material.metallic
- return self.node_principled_bsdf.inputs["Metallic"].default_value
- @_set_check
- def metallic_set(self, value):
- self.material.metallic = value
- if self.use_nodes and self.node_principled_bsdf is not None:
- self.node_principled_bsdf.inputs["Metallic"].default_value = value
- metallic = property(metallic_get, metallic_set)
- # Will only be used as gray-scale one...
- def metallic_texture_get(self):
- if not self.use_nodes or self.node_principled_bsdf is None:
- return None
- return ShaderImageTextureWrapper(
- self, self.node_principled_bsdf,
- self.node_principled_bsdf.inputs["Metallic"],
- grid_row_diff=0,
- )
- metallic_texture = property(metallic_texture_get)
- # --------------------------------------------------------------------
- # Transparency settings.
- def ior_get(self):
- if not self.use_nodes or self.node_principled_bsdf is None:
- return 1.0
- return self.node_principled_bsdf.inputs["IOR"].default_value
- @_set_check
- def ior_set(self, value):
- if self.use_nodes and self.node_principled_bsdf is not None:
- self.node_principled_bsdf.inputs["IOR"].default_value = value
- ior = property(ior_get, ior_set)
- # Will only be used as gray-scale one...
- def ior_texture_get(self):
- if not self.use_nodes or self.node_principled_bsdf is None:
- return None
- return ShaderImageTextureWrapper(
- self, self.node_principled_bsdf,
- self.node_principled_bsdf.inputs["IOR"],
- grid_row_diff=-1,
- )
- ior_texture = property(ior_texture_get)
- def transmission_get(self):
- if not self.use_nodes or self.node_principled_bsdf is None:
- return 0.0
- return self.node_principled_bsdf.inputs["Transmission"].default_value
- @_set_check
- def transmission_set(self, value):
- if self.use_nodes and self.node_principled_bsdf is not None:
- self.node_principled_bsdf.inputs["Transmission"].default_value = value
- transmission = property(transmission_get, transmission_set)
- # Will only be used as gray-scale one...
- def transmission_texture_get(self):
- if not self.use_nodes or self.node_principled_bsdf is None:
- return None
- return ShaderImageTextureWrapper(
- self, self.node_principled_bsdf,
- self.node_principled_bsdf.inputs["Transmission"],
- grid_row_diff=-1,
- )
- transmission_texture = property(transmission_texture_get)
- def alpha_get(self):
- if not self.use_nodes or self.node_principled_bsdf is None:
- return 1.0
- return self.node_principled_bsdf.inputs["Alpha"].default_value
- @_set_check
- def alpha_set(self, value):
- if self.use_nodes and self.node_principled_bsdf is not None:
- self.node_principled_bsdf.inputs["Alpha"].default_value = value
- alpha = property(alpha_get, alpha_set)
- # Will only be used as gray-scale one...
- def alpha_texture_get(self):
- if not self.use_nodes or self.node_principled_bsdf is None:
- return None
- return ShaderImageTextureWrapper(
- self, self.node_principled_bsdf,
- self.node_principled_bsdf.inputs["Alpha"],
- grid_row_diff=-1,
- )
- alpha_texture = property(alpha_texture_get)
- # --------------------------------------------------------------------
- # Normal map.
- def normalmap_strength_get(self):
- if not self.use_nodes or self.node_normalmap is None:
- return 0.0
- return self.node_normalmap.inputs["Strength"].default_value
- @_set_check
- def normalmap_strength_set(self, value):
- if self.use_nodes and self.node_normalmap is not None:
- self.node_normalmap.inputs["Strength"].default_value = value
- normalmap_strength = property(normalmap_strength_get, normalmap_strength_set)
- def normalmap_texture_get(self):
- if not self.use_nodes or self.node_normalmap is None:
- return None
- return ShaderImageTextureWrapper(
- self, self.node_normalmap,
- self.node_normalmap.inputs["Color"],
- grid_row_diff=-2,
- colorspace_is_data=True,
- )
- normalmap_texture = property(normalmap_texture_get)
- class ShaderImageTextureWrapper():
- """
- Generic 'image texture'-like wrapper, handling image node, some mapping (texture coordinates transformations),
- and texture coordinates source.
- """
- # Note: this class assumes we are using nodes, otherwise it should never be used...
- NODES_LIST = (
- "node_dst",
- "socket_dst",
- "_node_image",
- "_node_mapping",
- )
- __slots__ = (
- "owner_shader",
- "is_readonly",
- "grid_row_diff",
- "use_alpha",
- "colorspace_is_data",
- *NODES_LIST,
- )
- def __new__(cls, owner_shader: ShaderWrapper, node_dst, socket_dst, *_args, **_kwargs):
- instance = owner_shader._textures.get((node_dst, socket_dst), None)
- if instance is not None:
- return instance
- instance = super(ShaderImageTextureWrapper, cls).__new__(cls)
- owner_shader._textures[(node_dst, socket_dst)] = instance
- return instance
- def __init__(self, owner_shader: ShaderWrapper, node_dst, socket_dst, grid_row_diff=0,
- use_alpha=False, colorspace_is_data=...):
- self.owner_shader = owner_shader
- self.is_readonly = owner_shader.is_readonly
- self.node_dst = node_dst
- self.socket_dst = socket_dst
- self.grid_row_diff = grid_row_diff
- self.use_alpha = use_alpha
- self.colorspace_is_data = colorspace_is_data
- self._node_image = ...
- self._node_mapping = ...
- # tree = node_dst.id_data
- # nodes = tree.nodes
- # links = tree.links
- if socket_dst.is_linked:
- from_node = socket_dst.links[0].from_node
- if from_node.bl_idname == 'ShaderNodeTexImage':
- self._node_image = from_node
- if self.node_image is not None:
- socket_dst = self.node_image.inputs["Vector"]
- if socket_dst.is_linked:
- from_node = socket_dst.links[0].from_node
- if from_node.bl_idname == 'ShaderNodeMapping':
- self._node_mapping = from_node
- def copy_from(self, tex):
- # Avoid generating any node in source texture.
- is_readonly_back = tex.is_readonly
- tex.is_readonly = True
- if tex.node_image is not None:
- self.image = tex.image
- self.projection = tex.projection
- self.texcoords = tex.texcoords
- self.copy_mapping_from(tex)
- tex.is_readonly = is_readonly_back
- def copy_mapping_from(self, tex):
- # Avoid generating any node in source texture.
- is_readonly_back = tex.is_readonly
- tex.is_readonly = True
- if tex.node_mapping is None: # Used to actually remove mapping node.
- if self.has_mapping_node():
- # We assume node_image can never be None in that case...
- # Find potential existing link into image's Vector input.
- socket_dst = socket_src = None
- if self.node_mapping.inputs["Vector"].is_linked:
- socket_dst = self.node_image.inputs["Vector"]
- socket_src = self.node_mapping.inputs["Vector"].links[0].from_socket
- tree = self.owner_shader.material.node_tree
- tree.nodes.remove(self.node_mapping)
- self._node_mapping = None
- # If previously existing, re-link texcoords -> image
- if socket_src is not None:
- tree.links.new(socket_src, socket_dst)
- elif self.node_mapping is not None:
- self.translation = tex.translation
- self.rotation = tex.rotation
- self.scale = tex.scale
- self.use_min = tex.use_min
- self.use_max = tex.use_max
- self.min = tex.min
- self.max = tex.max
- tex.is_readonly = is_readonly_back
- # --------------------------------------------------------------------
- # Image.
- def node_image_get(self):
- if self._node_image is ...:
- # Running only once, trying to find a valid image node.
- if self.socket_dst.is_linked:
- node_image = self.socket_dst.links[0].from_node
- if node_image.bl_idname == 'ShaderNodeTexImage':
- self._node_image = node_image
- self.owner_shader._grid_to_location(0, 0, ref_node=node_image)
- if self._node_image is ...:
- self._node_image = None
- if self._node_image is None and not self.is_readonly:
- tree = self.owner_shader.material.node_tree
- node_image = tree.nodes.new(type='ShaderNodeTexImage')
- self.owner_shader._grid_to_location(-1, 0 + self.grid_row_diff, dst_node=node_image, ref_node=self.node_dst)
- tree.links.new(node_image.outputs["Alpha" if self.use_alpha else "Color"], self.socket_dst)
- self._node_image = node_image
- return self._node_image
- node_image = property(node_image_get)
- def image_get(self):
- return self.node_image.image if self.node_image is not None else None
- @_set_check
- def image_set(self, image):
- if self.colorspace_is_data is not ...:
- image.colorspace_settings.is_data = self.colorspace_is_data
- self.node_image.image = image
- image = property(image_get, image_set)
- def projection_get(self):
- return self.node_image.projection if self.node_image is not None else 'FLAT'
- @_set_check
- def projection_set(self, projection):
- self.node_image.projection = projection
- projection = property(projection_get, projection_set)
- def texcoords_get(self):
- if self.node_image is not None:
- socket = (self.node_mapping if self.has_mapping_node() else self.node_image).inputs["Vector"]
- if socket.is_linked:
- return socket.links[0].from_socket.name
- return 'UV'
- @_set_check
- def texcoords_set(self, texcoords):
- # Image texture node already defaults to UVs, no extra node needed.
- # ONLY in case we do not have any texcoords mapping!!!
- if texcoords == 'UV' and not self.has_mapping_node():
- return
- tree = self.node_image.id_data
- links = tree.links
- node_dst = self.node_mapping if self.has_mapping_node() else self.node_image
- socket_src = self.owner_shader.node_texcoords.outputs[texcoords]
- links.new(socket_src, node_dst.inputs["Vector"])
- texcoords = property(texcoords_get, texcoords_set)
- def extension_get(self):
- return self.node_image.extension if self.node_image is not None else 'REPEAT'
- @_set_check
- def extension_set(self, extension):
- self.node_image.extension = extension
- extension = property(extension_get, extension_set)
- # --------------------------------------------------------------------
- # Mapping.
- def has_mapping_node(self):
- return self._node_mapping not in {None, ...}
- def node_mapping_get(self):
- if self._node_mapping is ...:
- # Running only once, trying to find a valid mapping node.
- if self.node_image is None:
- return None
- if self.node_image.inputs["Vector"].is_linked:
- node_mapping = self.node_image.inputs["Vector"].links[0].from_node
- if node_mapping.bl_idname == 'ShaderNodeMapping':
- self._node_mapping = node_mapping
- self.owner_shader._grid_to_location(0, 0 + self.grid_row_diff, ref_node=node_mapping)
- if self._node_mapping is ...:
- self._node_mapping = None
- if self._node_mapping is None and not self.is_readonly:
- # Find potential existing link into image's Vector input.
- socket_dst = self.node_image.inputs["Vector"]
- # If not already existing, we need to create texcoords -> mapping link (from UV).
- socket_src = (socket_dst.links[0].from_socket if socket_dst.is_linked
- else self.owner_shader.node_texcoords.outputs['UV'])
- tree = self.owner_shader.material.node_tree
- node_mapping = tree.nodes.new(type='ShaderNodeMapping')
- node_mapping.vector_type = 'TEXTURE'
- self.owner_shader._grid_to_location(-1, 0, dst_node=node_mapping, ref_node=self.node_image)
- # Link mapping -> image node.
- tree.links.new(node_mapping.outputs["Vector"], socket_dst)
- # Link texcoords -> mapping.
- tree.links.new(socket_src, node_mapping.inputs["Vector"])
- self._node_mapping = node_mapping
- return self._node_mapping
- node_mapping = property(node_mapping_get)
- def translation_get(self):
- return self.node_mapping.translation if self.node_mapping is not None else Vector((0.0, 0.0, 0.0))
- @_set_check
- def translation_set(self, translation):
- self.node_mapping.translation = translation
- translation = property(translation_get, translation_set)
- def rotation_get(self):
- return self.node_mapping.rotation if self.node_mapping is not None else Vector((0.0, 0.0, 0.0))
- @_set_check
- def rotation_set(self, rotation):
- self.node_mapping.rotation = rotation
- rotation = property(rotation_get, rotation_set)
- def scale_get(self):
- return self.node_mapping.scale if self.node_mapping is not None else Vector((1.0, 1.0, 1.0))
- @_set_check
- def scale_set(self, scale):
- self.node_mapping.scale = scale
- scale = property(scale_get, scale_set)
- def use_min_get(self):
- return self.node_mapping.use_min if self.node_mapping is not None else False
- @_set_check
- def use_min_set(self, use_min):
- self.node_mapping.use_min = use_min
- use_min = property(use_min_get, use_min_set)
- def use_max_get(self):
- return self.node_mapping.use_max if self.node_mapping is not None else False
- @_set_check
- def use_max_set(self, use_max):
- self.node_mapping.use_max = use_max
- use_max = property(use_max_get, use_max_set)
- def min_get(self):
- return self.node_mapping.min if self.node_mapping is not None else Vector((0.0, 0.0, 0.0))
- @_set_check
- def min_set(self, min):
- self.node_mapping.min = min
- min = property(min_get, min_set)
- def max_get(self):
- return self.node_mapping.max if self.node_mapping is not None else Vector((0.0, 0.0, 0.0))
- @_set_check
- def max_set(self, max):
- self.node_mapping.max = max
- max = property(max_get, max_set)
|