FBX IO: Speed up parsing by multithreading array decompression #104739
@ -5,8 +5,8 @@
|
||||
bl_info = {
|
||||
"name": "3D-Coat Applink",
|
||||
"author": "Kalle-Samuli Riihikoski (haikalle)",
|
||||
"version": (4, 9, 34),
|
||||
"blender": (2, 80, 0),
|
||||
"version": (4, 9, 35),
|
||||
"blender": (4, 1, 0),
|
||||
"location": "Scene > 3D-Coat Applink",
|
||||
"description": "Transfer data between 3D-Coat/Blender",
|
||||
"warning": "",
|
||||
|
@ -521,7 +521,7 @@ def CreateTextureLine(type, act_material, main_mat, texcoat, coat3D, notegroup,
|
||||
|
||||
main_material.links.new(applink_tree.outputs[5], disp_node.inputs[0])
|
||||
main_material.links.new(disp_node.outputs[0], out_mat.inputs[2])
|
||||
coatMat.cycles.displacement_method = 'BOTH'
|
||||
coatMat.displacement_method = 'BOTH'
|
||||
|
||||
else:
|
||||
if (texcoat['alpha'] != []):
|
||||
|
@ -659,7 +659,7 @@ def CreateTextureLine(type, act_material, main_mat, texcoat, coat3D, notegroup,
|
||||
|
||||
main_material.links.new(applink_tree.outputs[5], disp_node.inputs[0])
|
||||
main_material.links.new(disp_node.outputs[0], out_mat.inputs[2])
|
||||
coatMat.cycles.displacement_method = 'BOTH'
|
||||
coatMat.displacement_method = 'BOTH'
|
||||
|
||||
else:
|
||||
if (texcoat['alpha'] != []):
|
||||
|
@ -286,7 +286,7 @@ class MAX3DS_PT_export_include(bpy.types.Panel):
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = True
|
||||
layout.use_property_decorate = False
|
||||
|
||||
sfile = context.space_data
|
||||
operator = sfile.active_operator
|
||||
@ -367,4 +367,4 @@ def unregister():
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
register()
|
@ -5,7 +5,7 @@
|
||||
bl_info = {
|
||||
"name": "FBX format",
|
||||
"author": "Campbell Barton, Bastien Montagne, Jens Restemeier, @Mysteryem",
|
||||
"version": (5, 11, 0),
|
||||
"version": (5, 11, 2),
|
||||
"blender": (4, 1, 0),
|
||||
"location": "File > Import-Export",
|
||||
"description": "FBX IO meshes, UVs, vertex colors, materials, textures, cameras, lamps and actions",
|
||||
|
@ -1638,7 +1638,7 @@ def blen_read_geom_layer_smooth(fbx_obj, mesh):
|
||||
fbx_layer = elem_find_first(fbx_obj, b'LayerElementSmoothing')
|
||||
|
||||
if fbx_layer is None:
|
||||
return False
|
||||
return
|
||||
|
||||
# all should be valid
|
||||
(fbx_layer_name,
|
||||
@ -1651,13 +1651,13 @@ def blen_read_geom_layer_smooth(fbx_obj, mesh):
|
||||
|
||||
# udk has 'Direct' mapped, with no Smoothing, not sure why, but ignore these
|
||||
if fbx_layer_data is None:
|
||||
return False
|
||||
return
|
||||
|
||||
if fbx_layer_mapping == b'ByEdge':
|
||||
# some models have bad edge data, we can't use this info...
|
||||
if not mesh.edges:
|
||||
print("warning skipping sharp edges data, no valid edges...")
|
||||
return False
|
||||
return
|
||||
|
||||
blen_data = MESH_ATTRIBUTE_SHARP_EDGE.ensure(mesh.attributes).data
|
||||
fbx_item_size = 1
|
||||
@ -1669,21 +1669,23 @@ def blen_read_geom_layer_smooth(fbx_obj, mesh):
|
||||
1, fbx_item_size, layer_id,
|
||||
xform=np.logical_not, # in FBX, 0 (False) is sharp, but in Blender True is sharp.
|
||||
)
|
||||
return False
|
||||
elif fbx_layer_mapping == b'ByPolygon':
|
||||
blen_data = MESH_ATTRIBUTE_SHARP_FACE.ensure(mesh.attributes).data
|
||||
sharp_face = MESH_ATTRIBUTE_SHARP_FACE.ensure(mesh.attributes)
|
||||
blen_data = sharp_face.data
|
||||
fbx_item_size = 1
|
||||
assert(fbx_item_size == MESH_ATTRIBUTE_SHARP_FACE.item_size)
|
||||
return blen_read_geom_array_mapped_polygon(
|
||||
sharp_face_set_successfully = blen_read_geom_array_mapped_polygon(
|
||||
mesh, blen_data, MESH_ATTRIBUTE_SHARP_FACE.foreach_attribute, MESH_ATTRIBUTE_SHARP_FACE.dtype,
|
||||
fbx_layer_data, None,
|
||||
fbx_layer_mapping, fbx_layer_ref,
|
||||
1, fbx_item_size, layer_id,
|
||||
xform=lambda s: (s == 0), # smoothgroup bitflags, treat as booleans for now
|
||||
)
|
||||
if not sharp_face_set_successfully:
|
||||
mesh.attributes.remove(sharp_face)
|
||||
else:
|
||||
print("warning layer %r mapping type unsupported: %r" % (fbx_layer.id, fbx_layer_mapping))
|
||||
return False
|
||||
|
||||
|
||||
def blen_read_geom_layer_edge_crease(fbx_obj, mesh):
|
||||
fbx_layer = elem_find_first(fbx_obj, b'LayerElementEdgeCrease')
|
||||
@ -1883,7 +1885,7 @@ def blen_read_geom(fbx_tmpl, fbx_obj, settings):
|
||||
print("ERROR: No polygons, but edges exist. Ignoring the edges!")
|
||||
|
||||
# must be after edge, face loading.
|
||||
ok_smooth = blen_read_geom_layer_smooth(fbx_obj, mesh)
|
||||
blen_read_geom_layer_smooth(fbx_obj, mesh)
|
||||
|
||||
blen_read_geom_layer_edge_crease(fbx_obj, mesh)
|
||||
|
||||
@ -1905,23 +1907,12 @@ def blen_read_geom(fbx_tmpl, fbx_obj, settings):
|
||||
clnors = np.empty(len(mesh.loops) * 3, dtype=bl_nors_dtype)
|
||||
mesh.attributes["temp_custom_normals"].data.foreach_get("vector", clnors)
|
||||
|
||||
if not ok_smooth:
|
||||
sharp_face = MESH_ATTRIBUTE_SHARP_FACE.get(attributes)
|
||||
if sharp_face:
|
||||
attributes.remove(sharp_face)
|
||||
ok_smooth = True
|
||||
|
||||
# Iterating clnors into a nested tuple first is faster than passing clnors.reshape(-1, 3) directly into
|
||||
# normals_split_custom_set. We use clnors.data since it is a memoryview, which is faster to iterate than clnors.
|
||||
mesh.normals_split_custom_set(tuple(zip(*(iter(clnors.data),) * 3)))
|
||||
if settings.use_custom_normals:
|
||||
mesh.attributes.remove(mesh.attributes["temp_custom_normals"])
|
||||
|
||||
if not ok_smooth:
|
||||
sharp_face = MESH_ATTRIBUTE_SHARP_FACE.get(attributes)
|
||||
if sharp_face:
|
||||
attributes.remove(sharp_face)
|
||||
|
||||
if settings.use_custom_props:
|
||||
blen_read_custom_properties(fbx_obj, mesh, settings)
|
||||
|
||||
@ -2779,7 +2770,13 @@ class FbxImportHelperNode:
|
||||
pose_bone = arm.bl_obj.pose.bones[self.bl_bone]
|
||||
pose_bone.matrix_basis = self.get_bind_matrix().inverted_safe() @ self.get_matrix()
|
||||
|
||||
if settings.use_custom_props:
|
||||
# `self.fbx_elem` can be `None` in cases where the imported hierarchy contains a mix of bone and non-bone FBX
|
||||
# Nodes parented to one another, e.g. "bone1"->"mesh1"->"bone2". In Blender, an Armature can only consist of
|
||||
# bones, so to maintain the imported hierarchy, a placeholder bone with the same name as "mesh1" is inserted
|
||||
# into the Armature and then the imported "mesh1" Object is parented to the placeholder bone. The placeholder
|
||||
# bone won't have a `self.fbx_elem` because it belongs to the "mesh1" Object instead.
|
||||
# See FbxImportHelperNode.find_fake_bones().
|
||||
if settings.use_custom_props and self.fbx_elem:
|
||||
blen_read_custom_properties(self.fbx_elem, pose_bone, settings)
|
||||
|
||||
for child in self.children:
|
||||
|
@ -5,7 +5,7 @@
|
||||
bl_info = {
|
||||
'name': 'glTF 2.0 format',
|
||||
'author': 'Julien Duroure, Scurest, Norbert Nopper, Urs Hanselmann, Moritz Becher, Benjamin Schmithüsen, Jim Eckerlein, and many external contributors',
|
||||
"version": (4, 1, 36),
|
||||
"version": (4, 1, 38),
|
||||
'blender': (4, 1, 0),
|
||||
'location': 'File > Import-Export',
|
||||
'description': 'Import-Export as glTF 2.0',
|
||||
|
@ -96,6 +96,7 @@ def __gather_gltf(exporter, export_settings):
|
||||
exporter.add_scene(scene, idx==active_scene_idx, export_settings=export_settings)
|
||||
for animation in animations:
|
||||
exporter.add_animation(animation)
|
||||
exporter.manage_gpu_instancing_nodes(export_settings)
|
||||
exporter.traverse_unused_skins(unused_skins)
|
||||
exporter.traverse_additional_textures()
|
||||
exporter.traverse_additional_images()
|
||||
|
@ -276,57 +276,44 @@ class GlTF2Exporter:
|
||||
|
||||
self.nodes_idx_to_remove.extend(insts)
|
||||
|
||||
def add_scene(self, scene: gltf2_io.Scene, active: bool = False, export_settings=None):
|
||||
"""
|
||||
Add a scene to the glTF.
|
||||
|
||||
The scene should be built up with the generated glTF classes
|
||||
:param scene: gltf2_io.Scene type. Root node of the scene graph
|
||||
:param active: If true, sets the glTD.scene index to the added scene
|
||||
:return: nothing
|
||||
"""
|
||||
if self.__finalized:
|
||||
raise RuntimeError("Tried to add scene to finalized glTF file")
|
||||
|
||||
scene_num = self.__traverse(scene)
|
||||
if active:
|
||||
self.__gltf.scene = scene_num
|
||||
|
||||
def manage_gpu_instancing_nodes(self, export_settings):
|
||||
if export_settings['gltf_gpu_instances'] is True:
|
||||
# Modify the scene data in case of EXT_mesh_gpu_instancing export
|
||||
for scene_num in range(len(self.__gltf.scenes)):
|
||||
# Modify the scene data in case of EXT_mesh_gpu_instancing export
|
||||
|
||||
self.nodes_idx_to_remove = []
|
||||
for node_idx in self.__gltf.scenes[scene_num].nodes:
|
||||
node = self.__gltf.nodes[node_idx]
|
||||
if node.mesh is None:
|
||||
self.manage_gpu_instancing(node)
|
||||
else:
|
||||
self.manage_gpu_instancing(node, also_mesh=True)
|
||||
for child_idx in node.children:
|
||||
child = self.__gltf.nodes[child_idx]
|
||||
self.manage_gpu_instancing(child, also_mesh=child.mesh is not None)
|
||||
self.nodes_idx_to_remove = []
|
||||
for node_idx in self.__gltf.scenes[scene_num].nodes:
|
||||
node = self.__gltf.nodes[node_idx]
|
||||
if node.mesh is None:
|
||||
self.manage_gpu_instancing(node)
|
||||
else:
|
||||
self.manage_gpu_instancing(node, also_mesh=True)
|
||||
for child_idx in node.children:
|
||||
child = self.__gltf.nodes[child_idx]
|
||||
self.manage_gpu_instancing(child, also_mesh=child.mesh is not None)
|
||||
|
||||
# Slides other nodes index
|
||||
# Slides other nodes index
|
||||
|
||||
self.nodes_idx_to_remove.sort()
|
||||
for node_idx in self.__gltf.scenes[scene_num].nodes:
|
||||
self.recursive_slide_node_idx(node_idx)
|
||||
self.nodes_idx_to_remove.sort()
|
||||
for node_idx in self.__gltf.scenes[scene_num].nodes:
|
||||
self.recursive_slide_node_idx(node_idx)
|
||||
|
||||
new_node_list = []
|
||||
for node_idx in self.__gltf.scenes[scene_num].nodes:
|
||||
len_ = len([i for i in self.nodes_idx_to_remove if i < node_idx])
|
||||
new_node_list.append(node_idx - len_)
|
||||
self.__gltf.scenes[scene_num].nodes = new_node_list
|
||||
|
||||
for skin in self.__gltf.skins:
|
||||
new_joint_list = []
|
||||
for node_idx in skin.joints:
|
||||
new_node_list = []
|
||||
for node_idx in self.__gltf.scenes[scene_num].nodes:
|
||||
len_ = len([i for i in self.nodes_idx_to_remove if i < node_idx])
|
||||
new_joint_list.append(node_idx - len_)
|
||||
skin.joints = new_joint_list
|
||||
if skin.skeleton is not None:
|
||||
len_ = len([i for i in self.nodes_idx_to_remove if i < skin.skeleton])
|
||||
skin.skeleton = skin.skeleton - len_
|
||||
new_node_list.append(node_idx - len_)
|
||||
self.__gltf.scenes[scene_num].nodes = new_node_list
|
||||
|
||||
for skin in self.__gltf.skins:
|
||||
new_joint_list = []
|
||||
for node_idx in skin.joints:
|
||||
len_ = len([i for i in self.nodes_idx_to_remove if i < node_idx])
|
||||
new_joint_list.append(node_idx - len_)
|
||||
skin.joints = new_joint_list
|
||||
if skin.skeleton is not None:
|
||||
len_ = len([i for i in self.nodes_idx_to_remove if i < skin.skeleton])
|
||||
skin.skeleton = skin.skeleton - len_
|
||||
|
||||
# Remove animation channels that was targeting a node that will be removed
|
||||
new_animation_list = []
|
||||
@ -345,6 +332,23 @@ class GlTF2Exporter:
|
||||
# And now really remove nodes
|
||||
self.__gltf.nodes = [node for idx, node in enumerate(self.__gltf.nodes) if idx not in self.nodes_idx_to_remove]
|
||||
|
||||
|
||||
def add_scene(self, scene: gltf2_io.Scene, active: bool = False, export_settings=None):
|
||||
"""
|
||||
Add a scene to the glTF.
|
||||
|
||||
The scene should be built up with the generated glTF classes
|
||||
:param scene: gltf2_io.Scene type. Root node of the scene graph
|
||||
:param active: If true, sets the glTD.scene index to the added scene
|
||||
:return: nothing
|
||||
"""
|
||||
if self.__finalized:
|
||||
raise RuntimeError("Tried to add scene to finalized glTF file")
|
||||
|
||||
scene_num = self.__traverse(scene)
|
||||
if active:
|
||||
self.__gltf.scene = scene_num
|
||||
|
||||
def recursive_slide_node_idx(self, node_idx):
|
||||
node = self.__gltf.nodes[node_idx]
|
||||
|
||||
|
@ -82,7 +82,6 @@ def export_anisotropy(blender_material, export_settings):
|
||||
anisotropy_texture, uvmap_info , udim_info, _ = gltf2_blender_gather_texture_info.gather_texture_info(
|
||||
anisotropy_data['tex_socket'],
|
||||
(anisotropy_data['tex_socket'],),
|
||||
(),
|
||||
export_settings,
|
||||
)
|
||||
anisotropy_extension['anisotropyTexture'] = anisotropy_texture
|
||||
@ -109,7 +108,6 @@ def export_anisotropy_from_grayscale_textures(blender_material, export_settings)
|
||||
anisotropyTexture, uvmap_info, _, _ = gltf2_blender_gather_texture_info.gather_texture_info(
|
||||
primary_socket,
|
||||
sockets,
|
||||
(),
|
||||
export_settings,
|
||||
filter_type='ANY')
|
||||
|
||||
|
@ -56,7 +56,6 @@ def export_clearcoat(blender_material, export_settings):
|
||||
clearcoat_texture, uvmap_info, udim_info, _ = gltf2_blender_gather_texture_info.gather_texture_info(
|
||||
clearcoat_socket,
|
||||
clearcoat_roughness_slots,
|
||||
(),
|
||||
export_settings,
|
||||
)
|
||||
clearcoat_extension['clearcoatTexture'] = clearcoat_texture
|
||||
@ -67,7 +66,6 @@ def export_clearcoat(blender_material, export_settings):
|
||||
clearcoat_roughness_texture, uvmap_info, udim_info, _ = gltf2_blender_gather_texture_info.gather_texture_info(
|
||||
clearcoat_roughness_socket,
|
||||
clearcoat_roughness_slots,
|
||||
(),
|
||||
export_settings,
|
||||
)
|
||||
clearcoat_extension['clearcoatRoughnessTexture'] = clearcoat_roughness_texture
|
||||
|
@ -58,7 +58,7 @@ def export_emission_texture(blender_material, export_settings):
|
||||
emissive = get_socket(blender_material, "Emissive")
|
||||
if emissive.socket is None:
|
||||
emissive = get_socket_from_gltf_material_node(blender_material, "Emissive")
|
||||
emissive_texture, uvmap_info, udim_info, _ = gltf2_blender_gather_texture_info.gather_texture_info(emissive, (emissive,), (), export_settings)
|
||||
emissive_texture, uvmap_info, udim_info, _ = gltf2_blender_gather_texture_info.gather_texture_info(emissive, (emissive,), export_settings)
|
||||
return emissive_texture, {'emissiveTexture': uvmap_info}, {'emissiveTexture': udim_info} if len(udim_info.keys()) > 0 else {}
|
||||
|
||||
def export_emission_strength_extension(emissive_factor, export_settings):
|
||||
|
@ -50,7 +50,6 @@ def export_sheen(blender_material, export_settings):
|
||||
original_sheenColor_texture, uvmap_info, udim_info, _ = gltf2_blender_gather_texture_info.gather_texture_info(
|
||||
sheenTint_socket,
|
||||
(sheenTint_socket,),
|
||||
(),
|
||||
export_settings,
|
||||
)
|
||||
sheen_extension['sheenColorTexture'] = original_sheenColor_texture
|
||||
@ -74,7 +73,6 @@ def export_sheen(blender_material, export_settings):
|
||||
original_sheenRoughness_texture, uvmap_info , udim_info, _ = gltf2_blender_gather_texture_info.gather_texture_info(
|
||||
sheenRoughness_socket,
|
||||
(sheenRoughness_socket,),
|
||||
(),
|
||||
export_settings,
|
||||
)
|
||||
sheen_extension['sheenRoughnessTexture'] = original_sheenRoughness_texture
|
||||
|
@ -56,7 +56,6 @@ def export_specular(blender_material, export_settings):
|
||||
specular_texture, uvmap_info, udim_info, _ = gather_texture_info(
|
||||
specular_socket,
|
||||
(specular_socket,),
|
||||
(),
|
||||
export_settings,
|
||||
)
|
||||
specular_extension['specularTexture'] = specular_texture
|
||||
@ -88,7 +87,6 @@ def export_specular(blender_material, export_settings):
|
||||
specularcolor_texture, uvmap_info, udim_info, _ = gather_texture_info(
|
||||
speculartint_socket,
|
||||
(speculartint_socket,),
|
||||
(),
|
||||
export_settings,
|
||||
)
|
||||
specular_extension['specularColorTexture'] = specularcolor_texture
|
||||
|
@ -42,7 +42,6 @@ def export_transmission(blender_material, export_settings):
|
||||
combined_texture, uvmap_info, udim_info, _ = gltf2_blender_gather_texture_info.gather_texture_info(
|
||||
transmission_socket,
|
||||
transmission_slots,
|
||||
(),
|
||||
export_settings,
|
||||
)
|
||||
if has_transmission_texture:
|
||||
|
@ -71,7 +71,6 @@ def export_volume(blender_material, export_settings):
|
||||
combined_texture, uvmap_info, udim_info, _ = gltf2_blender_gather_texture_info.gather_texture_info(
|
||||
thickness_socket,
|
||||
thickness_slots,
|
||||
(),
|
||||
export_settings,
|
||||
)
|
||||
if has_thickness_texture:
|
||||
|
@ -18,13 +18,12 @@ from .gltf2_blender_search_node_tree import get_texture_node_from_socket, detect
|
||||
@cached
|
||||
def gather_image(
|
||||
blender_shader_sockets: typing.Tuple[bpy.types.NodeSocket],
|
||||
default_sockets: typing.Tuple[bpy.types.NodeSocket],
|
||||
use_tile: bool,
|
||||
export_settings):
|
||||
if not __filter_image(blender_shader_sockets, export_settings):
|
||||
return None, None, None, None
|
||||
|
||||
image_data, udim_image = __get_image_data(blender_shader_sockets, default_sockets, use_tile, export_settings)
|
||||
image_data, udim_image = __get_image_data(blender_shader_sockets, use_tile, export_settings)
|
||||
|
||||
if udim_image is not None:
|
||||
# We are in a UDIM case, so we return no image data
|
||||
@ -194,7 +193,7 @@ def __gather_uri(image_data, mime_type, name, export_settings):
|
||||
return None, None
|
||||
|
||||
|
||||
def __get_image_data(sockets, default_sockets, use_tile, export_settings) -> ExportImage:
|
||||
def __get_image_data(sockets, use_tile, export_settings) -> ExportImage:
|
||||
# For shared resources, such as images, we just store the portion of data that is needed in the glTF property
|
||||
# in a helper class. During generation of the glTF in the exporter these will then be combined to actual binary
|
||||
# resources.
|
||||
@ -236,22 +235,15 @@ def __get_image_data(sockets, default_sockets, use_tile, export_settings) -> Exp
|
||||
# We are not in complex node setup, so we can try to get the image data from grayscale textures
|
||||
return __get_image_data_grayscale_anisotropy(sockets, results, export_settings), None
|
||||
|
||||
return __get_image_data_mapping(sockets, default_sockets, results, use_tile, export_settings), None
|
||||
return __get_image_data_mapping(sockets, results, use_tile, export_settings), None
|
||||
|
||||
def __get_image_data_mapping(sockets, default_sockets, results, use_tile, export_settings) -> ExportImage:
|
||||
def __get_image_data_mapping(sockets, results, use_tile, export_settings) -> ExportImage:
|
||||
"""
|
||||
Simple mapping
|
||||
Will fit for most of exported textures : RoughnessMetallic, Basecolor, normal, ...
|
||||
"""
|
||||
composed_image = ExportImage()
|
||||
|
||||
default_metallic = None
|
||||
default_roughness = None
|
||||
if "Metallic" in [s.name for s in default_sockets]:
|
||||
default_metallic = [s for s in default_sockets if s.name == "Metallic"][0].default_value
|
||||
if "Roughness" in [s.name for s in default_sockets]:
|
||||
default_roughness = [s for s in default_sockets if s.name == "Roughness"][0].default_value
|
||||
|
||||
for result, socket in zip(results, sockets):
|
||||
# Assume that user know what he does, and that channels/images are already combined correctly for pbr
|
||||
# If not, we are going to keep only the first texture found
|
||||
@ -334,15 +326,9 @@ def __get_image_data_mapping(sockets, default_sockets, results, use_tile, export
|
||||
# Since metal/roughness are always used together, make sure
|
||||
# the other channel is filled.
|
||||
if socket.socket.name == 'Metallic' and not composed_image.is_filled(Channel.G):
|
||||
if default_roughness is not None:
|
||||
composed_image.fill_with(Channel.G, default_roughness)
|
||||
else:
|
||||
composed_image.fill_white(Channel.G)
|
||||
composed_image.fill_white(Channel.G)
|
||||
elif socket.socket.name == 'Roughness' and not composed_image.is_filled(Channel.B):
|
||||
if default_metallic is not None:
|
||||
composed_image.fill_with(Channel.B, default_metallic)
|
||||
else:
|
||||
composed_image.fill_white(Channel.B)
|
||||
composed_image.fill_white(Channel.B)
|
||||
else:
|
||||
# copy full image...eventually following sockets might overwrite things
|
||||
if use_tile is None:
|
||||
|
@ -68,13 +68,13 @@ def gather_material(blender_material, export_settings):
|
||||
export_user_extensions('gather_material_hook', export_settings, mat_unlit, blender_material)
|
||||
return mat_unlit, {"uv_info": uvmap_info, "vc_info": vc_info, "udim_info": udim_info}
|
||||
|
||||
orm_texture, default_sockets = __gather_orm_texture(blender_material, export_settings)
|
||||
orm_texture = __gather_orm_texture(blender_material, export_settings)
|
||||
|
||||
emissive_factor = __gather_emissive_factor(blender_material, export_settings)
|
||||
emissive_texture, uvmap_info_emissive, udim_info_emissive = __gather_emissive_texture(blender_material, export_settings)
|
||||
extensions, uvmap_info_extensions, udim_info_extensions = __gather_extensions(blender_material, emissive_factor, export_settings)
|
||||
normal_texture, uvmap_info_normal, udim_info_normal = __gather_normal_texture(blender_material, export_settings)
|
||||
occlusion_texture, uvmap_info_occlusion, udim_occlusion = __gather_occlusion_texture(blender_material, orm_texture, default_sockets, export_settings)
|
||||
occlusion_texture, uvmap_info_occlusion, udim_occlusion = __gather_occlusion_texture(blender_material, orm_texture, export_settings)
|
||||
pbr_metallic_roughness, uvmap_info_pbr_metallic_roughness, vc_info, udim_info_prb_mr = __gather_pbr_metallic_roughness(blender_material, orm_texture, export_settings)
|
||||
|
||||
if any([i>1.0 for i in emissive_factor or []]) is True:
|
||||
@ -113,7 +113,7 @@ def gather_material(blender_material, export_settings):
|
||||
continue
|
||||
|
||||
s = NodeSocket(node[0].outputs[0], node[1])
|
||||
tex, uv_info_additional, udim_info, _ = gltf2_blender_gather_texture_info.gather_texture_info(s, (s,), (), export_settings)
|
||||
tex, uv_info_additional, udim_info, _ = gltf2_blender_gather_texture_info.gather_texture_info(s, (s,), export_settings)
|
||||
if tex is not None:
|
||||
export_settings['exported_images'][node[0].image.name] = 1 # Fully used
|
||||
uvmap_infos.update({'additional' + str(cpt_additional): uv_info_additional})
|
||||
@ -302,7 +302,7 @@ def __gather_orm_texture(blender_material, export_settings):
|
||||
if occlusion.socket is None or not has_image_node_from_socket(occlusion, export_settings):
|
||||
occlusion = get_socket_from_gltf_material_node(blender_material, "Occlusion")
|
||||
if occlusion.socket is None or not has_image_node_from_socket(occlusion, export_settings):
|
||||
return None, None
|
||||
return None
|
||||
|
||||
metallic_socket = get_socket(blender_material, "Metallic")
|
||||
roughness_socket = get_socket(blender_material, "Roughness")
|
||||
@ -310,38 +310,34 @@ def __gather_orm_texture(blender_material, export_settings):
|
||||
hasMetal = metallic_socket.socket is not None and has_image_node_from_socket(metallic_socket, export_settings)
|
||||
hasRough = roughness_socket.socket is not None and has_image_node_from_socket(roughness_socket, export_settings)
|
||||
|
||||
default_sockets = ()
|
||||
# Warning: for default socket, do not use NodeSocket object, because it will break cache
|
||||
# Using directlty the Blender socket object
|
||||
if not hasMetal and not hasRough:
|
||||
metallic_roughness = get_socket_from_gltf_material_node(blender_material, "MetallicRoughness")
|
||||
if metallic_roughness.socket is None or not has_image_node_from_socket(metallic_roughness, export_settings):
|
||||
return None, default_sockets
|
||||
return None
|
||||
result = (occlusion, metallic_roughness)
|
||||
elif not hasMetal:
|
||||
result = (occlusion, roughness_socket)
|
||||
default_sockets = (metallic_socket.socket,)
|
||||
elif not hasRough:
|
||||
result = (occlusion, metallic_socket)
|
||||
default_sockets = (roughness_socket.socket,)
|
||||
else:
|
||||
result = (occlusion, roughness_socket, metallic_socket)
|
||||
default_sockets = ()
|
||||
|
||||
if not gltf2_blender_gather_texture_info.check_same_size_images(result, export_settings):
|
||||
print_console("INFO",
|
||||
"Occlusion and metal-roughness texture will be exported separately "
|
||||
"(use same-sized images if you want them combined)")
|
||||
return None, ()
|
||||
return None
|
||||
|
||||
# Double-check this will past the filter in texture_info
|
||||
info, _, _, _ = gltf2_blender_gather_texture_info.gather_texture_info(result[0], result, default_sockets, export_settings)
|
||||
info, _, _, _ = gltf2_blender_gather_texture_info.gather_texture_info(result[0], result, export_settings)
|
||||
if info is None:
|
||||
return None, ()
|
||||
return None
|
||||
|
||||
return result, default_sockets
|
||||
return result
|
||||
|
||||
def __gather_occlusion_texture(blender_material, orm_texture, default_sockets, export_settings):
|
||||
def __gather_occlusion_texture(blender_material, orm_texture, export_settings):
|
||||
occlusion = get_socket(blender_material, "Occlusion")
|
||||
if occlusion.socket is None:
|
||||
occlusion = get_socket_from_gltf_material_node(blender_material, "Occlusion")
|
||||
@ -350,7 +346,6 @@ def __gather_occlusion_texture(blender_material, orm_texture, default_sockets, e
|
||||
occlusion_texture, uvmap_info, udim_info, _ = gltf2_blender_gather_texture_info.gather_material_occlusion_texture_info_class(
|
||||
occlusion,
|
||||
orm_texture or (occlusion,),
|
||||
default_sockets,
|
||||
export_settings)
|
||||
return occlusion_texture, \
|
||||
{"occlusionTexture" : uvmap_info}, {'occlusionTexture': udim_info } if len(udim_info.keys()) > 0 else {}
|
||||
|
@ -108,7 +108,7 @@ def __gather_base_color_texture(blender_material, export_settings):
|
||||
if not inputs:
|
||||
return None, {}, {}, None
|
||||
|
||||
tex, uvmap_info, udim_info, factor = gather_texture_info(inputs[0], inputs, (), export_settings)
|
||||
tex, uvmap_info, udim_info, factor = gather_texture_info(inputs[0], inputs, export_settings)
|
||||
return tex, {'baseColorTexture': uvmap_info}, {'baseColorTexture': udim_info} if len(udim_info.keys()) > 0 else {}, factor
|
||||
|
||||
|
||||
@ -140,7 +140,6 @@ def __gather_metallic_roughness_texture(blender_material, orm_texture, export_se
|
||||
hasMetal = metallic_socket.socket is not None and has_image_node_from_socket(metallic_socket, export_settings)
|
||||
hasRough = roughness_socket.socket is not None and has_image_node_from_socket(roughness_socket, export_settings)
|
||||
|
||||
default_sockets = ()
|
||||
# Warning: for default socket, do not use NodeSocket object, because it will break cache
|
||||
# Using directlty the Blender socket object
|
||||
if not hasMetal and not hasRough:
|
||||
@ -149,18 +148,14 @@ def __gather_metallic_roughness_texture(blender_material, orm_texture, export_se
|
||||
return None, {}, {}, None
|
||||
elif not hasMetal:
|
||||
texture_input = (roughness_socket,)
|
||||
default_sockets = (metallic_socket.socket,)
|
||||
elif not hasRough:
|
||||
texture_input = (metallic_socket,)
|
||||
default_sockets = (roughness_socket.socket,)
|
||||
else:
|
||||
texture_input = (metallic_socket, roughness_socket)
|
||||
default_sockets = ()
|
||||
|
||||
tex, uvmap_info, udim_info, factor = gather_texture_info(
|
||||
texture_input[0],
|
||||
orm_texture or texture_input,
|
||||
default_sockets,
|
||||
export_settings,
|
||||
)
|
||||
|
||||
|
@ -138,7 +138,6 @@ def gather_base_color_texture(info, export_settings):
|
||||
unlit_texture, uvmap_info, udim_info, _ = gltf2_blender_gather_texture_info.gather_texture_info(
|
||||
sockets[0],
|
||||
sockets,
|
||||
(),
|
||||
export_settings,
|
||||
)
|
||||
|
||||
|
@ -20,7 +20,6 @@ from . import gltf2_blender_gather_image
|
||||
@cached
|
||||
def gather_texture(
|
||||
blender_shader_sockets: typing.Tuple[bpy.types.NodeSocket],
|
||||
default_sockets,
|
||||
use_tile: bool,
|
||||
export_settings):
|
||||
"""
|
||||
@ -34,7 +33,7 @@ def gather_texture(
|
||||
if not __filter_texture(blender_shader_sockets, export_settings):
|
||||
return None, None, False
|
||||
|
||||
source, webp_image, image_data, factor, udim_image = __gather_source(blender_shader_sockets, default_sockets, use_tile, export_settings)
|
||||
source, webp_image, image_data, factor, udim_image = __gather_source(blender_shader_sockets, use_tile, export_settings)
|
||||
|
||||
exts, remove_source = __gather_extensions(blender_shader_sockets, source, webp_image, image_data, export_settings)
|
||||
|
||||
@ -197,8 +196,8 @@ def __gather_sampler(blender_shader_sockets, export_settings):
|
||||
export_settings)
|
||||
|
||||
|
||||
def __gather_source(blender_shader_sockets, default_sockets, use_tile, export_settings):
|
||||
source, image_data, factor, udim_image = gltf2_blender_gather_image.gather_image(blender_shader_sockets, default_sockets, use_tile, export_settings)
|
||||
def __gather_source(blender_shader_sockets, use_tile, export_settings):
|
||||
source, image_data, factor, udim_image = gltf2_blender_gather_image.gather_image(blender_shader_sockets, use_tile, export_settings)
|
||||
|
||||
|
||||
if export_settings['gltf_keep_original_textures'] is False \
|
||||
|
@ -24,25 +24,20 @@ from .gltf2_blender_search_node_tree import \
|
||||
# occlusion the primary_socket would be the occlusion socket, and
|
||||
# blender_shader_sockets would be the (O,R,M) sockets.
|
||||
|
||||
# Default socket parameter is used when there is a mapping between channels, and one of the channel is not a texture
|
||||
# In that case, we will create a texture with one channel from texture, other from default socket value
|
||||
# Example: MetallicRoughness
|
||||
|
||||
def gather_texture_info(primary_socket, blender_shader_sockets, default_sockets, export_settings, filter_type='ALL'):
|
||||
return __gather_texture_info_helper(primary_socket, blender_shader_sockets, default_sockets, 'DEFAULT', filter_type, export_settings)
|
||||
def gather_texture_info(primary_socket, blender_shader_sockets, export_settings, filter_type='ALL'):
|
||||
return __gather_texture_info_helper(primary_socket, blender_shader_sockets, 'DEFAULT', filter_type, export_settings)
|
||||
|
||||
def gather_material_normal_texture_info_class(primary_socket, blender_shader_sockets, export_settings, filter_type='ALL'):
|
||||
return __gather_texture_info_helper(primary_socket, blender_shader_sockets, (), 'NORMAL', filter_type, export_settings)
|
||||
return __gather_texture_info_helper(primary_socket, blender_shader_sockets, 'NORMAL', filter_type, export_settings)
|
||||
|
||||
def gather_material_occlusion_texture_info_class(primary_socket, blender_shader_sockets, default_sockets, export_settings, filter_type='ALL'):
|
||||
return __gather_texture_info_helper(primary_socket, blender_shader_sockets, default_sockets, 'OCCLUSION', filter_type, export_settings)
|
||||
def gather_material_occlusion_texture_info_class(primary_socket, blender_shader_sockets, export_settings, filter_type='ALL'):
|
||||
return __gather_texture_info_helper(primary_socket, blender_shader_sockets, 'OCCLUSION', filter_type, export_settings)
|
||||
|
||||
|
||||
@cached
|
||||
def __gather_texture_info_helper(
|
||||
primary_socket: bpy.types.NodeSocket,
|
||||
blender_shader_sockets: typing.Tuple[bpy.types.NodeSocket],
|
||||
default_sockets,
|
||||
kind: str,
|
||||
filter_type: str,
|
||||
export_settings):
|
||||
@ -51,7 +46,7 @@ def __gather_texture_info_helper(
|
||||
|
||||
tex_transform, uvmap_info = __gather_texture_transform_and_tex_coord(primary_socket, export_settings)
|
||||
|
||||
index, factor, udim_image = __gather_index(blender_shader_sockets, default_sockets, None, export_settings)
|
||||
index, factor, udim_image = __gather_index(blender_shader_sockets, None, export_settings)
|
||||
if udim_image is not None:
|
||||
udim_info = {'udim': udim_image is not None, 'image': udim_image, 'sockets': blender_shader_sockets}
|
||||
else:
|
||||
@ -91,7 +86,7 @@ def gather_udim_texture_info(
|
||||
|
||||
tex_transform, _ = __gather_texture_transform_and_tex_coord(primary_socket, export_settings)
|
||||
export_settings['current_udim_info'] = udim_info
|
||||
index, _, _ = __gather_index(blender_shader_sockets, (), udim_info['image'].name + str(udim_info['tile']), export_settings)
|
||||
index, _, _ = __gather_index(blender_shader_sockets, udim_info['image'].name + str(udim_info['tile']), export_settings)
|
||||
export_settings['current_udim_info'] = {}
|
||||
|
||||
fields = {
|
||||
@ -182,9 +177,9 @@ def __gather_occlusion_strength(primary_socket, export_settings):
|
||||
return None
|
||||
|
||||
|
||||
def __gather_index(blender_shader_sockets, default_sockets, use_tile, export_settings):
|
||||
def __gather_index(blender_shader_sockets, use_tile, export_settings):
|
||||
# We just put the actual shader into the 'index' member
|
||||
return gltf2_blender_gather_texture.gather_texture(blender_shader_sockets, default_sockets, use_tile, export_settings)
|
||||
return gltf2_blender_gather_texture.gather_texture(blender_shader_sockets, use_tile, export_settings)
|
||||
|
||||
|
||||
def __gather_texture_transform_and_tex_coord(primary_socket, export_settings):
|
||||
|
@ -20,8 +20,8 @@
|
||||
bl_info = {
|
||||
"name": "Material Utilities",
|
||||
"author": "MichaleW, ChrisHinde",
|
||||
"version": (2, 2, 0),
|
||||
"blender": (2, 80, 0),
|
||||
"version": (2, 2, 1),
|
||||
"blender": (3, 0, 0),
|
||||
"location": "View3D > Shift + Q key",
|
||||
"description": "Menu of material tools (assign, select..) in the 3D View",
|
||||
"warning": "Beta",
|
||||
|
@ -55,6 +55,7 @@ class VIEW3D_MT_materialutilities_assign_material(bpy.types.Menu):
|
||||
layout.separator()
|
||||
|
||||
for material_name, material in materials:
|
||||
material.preview_ensure()
|
||||
op = layout.operator(bl_id,
|
||||
text = material_name,
|
||||
icon_value = material.preview.icon_id)
|
||||
@ -119,6 +120,7 @@ class VIEW3D_MT_materialutilities_select_by_material(bpy.types.Menu):
|
||||
# There's no point in showing materials with 0 users
|
||||
# (It will still show materials with fake user though)
|
||||
if material.users > 0:
|
||||
material.preview_ensure()
|
||||
op = layout.operator(bl_id,
|
||||
text = material_name,
|
||||
icon_value = material.preview.icon_id
|
||||
@ -140,6 +142,7 @@ class VIEW3D_MT_materialutilities_select_by_material(bpy.types.Menu):
|
||||
if material.name in materials_added:
|
||||
continue
|
||||
|
||||
material.preview_ensure()
|
||||
op = layout.operator(bl_id,
|
||||
text = material.name,
|
||||
icon_value = material.preview.icon_id
|
||||
|
@ -5,7 +5,7 @@
|
||||
bl_info = {
|
||||
"name": "Node Wrangler",
|
||||
"author": "Bartek Skorupa, Greg Zaal, Sebastian Koenig, Christian Brinkmann, Florian Meyer",
|
||||
"version": (3, 47),
|
||||
"version": (3, 48),
|
||||
"blender": (4, 0, 0),
|
||||
"location": "Node Editor Toolbar or Shift-W",
|
||||
"description": "Various tools to enhance and speed up node-based workflow",
|
||||
|
@ -518,7 +518,7 @@ class NWPreviewNode(Operator, NWBase):
|
||||
output_sockets = self.get_output_sockets(node.node_tree)
|
||||
if len(output_sockets):
|
||||
free_socket = None
|
||||
for socket in output_sockets:
|
||||
for i, socket in enumerate(output_sockets):
|
||||
if is_viewer_socket(socket) and socket.socket_type == socket_type:
|
||||
# if viewer output is already used but leads to the same socket we can still use it
|
||||
is_used = self.is_socket_used_other_mats(socket)
|
||||
@ -694,7 +694,6 @@ class NWPreviewNode(Operator, NWBase):
|
||||
else:
|
||||
out_i = valid_outputs[0]
|
||||
|
||||
make_links = [] # store sockets for new links
|
||||
if active.outputs:
|
||||
# If there is no 'GEOMETRY' output type - We can't preview the node
|
||||
if out_i is None:
|
||||
@ -708,26 +707,25 @@ class NWPreviewNode(Operator, NWBase):
|
||||
break
|
||||
if geometryoutindex is None:
|
||||
# Create geometry socket
|
||||
geometryoutput.inputs.new(socket_type, 'Geometry')
|
||||
geometryoutindex = len(geometryoutput.inputs) - 1
|
||||
geometry_output_socket = base_node_tree.interface.new_socket(
|
||||
'Geometry', in_out='OUTPUT', socket_type='NodeSocketGeometry')
|
||||
geometryoutindex = geometry_output_socket.index
|
||||
|
||||
make_links.append((active.outputs[out_i], geometryoutput.inputs[geometryoutindex]))
|
||||
output_socket = geometryoutput.inputs[geometryoutindex]
|
||||
for li_from, li_to in make_links:
|
||||
connect_sockets(li_from, li_to)
|
||||
|
||||
# Create links through node groups until we reach the active node
|
||||
tree = base_node_tree
|
||||
link_end = output_socket
|
||||
while tree.nodes.active != active:
|
||||
node = tree.nodes.active
|
||||
viewer_socket = self.ensure_viewer_socket(
|
||||
node, 'NodeSocketGeometry', connect_socket=active.outputs[out_i] if node.node_tree.nodes.active == active else None)
|
||||
link_start = node.outputs[viewer_socket_name]
|
||||
node_socket = viewer_socket
|
||||
if node_socket in delete_sockets:
|
||||
delete_sockets.remove(node_socket)
|
||||
link_start = node.outputs[viewer_socket.identifier]
|
||||
if viewer_socket in delete_sockets:
|
||||
delete_sockets.remove(viewer_socket)
|
||||
connect_sockets(link_start, link_end)
|
||||
# Iterate
|
||||
link_end = self.ensure_group_output(node.node_tree).inputs[viewer_socket_name]
|
||||
link_end = self.ensure_group_output(node.node_tree).inputs[viewer_socket.identifier]
|
||||
tree = tree.nodes.active.node_tree
|
||||
connect_sockets(active.outputs[out_i], link_end)
|
||||
|
||||
@ -778,14 +776,10 @@ class NWPreviewNode(Operator, NWBase):
|
||||
else:
|
||||
out_i = valid_outputs[0]
|
||||
|
||||
make_links = [] # store sockets for new links
|
||||
if active.outputs:
|
||||
socket_type = 'NodeSocketShader'
|
||||
materialout_index = 1 if active.outputs[out_i].name == "Volume" else 0
|
||||
make_links.append((active.outputs[out_i], materialout.inputs[materialout_index]))
|
||||
output_socket = materialout.inputs[materialout_index]
|
||||
for li_from, li_to in make_links:
|
||||
connect_sockets(li_from, li_to)
|
||||
|
||||
# Create links through node groups until we reach the active node
|
||||
tree = base_node_tree
|
||||
@ -794,13 +788,12 @@ class NWPreviewNode(Operator, NWBase):
|
||||
node = tree.nodes.active
|
||||
viewer_socket = self.ensure_viewer_socket(
|
||||
node, socket_type, connect_socket=active.outputs[out_i] if node.node_tree.nodes.active == active else None)
|
||||
link_start = node.outputs[viewer_socket_name]
|
||||
node_socket = viewer_socket
|
||||
if node_socket in delete_sockets:
|
||||
delete_sockets.remove(node_socket)
|
||||
link_start = node.outputs[viewer_socket.identifier]
|
||||
if viewer_socket in delete_sockets:
|
||||
delete_sockets.remove(viewer_socket)
|
||||
connect_sockets(link_start, link_end)
|
||||
# Iterate
|
||||
link_end = self.ensure_group_output(node.node_tree).inputs[viewer_socket_name]
|
||||
link_end = self.ensure_group_output(node.node_tree).inputs[viewer_socket.identifier]
|
||||
tree = tree.nodes.active.node_tree
|
||||
connect_sockets(active.outputs[out_i], link_end)
|
||||
|
||||
|
33
real_snow.py
33
real_snow.py
@ -6,8 +6,8 @@ bl_info = {
|
||||
"name": "Real Snow",
|
||||
"description": "Generate snow mesh",
|
||||
"author": "Marco Pavanello, Drew Perttula",
|
||||
"version": (1, 3),
|
||||
"blender": (3, 1, 0),
|
||||
"version": (1, 3, 2),
|
||||
"blender": (4, 1, 0),
|
||||
"location": "View 3D > Properties Panel",
|
||||
"doc_url": "{BLENDER_MANUAL_URL}/addons/object/real_snow.html",
|
||||
"tracker_url": "https://gitlab.com/marcopavanello/real-snow/-/issues",
|
||||
@ -273,20 +273,19 @@ def add_material(obj: bpy.types.Object):
|
||||
coord.location = (-1900, 0)
|
||||
# Change node parameters
|
||||
principled.distribution = "MULTI_GGX"
|
||||
principled.subsurface_method = "RANDOM_WALK"
|
||||
principled.inputs[0].default_value[0] = 0.904
|
||||
principled.subsurface_method = "RANDOM_WALK_SKIN"
|
||||
principled.inputs[0].default_value[0] = 0.904 # Base color
|
||||
principled.inputs[0].default_value[1] = 0.904
|
||||
principled.inputs[0].default_value[2] = 0.904
|
||||
principled.inputs[1].default_value = 1
|
||||
principled.inputs[2].default_value[0] = 0.36
|
||||
principled.inputs[2].default_value[1] = 0.46
|
||||
principled.inputs[2].default_value[2] = 0.6
|
||||
principled.inputs[3].default_value[0] = 0.904
|
||||
principled.inputs[3].default_value[1] = 0.904
|
||||
principled.inputs[3].default_value[2] = 0.904
|
||||
principled.inputs[7].default_value = 0.224
|
||||
principled.inputs[9].default_value = 0.1
|
||||
principled.inputs[15].default_value = 0.1
|
||||
principled.inputs[7].default_value = 1 # Subsurface weight
|
||||
principled.inputs[9].default_value = 1 # Subsurface scale
|
||||
principled.inputs[8].default_value[0] = 0.36 # Subsurface radius
|
||||
principled.inputs[8].default_value[1] = 0.46
|
||||
principled.inputs[8].default_value[2] = 0.6
|
||||
principled.inputs[12].default_value = 0.224 # Specular
|
||||
principled.inputs[2].default_value = 0.1 # Roughness
|
||||
principled.inputs[19].default_value = 0.1 # Coat roughness
|
||||
principled.inputs[20].default_value = 1.2 # Coat IOR
|
||||
vec_math.operation = "MULTIPLY"
|
||||
vec_math.inputs[1].default_value[0] = 0.5
|
||||
vec_math.inputs[1].default_value[1] = 0.5
|
||||
@ -321,7 +320,7 @@ def add_material(obj: bpy.types.Object):
|
||||
# Link nodes
|
||||
link = mat.node_tree.links
|
||||
link.new(principled.outputs[0], output.inputs[0])
|
||||
link.new(vec_math.outputs[0], principled.inputs[2])
|
||||
link.new(vec_math.outputs[0], principled.inputs[8])
|
||||
link.new(com_xyz.outputs[0], vec_math.inputs[0])
|
||||
link.new(dis.outputs[0], output.inputs[2])
|
||||
link.new(mul1.outputs[0], dis.inputs[0])
|
||||
@ -329,7 +328,7 @@ def add_material(obj: bpy.types.Object):
|
||||
link.new(add2.outputs[0], add1.inputs[0])
|
||||
link.new(mul2.outputs[0], add2.inputs[0])
|
||||
link.new(mul3.outputs[0], add2.inputs[1])
|
||||
link.new(range1.outputs[0], principled.inputs[14])
|
||||
link.new(range1.outputs[0], principled.inputs[18])
|
||||
link.new(range2.outputs[0], mul3.inputs[0])
|
||||
link.new(range3.outputs[0], add1.inputs[1])
|
||||
link.new(vor.outputs[4], range1.inputs[0])
|
||||
@ -342,7 +341,7 @@ def add_material(obj: bpy.types.Object):
|
||||
link.new(mapping.outputs[0], noise3.inputs[0])
|
||||
link.new(coord.outputs[3], mapping.inputs[0])
|
||||
# Set displacement and add material
|
||||
mat.cycles.displacement_method = "DISPLACEMENT"
|
||||
mat.displacement_method = "DISPLACEMENT"
|
||||
obj.data.materials.append(mat)
|
||||
|
||||
|
||||
|
@ -229,7 +229,7 @@ class SunPosProperties(PropertyGroup):
|
||||
|
||||
object_collection_type: EnumProperty(
|
||||
name="Display type",
|
||||
description="Type of Sun motion to visualize.",
|
||||
description="Type of Sun motion to visualize",
|
||||
items=(
|
||||
('ANALEMMA', "Analemma", "Trajectory of the Sun in the sky during the year, for a given time of the day"),
|
||||
('DIURNAL', "Diurnal", "Trajectory of the Sun in the sky during a single day"),
|
||||
|
@ -32,7 +32,7 @@ translations_tuple = (
|
||||
(False, ())),
|
||||
),
|
||||
(("*", "Daylight Savings"),
|
||||
(("bpy.types.SunPosProperties.use_daylight_savings"),
|
||||
(("bpy.types.SunPosProperties.use_daylight_savings",),
|
||||
()),
|
||||
("fr_FR", "Heure d’été",
|
||||
(False, ())),
|
||||
@ -218,7 +218,7 @@ translations_tuple = (
|
||||
("fr_FR", "Collection d’objets utilisée pour visualiser la trajectoire du Soleil",
|
||||
(False, ())),
|
||||
),
|
||||
(("*", "Type of Sun motion to visualize."),
|
||||
(("*", "Type of Sun motion to visualize"),
|
||||
(("bpy.types.SunPosProperties.object_collection_type",),
|
||||
()),
|
||||
("fr_FR", "Type de trajectoire du Soleil à visualiser",
|
||||
@ -530,7 +530,7 @@ translations_tuple = (
|
||||
(("scripts/addons/sun_position/ui_sun.py:94",
|
||||
"scripts/addons/sun_position/ui_sun.py:137"),
|
||||
()),
|
||||
("fr_FR", "Veuillez activer Utiliser nœuds dans le panneau Monde",
|
||||
("fr_FR", "Veuillez activer Utiliser nœuds dans le panneau Monde.",
|
||||
(False, ())),
|
||||
),
|
||||
(("*", "World > Sun Position"),
|
||||
|
Loading…
Reference in New Issue
Block a user