glTF exporter: Fix UVMap export when is set from an attribute node

This commit is contained in:
Julien Duroure 2024-05-24 09:28:53 +02:00
parent a71027d37f
commit ac97907841
4 changed files with 31 additions and 6 deletions

@ -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, 2, 34),
"version": (4, 2, 35),
'blender': (4, 2, 0),
'location': 'File > Import-Export',
'description': 'Import-Export as glTF 2.0',

@ -420,7 +420,8 @@ class PrimitiveCreator:
new_prim_indices = {}
self.additional_materials = [] # In case of UDIM
self.uvmap_attribute_list = [] # Initialize here, in case we don't have any triangle primitive
self.uvmap_attribute_lists = []
self.uvmap_attribute_list = [] # For each material # Initialize here, in case we don't have any triangle primitive
materials_use_vc = None
warning_already_displayed = False
@ -431,6 +432,10 @@ class PrimitiveCreator:
self.uvmap_attribute_list = list(
set([i['value'] for i in material_info["uv_info"].values() if 'type' in i.keys() and i['type'] == "Attribute"]))
# Check that attributes are not regular UVMaps
self.uvmap_attribute_list = [
i for i in self.uvmap_attribute_list if i not in self.blender_mesh.uv_layers.keys()]
additional_fields = []
for attr in self.uvmap_attribute_list:
if attr + str(0) not in self.dots.dtype.names: # In case user exports custom attributes, we may have it already
@ -455,6 +460,8 @@ class PrimitiveCreator:
data = data.reshape(-1, 3)
data = data[:, :2]
elif self.blender_mesh.attributes[attr].data_type == "FLOAT2":
# This case should not happen, because we are in CORNER domain / 2D Vector,
# So this attribute is an UVMap
data = np.empty(len(self.blender_mesh.loops) *
2, gltf2_blender_conversion.get_numpy_type('FLOAT2'))
self.blender_mesh.attributes[attr].data.foreach_get('vector', data)
@ -550,6 +557,7 @@ class PrimitiveCreator:
if len(material_info['udim_info'].keys()) == 0:
new_prim_indices[material_idx] = self.prim_indices[material_idx]
self.uvmap_attribute_lists.append(self.uvmap_attribute_list)
self.additional_materials.append(None)
continue
@ -571,12 +579,19 @@ class PrimitiveCreator:
index_uvmap = get_active_uvmap_index(self.blender_mesh)
uvmap_name = "TEXCOORD_" + str(index_uvmap)
else: # Attribute
uvmap_name = material_info['uv_info'][tex]['value']
# This can be a regular UVMap, or a custom attribute
index_uvmap = self.blender_mesh.uv_layers.find(material_info['uv_info'][tex]['value'])
if index_uvmap < 0:
# This is a custom attribute
uvmap_name = material_info['uv_info'][tex]['value']
else:
uvmap_name = "TEXCOORD_" + str(index_uvmap)
all_uvmaps[tex] = uvmap_name
if len(set(all_uvmaps.values())) > 1:
self.export_settings['log'].warning('We are not managing this case (multiple UVMap for UDIM)')
new_prim_indices[material_idx] = self.prim_indices[material_idx]
self.uvmap_attribute_lists.append(self.uvmap_attribute_list)
self.additional_materials.append(None)
continue
@ -632,6 +647,7 @@ class PrimitiveCreator:
new_triangle_indices.append(self.prim_indices[material_idx][idx + 1])
new_triangle_indices.append(self.prim_indices[material_idx][idx + 2])
new_prim_indices[new_material_index] = np.array(new_triangle_indices, dtype=np.uint32)
self.uvmap_attribute_lists.append(self.uvmap_attribute_list)
new_material_index += 1
# Now we have to create a new material for this tile
@ -763,7 +779,8 @@ class PrimitiveCreator:
def primitive_creation_not_shared(self):
primitives = []
for material_idx, dot_indices in self.prim_indices.items():
for (material_idx, dot_indices), uvmap_attribute_list in zip(
self.prim_indices.items(), self.uvmap_attribute_lists):
# Extract just dots used by this primitive, deduplicate them, and
# calculate indices into this deduplicated list.
self.prim_dots = self.dots[dot_indices]
@ -786,7 +803,7 @@ class PrimitiveCreator:
next_texcoor_idx = self.tex_coord_max
uvmap_attributes_index = {}
for attr in self.uvmap_attribute_list:
for attr in uvmap_attribute_list:
res = np.empty((len(self.prim_dots), 2), dtype=gltf2_blender_conversion.get_numpy_type('FLOAT2'))
for i in range(2):
res[:, i] = self.prim_dots[attr + str(i)]

@ -561,7 +561,12 @@ def get_final_material(mesh, blender_material, attr_indices, base_material, uvma
elif v['type'] == 'Active':
indices[m] = get_active_uvmap_index(mesh)
elif v['type'] == "Attribute":
indices[m] = attr_indices[v['value']]
# This can be a regular UVMap or a custom attribute
i = mesh.uv_layers.find(v['value'])
if i >= 0:
indices[m] = i
else:
indices[m] = attr_indices[v['value']]
# Now we have all needed indices, let's create a set that can be used for
# caching, so containing all possible textures

@ -259,6 +259,9 @@ def __gather_texture_transform_and_tex_coord(primary_socket, export_settings):
elif node and node.node and node.node.type == 'ATTRIBUTE' \
and node.node.attribute_type == "GEOMETRY" \
and node.node.attribute_name:
# If this attribute is Face Corner / 2D Vector, this is a UV map
# So we can use it as a UV map Fixed
# But this will be checked later, when we know the mesh
uvmap_info['type'] = 'Attribute'
uvmap_info['value'] = node.node.attribute_name