Add UV texture support for IfcTessellatedFaceSet (#3523)

* Add texture support for IfcIndexedTextureMap

* fix description.

* Fix posible duplicate coordinate index issue

* Clean up code.

* revert default clean_mesh.

* Fix errors.

* change to EXTEND mode when not RepeatS/T

* remove tris merge to support mix quads and tris.
This commit is contained in:
Wei Yang
2023-07-30 12:34:50 +02:00
committed by GitHub
parent 60f60798df
commit 356a10eac9
3 changed files with 64 additions and 2 deletions
@@ -52,6 +52,7 @@ class FileCopy(threading.Thread):
class MaterialCreator:
def __init__(self, ifc_import_settings, ifc_importer):
self.mesh = None
self.obj = None
self.materials = {}
self.styles = {}
self.parsed_meshes = set()
@@ -60,6 +61,8 @@ class MaterialCreator:
def create(self, element, obj, mesh):
self.mesh = mesh
# as ifcopenshell triangulates the mesh, we need to merge it to quads again
self.obj = obj
if (hasattr(element, "Representation") and not element.Representation) or (
hasattr(element, "RepresentationMaps") and not element.RepresentationMaps
):
@@ -132,10 +135,55 @@ class MaterialCreator:
return
for style_id in style_ids:
material = self.styles[style_id]
ifc_coordinate_id = material.BIMMaterialProperties.ifc_coordinate_id
if ifc_coordinate_id != 0:
self.load_texture_map(tool.Ifc.get().by_id(ifc_coordinate_id))
if self.mesh.materials.find(material.name) == -1:
self.mesh.materials.append(material)
return True
def load_texture_map(self, coordinates):
# Get a BMesh representation
bm = bmesh.new()
bm.from_mesh(self.mesh)
uv_layer = bm.loops.layers.uv.verify()
# remap the faceset CoordList index to the vertices in blender mesh
coordinates_remap = []
for co in coordinates.MappedTo.Coordinates.CoordList:
co = mathutils.Vector(co)
index = next(v.index for v in bm.verts if (v.co - co).length_squared < 1e-5)
coordinates_remap.append(index)
faces_remap = None
texture_map = None
if coordinates.is_a("IfcIndexedPolygonalTextureMap"):
faces_remap = [[coordinates_remap[i-1] for i in tex_coord_index.TexCoordsOf.CoordIndex]
for tex_coord_index in coordinates.TexCoordIndices]
texture_map = [tex_coord_index.TexCoordIndex for tex_coord_index in coordinates.TexCoordIndices]
elif coordinates.is_a("IfcIndexedTriangleTextureMap"):
faces_remap = [[coordinates_remap[i-1] for i in triangle_face]
for triangle_face in coordinates.MappedTo.CoordIndex]
texture_map = coordinates.TexCoordIndex
# apply uv to each face
for bface in bm.faces:
face = [loop.vert.index for loop in bface.loops]
# find the corresponding TexCoordIndex by matching ifc faceset with blender face
# remap TexCoordIndex as the loop start may different from blender face
texCoordIndex = next(
[tex_coord_index[face_remap.index(i)] for i in face]
for tex_coord_index, face_remap in zip(texture_map, faces_remap)
if all(i in face_remap for i in face)
)
# apply uv to each loop
for loop, i in zip(bface.loops, texCoordIndex):
loop[uv_layer].uv = coordinates.TexCoords.TexCoordsList[i-1]
# Finish up, write the bmesh back to the mesh
bm.to_mesh(self.mesh)
bm.free()
def assign_material_slots_to_faces(self):
if "ios_materials" not in self.mesh or not self.mesh["ios_materials"]:
return
+1
View File
@@ -427,6 +427,7 @@ class BIMMaterialProperties(PropertyGroup):
attributes: CollectionProperty(name="Attributes", type=Attribute)
# In Blender, a material object can map to an IFC material, IFC surface style, or both
ifc_style_id: IntProperty(name="IFC Style ID")
ifc_coordinate_id: IntProperty(name="IFC Coordinate ID")
shading_checksum: StringProperty(name="Shading Checksum")
+15 -2
View File
@@ -308,8 +308,10 @@ class Loader(blenderbim.core.tool.Loader):
image = bpy.data.images.load(image_url)
node.image = image
blender_material.node_tree.links.new(node.outputs[0], bsdf.inputs["Base Color"])
blender_material.node_tree.links.new(node.outputs[1], bsdf.inputs["Alpha"])
blender_material.blend_method = "BLEND"
# leave it to default(OPAQUE) when no Transparency defined
if transparency := rendering_style.get("Transparency", None):
blender_material.node_tree.links.new(node.outputs[1], bsdf.inputs["Alpha"])
blender_material.blend_method = "BLEND"
elif reflectance_method == "FLAT":
bsdf = tool.Blender.get_material_node(blender_material, "MIX_SHADER")
@@ -328,7 +330,16 @@ class Loader(blenderbim.core.tool.Loader):
blender_material.node_tree.links.new(node.outputs[0], bsdf.inputs[2])
# extend the image by repeating pixels on its edges if RepeatS or RepeatT is False
repeat_s = texture.get("RepeatS", True)
repeat_t = texture.get("RepeatT", True)
if node and (not repeat_s or not repeat_t):
node.extension = "EXTEND"
# TODO: add support for texture data not ifc elements
# IsMappedBy could only get with the entity_instance for IFC4/IFC4x3
if isinstance(texture, dict):
texture = tool.Ifc.get().by_id(texture['id'])
if node and getattr(texture, "IsMappedBy", None):
coordinates = texture.IsMappedBy[0]
coord = blender_material.node_tree.nodes.new(type="ShaderNodeTexCoord")
@@ -339,3 +350,5 @@ class Loader(blenderbim.core.tool.Loader):
blender_material.node_tree.links.new(coord.outputs["Camera"], node.inputs["Vector"])
else:
blender_material.node_tree.links.new(coord.outputs["UV"], node.inputs["Vector"])
# save the TextureMap id for set uv when set material to mesh
blender_material.BIMMaterialProperties.ifc_coordinate_id = coordinates.id()