moved load_texture_map to tool.Loader, added a test

This commit is contained in:
Andrej730
2023-11-28 15:33:30 +05:00
parent 7cb582de5d
commit 18c93a13ec
3 changed files with 167 additions and 52 deletions
+1 -52
View File
@@ -143,62 +143,11 @@ class MaterialCreator:
return return
if coords := get_ifc_coordinate(material): if coords := get_ifc_coordinate(material):
self.load_texture_map(coords) tool.Loader.load_indexed_texture_map(coords, self.mesh)
if self.mesh.materials.find(material.name) == -1: if self.mesh.materials.find(material.name) == -1:
self.mesh.materials.append(material) self.mesh.materials.append(material)
return True 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 = []
si_conversion = ifcopenshell.util.unit.calculate_unit_scale(self.ifc_importer.file)
faceset = coordinates.MappedTo
for co in faceset.Coordinates.CoordList:
co = mathutils.Vector(co) * si_conversion
index = next(v.index for v in bm.verts if (v.co - co).length_squared < 1e-5)
coordinates_remap.append(index)
# ifc indices start with 1
remap_verts_to_blender = lambda ifc_verts: [coordinates_remap[i - 1] for i in ifc_verts]
# faces_remap - ifc faces described using blender verts indices
# IFC4.3+
if coordinates.is_a("IfcIndexedPolygonalTextureMap"):
faces_remap = [
remap_verts_to_blender(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]
else: # IfcIndexedTriangleTextureMap
if faceset.is_a("IfcTriangulatedFaceSet"):
faces_remap = [remap_verts_to_blender(triangle_face) for triangle_face in faceset.CoordIndex]
else: # IfcPolygonalFaceSet
faces_remap = [remap_verts_to_blender(triangle_face.CoordIndex) for triangle_face in faceset.Faces]
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, strict=True)
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): def assign_material_slots_to_faces(self):
if "ios_materials" not in self.mesh or not self.mesh["ios_materials"]: if "ios_materials" not in self.mesh or not self.mesh["ios_materials"]:
return return
+53
View File
@@ -18,6 +18,7 @@
import re import re
import bpy import bpy
import bmesh
import ifcopenshell.util.element import ifcopenshell.util.element
import blenderbim.core.tool import blenderbim.core.tool
import blenderbim.tool as tool import blenderbim.tool as tool
@@ -380,3 +381,55 @@ class Loader(blenderbim.core.tool.Loader):
blender_material.node_tree.links.new(coord.outputs["Camera"], node.inputs["Vector"]) blender_material.node_tree.links.new(coord.outputs["Camera"], node.inputs["Vector"])
else: # uv_mode == UV else: # uv_mode == UV
blender_material.node_tree.links.new(coord.outputs["UV"], node.inputs["Vector"]) blender_material.node_tree.links.new(coord.outputs["UV"], node.inputs["Vector"])
@classmethod
def load_indexed_texture_map(cls, coordinates, mesh):
# Get a BMesh representation
bm = bmesh.new()
bm.from_mesh(mesh)
uv_layer = bm.loops.layers.uv.verify()
# remap the faceset CoordList index to the vertices in blender mesh
coordinates_remap = []
si_conversion = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
faceset = coordinates.MappedTo
for co in faceset.Coordinates.CoordList:
co = Vector(co) * si_conversion
index = next(v.index for v in bm.verts if (v.co - co).length_squared < 1e-5)
coordinates_remap.append(index)
# ifc indices start with 1
remap_verts_to_blender = lambda ifc_verts: [coordinates_remap[i - 1] for i in ifc_verts]
# faces_remap - ifc faces described using blender verts indices
# IFC4.3+
if coordinates.is_a("IfcIndexedPolygonalTextureMap"):
faces_remap = [
remap_verts_to_blender(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]
else: # IfcIndexedTriangleTextureMap
if faceset.is_a("IfcTriangulatedFaceSet"):
faces_remap = [remap_verts_to_blender(triangle_face) for triangle_face in faceset.CoordIndex]
else: # IfcPolygonalFaceSet
faces_remap = [remap_verts_to_blender(triangle_face.CoordIndex) for triangle_face in faceset.Faces]
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, strict=True)
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(mesh)
bm.free()
+113
View File
@@ -17,12 +17,15 @@
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>. # along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import bpy import bpy
import bmesh
import ifcopenshell import ifcopenshell
import blenderbim.core.tool import blenderbim.core.tool
import blenderbim.tool as tool import blenderbim.tool as tool
from test.bim.bootstrap import NewFile from test.bim.bootstrap import NewFile
from blenderbim.tool.loader import Loader as subject from blenderbim.tool.loader import Loader as subject
import numpy as np import numpy as np
from ifcopenshell.util.shape_builder import ShapeBuilder, V
from mathutils import Vector
class TestImplementsTool(NewFile): class TestImplementsTool(NewFile):
@@ -78,3 +81,113 @@ class TestCreatingStyles(NewFile):
image_node = tool.Blender.get_material_node(material, "TEX_IMAGE") image_node = tool.Blender.get_material_node(material, "TEX_IMAGE")
assert image_node.outputs["Color"].links[0].to_socket.name == "Base Color" assert image_node.outputs["Color"].links[0].to_socket.name == "Base Color"
assert image_node.inputs["Vector"].links[0].from_socket.name == "Generated" assert image_node.inputs["Vector"].links[0].from_socket.name == "Generated"
class TestLoadingIndexedTextureMap(NewFile):
def test_run(self):
bpy.context.scene.unit_settings.length_unit = "MILLIMETERS"
bpy.ops.bim.create_project()
# TODO: replace with loading geometry from IFC
# create a cube without uv and triangulate it
mesh = bpy.data.meshes.new("Cube")
bm = tool.Blender.get_bmesh_for_mesh(mesh, clean=True)
bmesh.ops.create_cube(bm, size=2.0, calc_uvs=False)
bmesh.ops.triangulate(bm, faces=bm.faces[:])
tool.Blender.apply_bmesh(mesh, bm)
ifc_file = tool.Ifc.get()
builder = ShapeBuilder(ifc_file)
# tesselated cube
points = (
V(-1000, -1000, -1000),
V(-1000, -1000, 1000),
V(-1000, 1000, -1000),
V(-1000, 1000, 1000),
V(1000, -1000, -1000),
V(1000, -1000, 1000),
V(1000, 1000, -1000),
V(1000, 1000, 1000),
)
faces = (
(1, 2, 0),
(3, 6, 2),
(7, 4, 6),
(5, 0, 4),
(6, 0, 2),
(3, 5, 7),
(1, 3, 2),
(3, 7, 6),
(7, 5, 4),
(5, 1, 0),
(6, 4, 0),
(3, 1, 5),
)
face_set = builder.polygonal_face_set(points, faces)
uv_indices = (
(1, 2, 3),
(4, 5, 6),
(7, 8, 9),
(10, 11, 12),
(13, 14, 15),
(16, 17, 18),
(19, 20, 21),
(22, 23, 24),
(25, 26, 27),
(28, 29, 30),
(31, 32, 33),
(34, 35, 36),
)
uv_verts = (
(0.625, 0.0),
(0.375, 0.25),
(0.375, 0.0),
(0.625, 0.25),
(0.375, 0.5),
(0.375, 0.25),
(0.625, 0.5),
(0.375, 0.75),
(0.375, 0.5),
(0.625, 0.75),
(0.375, 1.0),
(0.375, 0.75),
(0.375, 0.5),
(0.125, 0.75),
(0.125, 0.5),
(0.875, 0.5),
(0.625, 0.75),
(0.625, 0.5),
(0.625, 0.0),
(0.625, 0.25),
(0.375, 0.25),
(0.625, 0.25),
(0.625, 0.5),
(0.375, 0.5),
(0.625, 0.5),
(0.625, 0.75),
(0.375, 0.75),
(0.625, 0.75),
(0.625, 1.0),
(0.375, 1.0),
(0.375, 0.5),
(0.375, 0.75),
(0.125, 0.75),
(0.875, 0.5),
(0.875, 0.75),
(0.625, 0.75),
)
uv_verts_list = ifc_file.createIfcTextureVertexList()
uv_verts_list.TexCoordsList = uv_verts
texture_coord = ifc_file.createIfcIndexedTriangleTextureMap()
texture_coord.MappedTo = face_set
texture_coord.TexCoordIndex = uv_indices
texture_coord.TexCoords = uv_verts_list
subject.load_indexed_texture_map(texture_coord, mesh)
uv_layer = mesh.uv_layers.active
assert uv_layer is not None
for ifc_uv, blender_uv in zip(uv_verts, uv_layer.uv, strict=True):
assert tool.Cad.are_vectors_equal(Vector(ifc_uv), blender_uv.vector)