From 53f601943472b520bf484d755b82d01661e0d9d6 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 4 Sep 2013 10:23:51 +0000 Subject: fbx/cycles support for mapping node. --- io_scene_fbx/cycles_shader_compat.py | 118 ++++++++++++++++++++++++++++++----- io_scene_fbx/import_fbx.py | 53 +++++++++++++++- 2 files changed, 151 insertions(+), 20 deletions(-) (limited to 'io_scene_fbx') diff --git a/io_scene_fbx/cycles_shader_compat.py b/io_scene_fbx/cycles_shader_compat.py index 2f1b9fb2..7fb06467 100644 --- a/io_scene_fbx/cycles_shader_compat.py +++ b/io_scene_fbx/cycles_shader_compat.py @@ -52,6 +52,7 @@ class CyclesShaderWrapper(): "node_mix_color_bump", "node_normalmap", + "node_texcoords", "node_image_alpha", "node_image_diff", @@ -276,6 +277,15 @@ class CyclesShaderWrapper(): links.new(self.node_mix_color_bump.outputs["Color"], self.node_out.inputs["Displacement"]) + # -------------------------------------------------------------------- + # Tex Coords + node = nodes.new(type='ShaderNodeTexCoord') + node.label = "Texture Coords" + node.location = self._grid_location(-3, 3) + self.node_texcoords = node + del node + # no links, only use when needed! + @staticmethod def _image_create_helper(image, node_dst, sockets_dst, use_alpha=False): tree = node_dst.id_data @@ -291,6 +301,41 @@ class CyclesShaderWrapper(): socket) return node + @staticmethod + def _mapping_create_helper(node_dst, socket_src, + translation, rotation, scale): + tree = node_dst.id_data + nodes = tree.nodes + links = tree.links + + # in most cases: + # (socket_src == self.node_texcoords.outputs['UV']) + + node_map = nodes.new(type='ShaderNodeMapping') + node_map.location = node_dst.location + node_map.location.x -= CyclesShaderWrapper._col_size + + node_map.width = 160.0 + + if translation is not None: + node_map.translation = translation + if scale is not None: + node_map.scale = scale + if rotation is not None: + node_map.rotation = rotation + + # link mapping -> image node + links.new(node_map.outputs["Vector"], + node_dst.inputs["Vector"]) + + # link coord -> mapping + links.new(socket_src, + node_map.inputs["Vector"]) + return node_map + + # note, all ***_mapping_set() functions currenly work the same way + # (only with different image arg), could generalize. + @staticmethod def _grid_location(x, y): return (x * CyclesShaderWrapper._col_size, @@ -301,8 +346,13 @@ class CyclesShaderWrapper(): def diffuse_image_set(self, image): node = self.node_mix_color_diff - (self.node_image_diff = - self._image_create_helper(image, node, (node.inputs["Color2"],))) + self.node_image_diff = ( + self._image_create_helper(image, node, (node.inputs["Color2"],))) + + def diffuse_mapping_set(self, coords='UV', + translation=None, rotation=None, scale=None): + return self._mapping_create_helper( + self.node_image_diff, self.node_texcoords.outputs[coords], translation, rotation, scale) def specular_color_set(self, color): self.node_bsdf_spec.mute = max(color) <= 0.0 @@ -310,8 +360,13 @@ class CyclesShaderWrapper(): def specular_image_set(self, image): node = self.node_mix_color_spec - (self.node_image_spec = - self._image_create_helper(image, node, (node.inputs["Color2"],))) + self.node_image_spec = ( + self._image_create_helper(image, node, (node.inputs["Color2"],))) + + def specular_mapping_set(self, coords='UV', + translation=None, rotation=None, scale=None): + return self._mapping_create_helper( + self.node_image_spec, self.node_texcoords.outputs[coords], translation, rotation, scale) def hardness_value_set(self, value): node = self.node_mix_color_hard @@ -319,8 +374,13 @@ class CyclesShaderWrapper(): def hardness_image_set(self, image): node = self.node_mix_color_hard - (self.node_image_hard = - self._image_create_helper(image, node, (node.inputs["Color2"],))) + self.node_image_hard = ( + self._image_create_helper(image, node, (node.inputs["Color2"],))) + + def hardness_mapping_set(self, coords='UV', + translation=None, rotation=None, scale=None): + return self._mapping_create_helper( + self.node_image_hard, self.node_texcoords.outputs[coords], translation, rotation, scale) def reflect_color_set(self, color): node = self.node_mix_color_refl @@ -335,8 +395,13 @@ class CyclesShaderWrapper(): def reflect_image_set(self, image): self.node_bsdf_refl.mute = False node = self.node_mix_color_refl - (self.node_image_refl = - self._image_create_helper(image, node, (node.inputs["Color2"],))) + self.node_image_refl = ( + self._image_create_helper(image, node, (node.inputs["Color2"],))) + + def reflect_mapping_set(self, coords='UV', + translation=None, rotation=None, scale=None): + return self._mapping_create_helper( + self.node_image_refl, self.node_texcoords.outputs[coords], translation, rotation, scale) def alpha_value_set(self, value): self.node_bsdf_alpha.mute &= (value >= 1.0) @@ -349,8 +414,13 @@ class CyclesShaderWrapper(): # note: use_alpha may need to be configurable # its not always the case that alpha channels use the image alpha # a greyscale image may also be used. - (self.node_image_alpha = - self._image_create_helper(image, node, (node.inputs["Color2"],), use_alpha=True)) + self.node_image_alpha = ( + self._image_create_helper(image, node, (node.inputs["Color2"],), use_alpha=True)) + + def alpha_mapping_set(self, coords='UV', + translation=None, rotation=None, scale=None): + return self._mapping_create_helper( + self.node_image_alpha, self.node_texcoords.outputs[coords], translation, rotation, scale) def alpha_image_set_from_diffuse(self): # XXX, remove? @@ -358,10 +428,14 @@ class CyclesShaderWrapper(): links = tree.links self.node_bsdf_alpha.mute = False - node_image = self.node_mix_color_diff.inputs["Color2"].links[0].from_node + node_image = self.node_image_diff node = self.node_mix_color_alpha - links.new(node_image.outputs["Alpha"], - node.inputs["Color2"]) + if 1: + links.new(node_image.outputs["Alpha"], + node.inputs["Color2"]) + else: + self.alpha_image_set(node_image.image) + self.node_image_alpha.label = "Image Texture_ALPHA" def normal_factor_set(self, value): node = self.node_normalmap @@ -370,10 +444,15 @@ class CyclesShaderWrapper(): def normal_image_set(self, image): self.node_normalmap.mute = False node = self.node_normalmap - (self.node_image_normalmap = - self._image_create_helper(image, node, (node.inputs["Color"],))) + self.node_image_normalmap = ( + self._image_create_helper(image, node, (node.inputs["Color"],))) self.node_image_normalmap.color_space = 'NONE' + def normal_mapping_set(self, coords='UV', + translation=None, rotation=None, scale=None): + return self._mapping_create_helper( + self.node_image_normalmap, self.node_texcoords.outputs[coords], translation, rotation, scale) + def bump_factor_set(self, value): node = self.node_mix_color_bump node.mute = (value <= 0.0) @@ -381,5 +460,10 @@ class CyclesShaderWrapper(): def bump_image_set(self, image): node = self.node_mix_color_bump - (self.node_image_bump = - self._image_create_helper(image, node, (node.inputs["Color2"],))) + self.node_image_bump = ( + self._image_create_helper(image, node, (node.inputs["Color2"],))) + + def bump_mapping_set(self, coords='UV', + translation=None, rotation=None, scale=None): + return self._mapping_create_helper( + self.node_image_bump, self.node_texcoords.outputs[coords], translation, rotation, scale) diff --git a/io_scene_fbx/import_fbx.py b/io_scene_fbx/import_fbx.py index 29f7acee..b386e47a 100644 --- a/io_scene_fbx/import_fbx.py +++ b/io_scene_fbx/import_fbx.py @@ -708,6 +708,7 @@ def blen_read_material(fbx_tmpl, fbx_obj, ma_wrap = cycles_shader_compat.CyclesShaderWrapper(ma) ma_wrap.diffuse_color_set(ma_diff) ma_wrap.specular_color_set([c * ma_spec_intensity for c in ma_spec]) + ma_wrap.hardness_value_set(((ma_spec_hardness + 3.0) / 5.0) - 0.65) ma_wrap.alpha_value_set(ma_alpha) ma_wrap.reflect_factor_set(ma_refl_factor) ma_wrap.reflect_color_set(ma_refl_color) @@ -1134,10 +1135,23 @@ def load(operator, context, filepath="", # textures that use this material def texture_bumpfac_get(fbx_obj): + assert(fbx_obj.id == b'Material') fbx_props = (elem_find_first(fbx_obj, b'Properties70'), elem_find_first(fbx_tmpl, b'Properties70', fbx_elem_nil)) assert(fbx_props[0] is not None) - return elem_props_get_number(fbx_props, b'BumpFactor', 1.0) + # (x / 7.142) is only a guess, cycles usable range is (0.0 -> 0.5) + return elem_props_get_number(fbx_props, b'BumpFactor', 2.5) / 7.142 + + def texture_mapping_get(fbx_obj): + assert(fbx_obj.id == b'Texture') + + fbx_props = (elem_find_first(fbx_obj, b'Properties70'), + elem_find_first(fbx_tmpl, b'Properties70', fbx_elem_nil)) + assert(fbx_props[0] is not None) + return (elem_props_get_vector_3d(fbx_props, b'Translation', (0.0, 0.0, 0.0)), + elem_props_get_vector_3d(fbx_props, b'Rotation', (0.0, 0.0, 0.0)), + elem_props_get_vector_3d(fbx_props, b'Scaling', (1.0, 1.0, 1.0)), + ) if not use_cycles: # Simple function to make a new mtex and set defaults @@ -1170,26 +1184,57 @@ def load(operator, context, filepath="", ma_wrap = cycles_material_wrap_map[material] + # tx/rot/scale + tex_map = texture_mapping_get(fbx_lnk) + if (tex_map[0] == (0.0, 0.0, 0.0) and + tex_map[1] == (0.0, 0.0, 0.0) and + tex_map[2] == (1.0, 1.0, 1.0)): + + use_mapping = False + else: + use_mapping = True + tex_map_kw = { + "translation": tex_map[0], + "rotation": tex_map[1], + "scale": tex_map[2], + } + if lnk_type == b'DiffuseColor': ma_wrap.diffuse_image_set(image) + if use_mapping: + ma_wrap.diffuse_mapping_set(**tex_map_kw) elif lnk_type == b'SpecularColor': ma_wrap.specular_image_set(image) + if use_mapping: + ma_wrap.specular_mapping_set(**tex_map_kw) elif lnk_type == b'ReflectionColor': ma_wrap.reflect_image_set(image) + if use_mapping: + ma_wrap.reflect_mapping_set(**tex_map_kw) elif lnk_type == b'TransparentColor': # alpha ma_wrap.alpha_image_set(image) + if use_mapping: + ma_wrap.alpha_mapping_set(**tex_map_kw) if use_alpha_decals: material_decals.add(material) elif lnk_type == b'DiffuseFactor': pass # TODO elif lnk_type == b'ShininessExponent': ma_wrap.hardness_image_set(image) - elif lnk_type == b'NormalMap': + if use_mapping: + ma_wrap.hardness_mapping_set(**tex_map_kw) + elif lnk_type == b'NormalMap' or lnk_type == b'Bump': # XXX, applications abuse bump! ma_wrap.normal_image_set(image) ma_wrap.normal_factor_set(texture_bumpfac_get(fbx_obj)) + if use_mapping: + ma_wrap.normal_mapping_set(**tex_map_kw) + """ elif lnk_type == b'Bump': ma_wrap.bump_image_set(image) ma_wrap.bump_factor_set(texture_bumpfac_get(fbx_obj)) + if use_mapping: + ma_wrap.bump_mapping_set(**tex_map_kw) + """ else: print("WARNING: material link %r ignored" % lnk_type) @@ -1220,13 +1265,15 @@ def load(operator, context, filepath="", mtex.use_map_diffuse = True elif lnk_type == b'ShininessExponent': mtex.use_map_hardness = True - elif lnk_type == b'NormalMap': + elif lnk_type == b'NormalMap' or lnk_type == b'Bump': # XXX, applications abuse bump! mtex.texture.use_normal_map = True # not ideal! mtex.use_map_normal = True mtex.normal_factor = texture_bumpfac_get(fbx_obj) + """ elif lnk_type == b'Bump': mtex.use_map_normal = True mtex.normal_factor = texture_bumpfac_get(fbx_obj) + """ else: print("WARNING: material link %r ignored" % lnk_type) -- cgit v1.2.3