mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-19 06:39:13 +00:00
moved load_texture_map to tool.Loader, added a test
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user