From 617c8d71134f0add1c4bff45c8c9db542e48c540 Mon Sep 17 00:00:00 2001 From: Mathias Artus Date: Thu, 22 Oct 2020 09:52:15 +0200 Subject: [PATCH 1/4] Adding the visualization of textures Adding a spherical texture mapping --- .../Extensions/Utility/GeomUtils.cs | 8 ++ .../LayerStyling/SurfaceLayerStyler.cs | 52 ++++++-- .../Texturing/ITextureMapping.cs | 20 ++++ .../Texturing/SphericalTextureMap.cs | 65 ++++++++++ Xbim.Presentation/WpfMaterial.cs | 24 ++++ Xbim.Presentation/WpfMeshGeometry3D.cs | 111 ++++++++++++++++-- 6 files changed, 259 insertions(+), 21 deletions(-) create mode 100644 Xbim.Presentation/Texturing/ITextureMapping.cs create mode 100644 Xbim.Presentation/Texturing/SphericalTextureMap.cs diff --git a/Xbim.Presentation/Extensions/Utility/GeomUtils.cs b/Xbim.Presentation/Extensions/Utility/GeomUtils.cs index b9c09e8b..5c7b0254 100644 --- a/Xbim.Presentation/Extensions/Utility/GeomUtils.cs +++ b/Xbim.Presentation/Extensions/Utility/GeomUtils.cs @@ -73,5 +73,13 @@ public static Point3DCollection GetPointCollection(List points) } return ret; } + + public static Vector3D VectorProduct (this Vector3D vector1, Vector3D vector2) + { + double nx = vector1.Y * vector2.Z - vector1.Z * vector2.Y; + double ny = vector1.Z * vector2.X - vector1.X * vector2.Z; + double nz = vector1.X * vector2.Y - vector1.Y * vector2.X; + return new Vector3D(nx, ny, nz); + } } } diff --git a/Xbim.Presentation/LayerStyling/SurfaceLayerStyler.cs b/Xbim.Presentation/LayerStyling/SurfaceLayerStyler.cs index 3e70c1a6..92ffa8b7 100644 --- a/Xbim.Presentation/LayerStyling/SurfaceLayerStyler.cs +++ b/Xbim.Presentation/LayerStyling/SurfaceLayerStyler.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; +using System.IO; using System.Linq; using System.Windows; using System.Windows.Media.Media3D; @@ -241,19 +242,52 @@ protected static WpfMeshGeometry3D GetNewStyleMesh(WpfMaterial wpfMaterial, Mode protected WpfMaterial GetWpfMaterial(IModel model, int styleId) { var sStyle = model.Instances[styleId] as IIfcSurfaceStyle; - var texture = XbimTexture.Create(sStyle); - if(texture.ColourMap.Count > 0) - { - if (texture.ColourMap[0].Alpha <= 0) + var wpfMaterial = new WpfMaterial(); + + //The style contains a texture + bool isTexture = false; + if (sStyle.Styles.Any(x => x is IIfcSurfaceStyleWithTextures)) + { + IIfcSurfaceStyleWithTextures surfaceStyleWithTexture = (IIfcSurfaceStyleWithTextures)sStyle.Styles.First(x => x is IIfcSurfaceStyleWithTextures); + if (surfaceStyleWithTexture.Textures.Any(x => x is IIfcImageTexture)) { - texture.ColourMap[0].Alpha = 0.5f; - Logger.LogWarning("Fully transparent style #{styleId} forced to 50% opacity.", styleId); + IIfcImageTexture imageTexture = surfaceStyleWithTexture.Textures.First(x => x is IIfcImageTexture) as IIfcImageTexture; + //generate the correct path + Uri imageUri; + if (Uri.TryCreate(imageTexture.URLReference, UriKind.Absolute, out imageUri)) + { + wpfMaterial.WpfMaterialFromImageTexture(imageUri); + } + else if (Uri.TryCreate(imageTexture.URLReference, UriKind.Relative, out imageUri)) + { + Uri modelFileUri = new Uri(model.Header.FileName.Name); + Uri absolutFileUri = new Uri(modelFileUri, imageTexture.URLReference); + wpfMaterial.WpfMaterialFromImageTexture(absolutFileUri); + } + else + { + Logger.LogWarning(0, "Invalid Uri " + imageTexture.URLReference + " (bad formatted or file not found).", imageTexture); + } + isTexture = true; } } + + //The style doesn't contain a texture + if (isTexture == false) + { + var texture = XbimTexture.Create(sStyle); + if (texture.ColourMap.Count > 0) + { + if (texture.ColourMap[0].Alpha <= 0) + { + texture.ColourMap[0].Alpha = 0.5f; + Logger.LogWarning("Fully transparent style #{styleId} forced to 50% opacity.", styleId); + } + } - texture.DefinedObjectId = styleId; - var wpfMaterial = new WpfMaterial(); - wpfMaterial.CreateMaterial(texture); + texture.DefinedObjectId = styleId; + wpfMaterial.CreateMaterial(texture); + } return wpfMaterial; } diff --git a/Xbim.Presentation/Texturing/ITextureMapping.cs b/Xbim.Presentation/Texturing/ITextureMapping.cs new file mode 100644 index 00000000..fa52a5a8 --- /dev/null +++ b/Xbim.Presentation/Texturing/ITextureMapping.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Media.Media3D; + +namespace Xbim.Presentation.Texturing +{ + public interface ITextureMapping + { + /// + /// returns the texture map for a given set of vertices + /// + /// Vertices of the related mesh + /// a texture map for the related mesh + IEnumerable GetTextureMap(IEnumerable vertices); + } +} diff --git a/Xbim.Presentation/Texturing/SphericalTextureMap.cs b/Xbim.Presentation/Texturing/SphericalTextureMap.cs new file mode 100644 index 00000000..a80ade0a --- /dev/null +++ b/Xbim.Presentation/Texturing/SphericalTextureMap.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Media.Media3D; + +namespace Xbim.Presentation.Texturing +{ + public class SphericalTextureMap : ITextureMapping + { + /// + /// Calculates the texture by using the algorithm of spherical texture mapping + /// + /// vertices of the mesh which shall be textured + /// A spherical texture map. The indices of the texture map are related + /// to the indices of the given vertices + IEnumerable ITextureMapping.GetTextureMap(IEnumerable vertices) + { + //Spherical uv mapping + //calculate mid point of the shape + List textureCoordinates = new List(); + double minX, minY, minZ, maxX, maxY, maxZ; + minX = vertices.Select(x => x.X).Min(); + maxX = vertices.Select(x => x.X).Max(); + minY = vertices.Select(x => x.Y).Min(); + maxY = vertices.Select(x => x.Y).Max(); + minZ = vertices.Select(x => x.Z).Min(); + maxZ = vertices.Select(x => x.Z).Max(); + Vector3D midPoint = new Vector3D((minX + maxX) / 2, (minY + maxY) / 2, (minZ + maxZ) / 2); + + foreach (Point3D meshPoint in vertices) + { + Vector3D direction = (Vector3D)(meshPoint - midPoint); + double theta = Math.Acos(direction.Z / direction.Length); + if (direction.Z < 0) + { + theta = theta * -1; + } + + double phi; + if (direction.X > 0) + { + phi = Math.Atan(direction.Y / direction.X); + } + else if (direction.X == 0) + { + phi = Math.Sign(direction.Y) * Math.PI / 2.0; + } + else if (direction.X < 0 && direction.Y >= 0) + { + phi = Math.Atan(direction.Y / direction.X) + Math.PI; + } + else + { + phi = Math.Atan(direction.Y / direction.X) - Math.PI; + } + + textureCoordinates.Add(new Point(phi, theta)); + } + return textureCoordinates; + } + } +} diff --git a/Xbim.Presentation/WpfMaterial.cs b/Xbim.Presentation/WpfMaterial.cs index b2974d8a..df919fcc 100644 --- a/Xbim.Presentation/WpfMaterial.cs +++ b/Xbim.Presentation/WpfMaterial.cs @@ -1,6 +1,8 @@ using System; +using System.IO; using System.Text; using System.Windows.Media; +using System.Windows.Media.Imaging; using System.Windows.Media.Media3D; using Xbim.Ifc; using Xbim.ModelGeometry.Scene; @@ -56,6 +58,10 @@ public void CreateMaterial(XbimTexture texture) _description = "Texture " + colour; IsTransparent = colour.IsTransparent; } + else + { + _material = new MaterialGroup(); + } _material.Freeze(); } @@ -93,5 +99,23 @@ private static Material MaterialFromColour(XbimColour colour) public string Description => _description; public bool IsCreated => _material != null; + + /// + /// Create a Material from an image + /// + /// Absolut path to the image file + /// + public void WpfMaterialFromImageTexture(Uri imageUri) + { + BitmapImage imgSource = new BitmapImage(); + Stream imgStream = File.OpenRead(imageUri.LocalPath); + imgSource.BeginInit(); + imgSource.StreamSource = imgStream; + imgSource.EndInit(); + + Brush brush = new ImageBrush(imgSource); + _material = new DiffuseMaterial(brush); + _material.Freeze(); + } } } diff --git a/Xbim.Presentation/WpfMeshGeometry3D.cs b/Xbim.Presentation/WpfMeshGeometry3D.cs index 7651cdff..086bd586 100644 --- a/Xbim.Presentation/WpfMeshGeometry3D.cs +++ b/Xbim.Presentation/WpfMeshGeometry3D.cs @@ -3,7 +3,9 @@ using System.Globalization; using System.IO; using System.Linq; +using System.Reflection; using System.Text; +using System.Windows; using System.Windows.Media; using System.Windows.Media.Media3D; using Xbim.Common; @@ -11,6 +13,8 @@ using Xbim.Common.XbimExtensions; using Xbim.Ifc4.Interfaces; using Xbim.ModelGeometry.Scene; +using Xbim.Presentation.Extensions.Utility; +using Xbim.Presentation.Texturing; namespace Xbim.Presentation { @@ -18,8 +22,10 @@ public class WpfMeshGeometry3D : IXbimMeshGeometry3D { public GeometryModel3D WpfModel; private List _unfrozenPositions; - private List _unfrozenIndices; + private List _unfrozenTriangleIndices; private List _unfrozenNormals; + private List _unfrozenTextureCoordinates; + private ITextureMapping _textureMapping = new SphericalTextureMap(); XbimMeshFragmentCollection _meshes = new XbimMeshFragmentCollection(); private TriangleType _meshType; @@ -184,6 +190,17 @@ public static WpfMeshGeometry3D GetGeometry(EntitySelection selection, XbimModel return tgt; } + static WpfMeshGeometry3D() + { + _brushProperties = new List(); + Type emType = typeof(EmissiveMaterial); + _brushProperties.Add(emType.GetProperty(nameof(EmissiveMaterial.Brush))); + Type dfType = typeof(DiffuseMaterial); + _brushProperties.Add(dfType.GetProperty(nameof(DiffuseMaterial.Brush))); + Type spType = typeof(SpecularMaterial); + _brushProperties.Add(spType.GetProperty(nameof(SpecularMaterial.Brush))); + } + public WpfMeshGeometry3D() { WpfModel = new GeometryModel3D {Geometry = new MeshGeometry3D()}; @@ -234,6 +251,61 @@ public XbimMeshFragmentCollection Meshes } } + /// + /// for later Checking + /// + private static readonly List _brushProperties; + + /// + /// return if a texture is used for the front + /// + private bool HasFrontTexture + { + get + { + if (this.WpfModel != null + && this.WpfModel.Material != null) + { + Type aimedMatType = WpfModel.Material.GetType(); + PropertyInfo propInfoMaterial = _brushProperties.FirstOrDefault(x => x.ReflectedType.Equals(aimedMatType)); + if (propInfoMaterial != null) + { + Brush frontBrush = (Brush)propInfoMaterial.GetValue(WpfModel.Material); + if (frontBrush != null) + { + return frontBrush is ImageBrush; + } + } + } + return false; + } + } + + /// + /// return if a texture is used for the front + /// + private bool HasBackTexture + { + get + { + if (this.WpfModel != null + && this.WpfModel.BackMaterial != null) + { + Type aimedMatType = WpfModel.BackMaterial.GetType(); + PropertyInfo propInfoMaterial = _brushProperties.FirstOrDefault(x => x.ReflectedType.Equals(aimedMatType)); + if (propInfoMaterial != null) + { + Brush backBrush = (Brush)propInfoMaterial.GetValue(WpfModel.BackMaterial); + if (backBrush != null) + { + return backBrush is ImageBrush; + } + } + } + return false; + } + } + /// /// Do not use this rather create a XbimMeshGeometry3D first and construct this from it, appending WPF collections is slow /// @@ -287,7 +359,7 @@ public IList TriangleIndices { if (WpfModel?.Geometry == null) { - _unfrozenIndices = value.ToList(); + _unfrozenTriangleIndices = value.ToList(); } else Mesh.TriangleIndices = new Int32Collection(value); @@ -406,7 +478,7 @@ public int TriangleIndexCount { return 0; } - return Mesh == null ? _unfrozenIndices.Count : Mesh.TriangleIndices.Count; + return Mesh == null ? _unfrozenTriangleIndices.Count : Mesh.TriangleIndices.Count; } } @@ -678,7 +750,7 @@ public bool Read(string data, XbimMatrix3D? tr = null) //all vertices will be unique and have only one normal writtenVertices.Add(index, PositionCount); - _unfrozenIndices.Add(PositionCount); + _unfrozenTriangleIndices.Add(PositionCount); _unfrozenPositions.Add(vertexList[index]); _unfrozenNormals.Add(currentNormal); @@ -686,10 +758,10 @@ public bool Read(string data, XbimMatrix3D? tr = null) else //just add the index reference { if (_unfrozenNormals[alreadyWrittenAt] == currentNormal) - _unfrozenIndices.Add(alreadyWrittenAt); + _unfrozenTriangleIndices.Add(alreadyWrittenAt); else //we need another { - _unfrozenIndices.Add(PositionCount); + _unfrozenTriangleIndices.Add(PositionCount); _unfrozenPositions.Add(vertexList[index]); _unfrozenNormals.Add(currentNormal); } @@ -711,6 +783,7 @@ public void Add(byte[] mesh, short productTypeId, int productLabel, int geometry { var frag = new XbimMeshFragment(PositionCount, TriangleIndexCount, productTypeId, productLabel, geometryLabel, modelId); Read(mesh, transform); + TextureMapping(); frag.EndPosition = PositionCount - 1; frag.EndTriangleIndex = TriangleIndexCount - 1; _meshes.Add(frag); @@ -750,7 +823,7 @@ public void Read(byte[] mesh, XbimMatrix3D? transform = null) // _unfrozenPositions.Capacity += pts.Count; _unfrozenNormals.Capacity += pts.Count; - _unfrozenIndices.Capacity += idx.Count; + _unfrozenTriangleIndices.Capacity += idx.Count; foreach (var floatsArray in pts) { var wpfPosition = new Point3D(floatsArray[0], floatsArray[1], floatsArray[2]); @@ -765,12 +838,23 @@ public void Read(byte[] mesh, XbimMatrix3D? transform = null) } foreach (var index in idx) { - _unfrozenIndices.Add(index + indexBase); + _unfrozenTriangleIndices.Add(index + indexBase); } } } } - + + /// + /// Calculates and sets the texture mapping + /// + private void TextureMapping() + { + if (HasFrontTexture || HasBackTexture) + { + _unfrozenTextureCoordinates.AddRange(this._textureMapping.GetTextureMap(_unfrozenPositions)); + } + } + /// /// Ends an update and freezes the geometry /// @@ -779,17 +863,20 @@ public void EndUpdate() WpfModel.Geometry = new MeshGeometry3D(); Mesh.Positions = new Point3DCollection(_unfrozenPositions); _unfrozenPositions = null; - Mesh.TriangleIndices = new Int32Collection(_unfrozenIndices); - _unfrozenIndices = null; + Mesh.TriangleIndices = new Int32Collection(_unfrozenTriangleIndices); + _unfrozenTriangleIndices = null; Mesh.Normals = new Vector3DCollection(_unfrozenNormals); _unfrozenNormals = null; + Mesh.TextureCoordinates = new PointCollection(_unfrozenTextureCoordinates); + _unfrozenTextureCoordinates = null; Mesh.Freeze(); } public void BeginUpdate() { _unfrozenPositions = new List(Mesh.Positions); - _unfrozenIndices = new List(Mesh.TriangleIndices); + _unfrozenTriangleIndices = new List(Mesh.TriangleIndices); _unfrozenNormals = new List(Mesh.Normals); + _unfrozenTextureCoordinates = new List(Mesh.TextureCoordinates); WpfModel.Geometry = null; } From 7faafad6e929b336b71818166c5d489ec7445819 Mon Sep 17 00:00:00 2001 From: Mathias Artus Date: Thu, 22 Oct 2020 09:58:22 +0200 Subject: [PATCH 2/4] small correction to the calculation of u and v --- Xbim.Presentation/Texturing/SphericalTextureMap.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Xbim.Presentation/Texturing/SphericalTextureMap.cs b/Xbim.Presentation/Texturing/SphericalTextureMap.cs index a80ade0a..19e976a6 100644 --- a/Xbim.Presentation/Texturing/SphericalTextureMap.cs +++ b/Xbim.Presentation/Texturing/SphericalTextureMap.cs @@ -57,7 +57,10 @@ IEnumerable ITextureMapping.GetTextureMap(IEnumerable vertices) phi = Math.Atan(direction.Y / direction.X) - Math.PI; } - textureCoordinates.Add(new Point(phi, theta)); + double u = Math.Sin(theta) * Math.Cos(phi); + double v = Math.Sin(theta) * Math.Sin(phi); + + textureCoordinates.Add(new Point(u, v)); } return textureCoordinates; } From 3befdec34d9d1c7c998eadbae86be0f2b3ef6627 Mon Sep 17 00:00:00 2001 From: Mathias Artus Date: Thu, 22 Oct 2020 10:16:08 +0200 Subject: [PATCH 3/4] Calculation of the texture map parallelized --- Xbim.Presentation/Texturing/SphericalTextureMap.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Xbim.Presentation/Texturing/SphericalTextureMap.cs b/Xbim.Presentation/Texturing/SphericalTextureMap.cs index 19e976a6..f085da53 100644 --- a/Xbim.Presentation/Texturing/SphericalTextureMap.cs +++ b/Xbim.Presentation/Texturing/SphericalTextureMap.cs @@ -20,7 +20,7 @@ IEnumerable ITextureMapping.GetTextureMap(IEnumerable vertices) { //Spherical uv mapping //calculate mid point of the shape - List textureCoordinates = new List(); + Point[] textureCoordinates = new Point[vertices.Count()]; double minX, minY, minZ, maxX, maxY, maxZ; minX = vertices.Select(x => x.X).Min(); maxX = vertices.Select(x => x.X).Max(); @@ -30,8 +30,10 @@ IEnumerable ITextureMapping.GetTextureMap(IEnumerable vertices) maxZ = vertices.Select(x => x.Z).Max(); Vector3D midPoint = new Vector3D((minX + maxX) / 2, (minY + maxY) / 2, (minZ + maxZ) / 2); - foreach (Point3D meshPoint in vertices) + //for (int verticeIndex = 0; verticeIndex < textureCoordinates.Length; verticeIndex++) + Parallel.For(0, textureCoordinates.Length, (verticeIndex) => { + Point3D meshPoint = vertices.ElementAt(verticeIndex); Vector3D direction = (Vector3D)(meshPoint - midPoint); double theta = Math.Acos(direction.Z / direction.Length); if (direction.Z < 0) @@ -60,8 +62,8 @@ IEnumerable ITextureMapping.GetTextureMap(IEnumerable vertices) double u = Math.Sin(theta) * Math.Cos(phi); double v = Math.Sin(theta) * Math.Sin(phi); - textureCoordinates.Add(new Point(u, v)); - } + textureCoordinates[verticeIndex] = new Point(u, v); + }); return textureCoordinates; } } From 29cdac76673ae548bbdbea878c6d549f507fb5dc Mon Sep 17 00:00:00 2001 From: Mathias Artus Date: Thu, 29 Oct 2020 10:05:25 +0100 Subject: [PATCH 4/4] Implementation of the TextureCoordinateFeature --- .../LayerStyling/SurfaceLayerStyler.cs | 44 ++++++++++- .../Texturing/ITextureMapping.cs | 9 ++- .../ManualTriangularTextureMapping.cs | 62 +++++++++++++++ .../Texturing/SphericalTextureMap.cs | 27 +++++-- .../Texturing/TextureMapGenerationMethod.cs | 75 +++++++++++++++++++ .../Texturing/TextureMappingFactory.cs | 62 +++++++++++++++ Xbim.Presentation/WpfMaterial.cs | 10 +++ Xbim.Presentation/WpfMeshGeometry3D.cs | 75 ++++--------------- 8 files changed, 291 insertions(+), 73 deletions(-) create mode 100644 Xbim.Presentation/Texturing/ManualTriangularTextureMapping.cs create mode 100644 Xbim.Presentation/Texturing/TextureMapGenerationMethod.cs create mode 100644 Xbim.Presentation/Texturing/TextureMappingFactory.cs diff --git a/Xbim.Presentation/LayerStyling/SurfaceLayerStyler.cs b/Xbim.Presentation/LayerStyling/SurfaceLayerStyler.cs index 92ffa8b7..c92d2e24 100644 --- a/Xbim.Presentation/LayerStyling/SurfaceLayerStyler.cs +++ b/Xbim.Presentation/LayerStyling/SurfaceLayerStyler.cs @@ -12,6 +12,7 @@ using Xbim.Common.Geometry; using Xbim.Ifc; using Xbim.Ifc4.Interfaces; +using Xbim.Presentation.Texturing; namespace Xbim.Presentation.LayerStyling { @@ -150,12 +151,31 @@ public XbimScene BuildScene(IModel model, XbimMa wpfMesh.Read(((XbimShapeGeometry) shapeGeom).ShapeData); break; } + repeatedShapeGeometries.Add(shapeInstance.ShapeGeometryLabel, wpfMesh); var mg = new GeometryModel3D(wpfMesh, materialsByStyleId[styleId]); mg.SetValue(FrameworkElement.TagProperty, new XbimInstanceHandle(model, shapeInstance.IfcProductLabel, shapeInstance.IfcTypeId)); mg.BackMaterial = mg.Material; mg.Transform = XbimMatrix3D.Multiply(shapeInstance.Transformation, modelTransform).ToMatrixTransform3D(); + + //manual Texturemapping + if (materialsByStyleId[styleId].HasTexture + && mg.Geometry is MeshGeometry3D mesh3D) + { + ITextureMapping tMapping; + if (materialsByStyleId[styleId].IfcTextureCoordinate != null) + { + tMapping = TextureMappingFactory.CreateTextureMapping(materialsByStyleId[styleId].IfcTextureCoordinate); + } + else + { + Logger.LogWarning(0, "No IfcTextureCoordinate is defined for style " + styleId + ". Spherical mapping is used."); + tMapping = new SphericalTextureMap(); + } + mesh3D.TextureCoordinates.Concat(tMapping.GetTextureMap(mesh3D.Positions, mesh3D.Normals, mesh3D.TriangleIndices)); + } + if (materialsByStyleId[styleId].IsTransparent) tmpTransparentsGroup.Children.Add(mg); else @@ -183,12 +203,27 @@ public XbimScene BuildScene(IModel model, XbimMa if (shapeGeom.Format != (byte) XbimGeometryType.PolyhedronBinary) continue; var transform = XbimMatrix3D.Multiply(shapeInstance.Transformation, modelTransform); + ITextureMapping textureMethod = null; + if (materialsByStyleId[styleId].HasTexture) + { + if (materialsByStyleId[styleId].IfcTextureCoordinate != null) + { + textureMethod = TextureMappingFactory.CreateTextureMapping(materialsByStyleId[styleId].IfcTextureCoordinate); + } + else + { + Logger.LogWarning(0, "No texture mapping method defined for style " + styleId + ". Spherical mapping is used."); + textureMethod = new SphericalTextureMap(); + } + } targetMergeMeshByStyle.Add( shapeGeom.ShapeData, shapeInstance.IfcTypeId, shapeInstance.IfcProductLabel, shapeInstance.InstanceLabel, transform, - (short) model.UserDefinedId); + (short) model.UserDefinedId, + textureMethod); + } } } @@ -228,7 +263,7 @@ protected IEnumerable GetShapeInstancesToRender(IGeometryStor protected static WpfMeshGeometry3D GetNewStyleMesh(WpfMaterial wpfMaterial, Model3DGroup tmpTransparentsGroup, Model3DGroup tmpOpaquesGroup) { - var mg = new WpfMeshGeometry3D(wpfMaterial, wpfMaterial); + var mg = new WpfMeshGeometry3D(wpfMaterial, wpfMaterial, wpfMaterial.IfcTextureCoordinate); mg.WpfModel.SetValue(FrameworkElement.TagProperty, mg); mg.BeginUpdate(); @@ -268,6 +303,11 @@ protected WpfMaterial GetWpfMaterial(IModel model, int styleId) { Logger.LogWarning(0, "Invalid Uri " + imageTexture.URLReference + " (bad formatted or file not found).", imageTexture); } + + if (imageTexture.IsMappedBy != null) + { + wpfMaterial.IfcTextureCoordinate = imageTexture.IsMappedBy.FirstOrDefault(); + } isTexture = true; } } diff --git a/Xbim.Presentation/Texturing/ITextureMapping.cs b/Xbim.Presentation/Texturing/ITextureMapping.cs index fa52a5a8..b8c78fec 100644 --- a/Xbim.Presentation/Texturing/ITextureMapping.cs +++ b/Xbim.Presentation/Texturing/ITextureMapping.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using System.Windows; using System.Windows.Media.Media3D; +using Xbim.Common; namespace Xbim.Presentation.Texturing { @@ -13,8 +14,12 @@ public interface ITextureMapping /// /// returns the texture map for a given set of vertices /// - /// Vertices of the related mesh /// a texture map for the related mesh - IEnumerable GetTextureMap(IEnumerable vertices); + IEnumerable GetTextureMap(IEnumerable vertices, IEnumerable normals, IEnumerable triangles); + + /// + /// Method for the Texturing + /// + TextureMapGenerationMethod TexturingMethod {get;} } } diff --git a/Xbim.Presentation/Texturing/ManualTriangularTextureMapping.cs b/Xbim.Presentation/Texturing/ManualTriangularTextureMapping.cs new file mode 100644 index 00000000..9087e361 --- /dev/null +++ b/Xbim.Presentation/Texturing/ManualTriangularTextureMapping.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Media.Media3D; +using Xbim.Common; +using Xbim.Ifc4.Interfaces; +using Xbim.Ifc4.MeasureResource; + +namespace Xbim.Presentation.Texturing +{ + public class ManualTriangularTextureMapping : ITextureMapping + { + /// + /// Manual map for texture coordinates. The index of the several vectors are related to the vertice index provided at GetTextureMap + /// + private IIfcIndexedTriangleTextureMap _ifcTextMap; + private int _numberOfVertices; + + public ManualTriangularTextureMapping(IIfcIndexedTriangleTextureMap textMap, int numberOfVertices) + { + _ifcTextMap = textMap; + _numberOfVertices = numberOfVertices; + } + + /// + /// Used Method for Texturing + /// + public TextureMapGenerationMethod TexturingMethod + { + get + { + return TextureMapGenerationMethod.MANUALTRIANGULAR; + } + } + + /// + /// returns the manual texture map + /// + /// + public IEnumerable GetTextureMap(IEnumerable vertices, IEnumerable normals, IEnumerable triangles) + { + IIfcTriangulatedFaceSet faceSet = _ifcTextMap.MappedTo as IIfcTriangulatedFaceSet; + Point[] result = new Point[_numberOfVertices]; + for (int triangleIdx = 0; triangleIdx < _ifcTextMap.TexCoordIndex.Count; triangleIdx++) + { + var texCoordTriangle = _ifcTextMap.TexCoordIndex[triangleIdx]; + for (int verticeIdx = 0; verticeIdx < texCoordTriangle.Count; verticeIdx++) + { + int texCoordIdx = (int)texCoordTriangle[verticeIdx] - 1; //ifc indexing is one based + int verticeRefIdx = (int)faceSet.CoordIndex[triangleIdx][verticeIdx] - 1; //ifc indexing is one based + + result[verticeRefIdx] = new Point(_ifcTextMap.TexCoords.TexCoordsList[texCoordIdx][0], _ifcTextMap.TexCoords.TexCoordsList[texCoordIdx][1]); + } + } + + return result; + } + } +} diff --git a/Xbim.Presentation/Texturing/SphericalTextureMap.cs b/Xbim.Presentation/Texturing/SphericalTextureMap.cs index f085da53..9ca7fe83 100644 --- a/Xbim.Presentation/Texturing/SphericalTextureMap.cs +++ b/Xbim.Presentation/Texturing/SphericalTextureMap.cs @@ -1,26 +1,36 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Media.Media3D; +using Xbim.Common; namespace Xbim.Presentation.Texturing { public class SphericalTextureMap : ITextureMapping { + /// + /// Used Method for Texturing + /// + public TextureMapGenerationMethod TexturingMethod + { + get + { + return TextureMapGenerationMethod.SPHERE; + } + } + /// /// Calculates the texture by using the algorithm of spherical texture mapping /// - /// vertices of the mesh which shall be textured /// A spherical texture map. The indices of the texture map are related /// to the indices of the given vertices - IEnumerable ITextureMapping.GetTextureMap(IEnumerable vertices) + public IEnumerable GetTextureMap(IEnumerable vertices, IEnumerable normals, IEnumerable triangles) { + Point[] textureCoordinates = new Point[vertices.Count()]; //Spherical uv mapping //calculate mid point of the shape - Point[] textureCoordinates = new Point[vertices.Count()]; double minX, minY, minZ, maxX, maxY, maxZ; minX = vertices.Select(x => x.X).Min(); maxX = vertices.Select(x => x.X).Max(); @@ -30,7 +40,6 @@ IEnumerable ITextureMapping.GetTextureMap(IEnumerable vertices) maxZ = vertices.Select(x => x.Z).Max(); Vector3D midPoint = new Vector3D((minX + maxX) / 2, (minY + maxY) / 2, (minZ + maxZ) / 2); - //for (int verticeIndex = 0; verticeIndex < textureCoordinates.Length; verticeIndex++) Parallel.For(0, textureCoordinates.Length, (verticeIndex) => { Point3D meshPoint = vertices.ElementAt(verticeIndex); @@ -38,7 +47,7 @@ IEnumerable ITextureMapping.GetTextureMap(IEnumerable vertices) double theta = Math.Acos(direction.Z / direction.Length); if (direction.Z < 0) { - theta = theta * -1; + theta *= -1; } double phi; @@ -59,8 +68,10 @@ IEnumerable ITextureMapping.GetTextureMap(IEnumerable vertices) phi = Math.Atan(direction.Y / direction.X) - Math.PI; } - double u = Math.Sin(theta) * Math.Cos(phi); - double v = Math.Sin(theta) * Math.Sin(phi); + //double u = Math.Sin(theta) * Math.Cos(phi); + //double v = Math.Sin(theta) * Math.Sin(phi); + double u = phi; + double v = theta; textureCoordinates[verticeIndex] = new Point(u, v); }); diff --git a/Xbim.Presentation/Texturing/TextureMapGenerationMethod.cs b/Xbim.Presentation/Texturing/TextureMapGenerationMethod.cs new file mode 100644 index 00000000..d481a6c5 --- /dev/null +++ b/Xbim.Presentation/Texturing/TextureMapGenerationMethod.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Xbim.Presentation.Texturing +{ + /// + /// Methods to generate a texture + /// + public enum TextureMapGenerationMethod + { + /// + /// Manual mapping + /// + MANUALTRIANGULAR, + + /// + /// direct mapping of vertices and coordinates + /// + MANUALDIRECT, + + /// + /// Spherical mapping + /// + SPHERE, + + /// + /// Camera space normal mapping + /// + CAMERASPACENORMAL, + + /// + /// camera space position normal mapping + /// + CAMERASPACEPOSITION, + + /// + /// camera space reflection vector mapping + /// + CAMERASPACEREFLECTIONVECTOR, + SPHERE_LOCAL, + + /// + /// + /// + COORD, + + /// + /// + /// + COORD_EYE, + + /// + /// + /// + NOISE, + + /// + /// + /// + NOISE_EYE, + + /// + /// + /// + SPHERE_REFLECT, + + /// + /// + /// + SPHERE_REFLECT_LOCAL + } +} diff --git a/Xbim.Presentation/Texturing/TextureMappingFactory.cs b/Xbim.Presentation/Texturing/TextureMappingFactory.cs new file mode 100644 index 00000000..0b59b930 --- /dev/null +++ b/Xbim.Presentation/Texturing/TextureMappingFactory.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Windows.Media.Media3D; +using Xbim.Ifc4.Interfaces; + +namespace Xbim.Presentation.Texturing +{ + public static class TextureMappingFactory + { + /// + /// Create a spherical texture mapping + /// + /// A spherical mapping object for the given vertices + public static ITextureMapping CreateSphericalTextureMapping() + { + return new SphericalTextureMap(); + } + + /// + /// create a new manual texture mapping + /// + /// + /// + /// + public static ITextureMapping CreateManualTextureMapping(IIfcIndexedTriangleTextureMap textMap, int numberOfVertices) + { + return new ManualTriangularTextureMapping(textMap, numberOfVertices); + } + + /// + /// create the corresponding Texturemapping to a related texture coordinate element + /// + /// + /// + public static ITextureMapping CreateTextureMapping(IIfcTextureCoordinate textureCoordinate) + { + if (textureCoordinate is IIfcTextureMap) + { + return null; + } + else if (textureCoordinate is IIfcTextureCoordinateGenerator generator) + { + TextureMapGenerationMethod method = (TextureMapGenerationMethod)Enum.Parse(typeof(TextureMapGenerationMethod), generator.Mode); + switch (method) + { + case TextureMapGenerationMethod.SPHERE: + return new SphericalTextureMap(); + default: + return null; + } + } + else if (textureCoordinate is IIfcIndexedTriangleTextureMap triTextureMap) + { + return new ManualTriangularTextureMapping(triTextureMap, triTextureMap.MappedTo.Coordinates.CoordList.Count); + } + else + { + return null; + } + } + } +} diff --git a/Xbim.Presentation/WpfMaterial.cs b/Xbim.Presentation/WpfMaterial.cs index df919fcc..f824f652 100644 --- a/Xbim.Presentation/WpfMaterial.cs +++ b/Xbim.Presentation/WpfMaterial.cs @@ -1,10 +1,13 @@ using System; +using System.Collections.Generic; using System.IO; +using System.Linq; using System.Text; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Media.Media3D; using Xbim.Ifc; +using Xbim.Ifc4.Interfaces; using Xbim.ModelGeometry.Scene; namespace Xbim.Presentation @@ -14,6 +17,12 @@ public class WpfMaterial : IXbimRenderMaterial Material _material; string _description; public bool IsTransparent; + public IIfcTextureCoordinate IfcTextureCoordinate { get; set; } + + /// + /// Has the material a texture + /// + public bool HasTexture { get; private set; } = false; // empty constructor public WpfMaterial() @@ -115,6 +124,7 @@ public void WpfMaterialFromImageTexture(Uri imageUri) Brush brush = new ImageBrush(imgSource); _material = new DiffuseMaterial(brush); + HasTexture = true; _material.Freeze(); } } diff --git a/Xbim.Presentation/WpfMeshGeometry3D.cs b/Xbim.Presentation/WpfMeshGeometry3D.cs index 086bd586..74509d56 100644 --- a/Xbim.Presentation/WpfMeshGeometry3D.cs +++ b/Xbim.Presentation/WpfMeshGeometry3D.cs @@ -25,7 +25,6 @@ public class WpfMeshGeometry3D : IXbimMeshGeometry3D private List _unfrozenTriangleIndices; private List _unfrozenNormals; private List _unfrozenTextureCoordinates; - private ITextureMapping _textureMapping = new SphericalTextureMap(); XbimMeshFragmentCollection _meshes = new XbimMeshFragmentCollection(); private TriangleType _meshType; @@ -219,9 +218,10 @@ public WpfMeshGeometry3D(IXbimMeshGeometry3D mesh) _meshes = new XbimMeshFragmentCollection(mesh.Meshes); } - public WpfMeshGeometry3D(Material material, Material backMaterial = null) + public WpfMeshGeometry3D(Material material, Material backMaterial = null, IIfcTextureCoordinate ifcTextureCoordinates = null) { WpfModel = new GeometryModel3D(new MeshGeometry3D(), material); + IfcTextureCoordinates = ifcTextureCoordinates; if (backMaterial != null) WpfModel.BackMaterial = backMaterial; } @@ -252,59 +252,14 @@ public XbimMeshFragmentCollection Meshes } /// - /// for later Checking - /// - private static readonly List _brushProperties; - - /// - /// return if a texture is used for the front + /// IFC texture Coordinates /// - private bool HasFrontTexture - { - get - { - if (this.WpfModel != null - && this.WpfModel.Material != null) - { - Type aimedMatType = WpfModel.Material.GetType(); - PropertyInfo propInfoMaterial = _brushProperties.FirstOrDefault(x => x.ReflectedType.Equals(aimedMatType)); - if (propInfoMaterial != null) - { - Brush frontBrush = (Brush)propInfoMaterial.GetValue(WpfModel.Material); - if (frontBrush != null) - { - return frontBrush is ImageBrush; - } - } - } - return false; - } - } + public IIfcTextureCoordinate IfcTextureCoordinates; /// - /// return if a texture is used for the front + /// for later Checking /// - private bool HasBackTexture - { - get - { - if (this.WpfModel != null - && this.WpfModel.BackMaterial != null) - { - Type aimedMatType = WpfModel.BackMaterial.GetType(); - PropertyInfo propInfoMaterial = _brushProperties.FirstOrDefault(x => x.ReflectedType.Equals(aimedMatType)); - if (propInfoMaterial != null) - { - Brush backBrush = (Brush)propInfoMaterial.GetValue(WpfModel.BackMaterial); - if (backBrush != null) - { - return backBrush is ImageBrush; - } - } - } - return false; - } - } + private static readonly List _brushProperties; /// /// Do not use this rather create a XbimMeshGeometry3D first and construct this from it, appending WPF collections is slow @@ -779,11 +734,15 @@ public bool Read(string data, XbimMatrix3D? tr = null) return true; } - public void Add(byte[] mesh, short productTypeId, int productLabel, int geometryLabel, XbimMatrix3D? transform = null, short modelId = 0) + public void Add(byte[] mesh, short productTypeId, int productLabel, int geometryLabel, XbimMatrix3D? transform = null, short modelId = 0, + ITextureMapping textureMappingMethod = null) { var frag = new XbimMeshFragment(PositionCount, TriangleIndexCount, productTypeId, productLabel, geometryLabel, modelId); Read(mesh, transform); - TextureMapping(); + if (textureMappingMethod != null) + { + AddTextureMapping(textureMappingMethod.GetTextureMap(this._unfrozenPositions, this._unfrozenNormals, this._unfrozenTriangleIndices)); + } frag.EndPosition = PositionCount - 1; frag.EndTriangleIndex = TriangleIndexCount - 1; _meshes.Add(frag); @@ -844,15 +803,9 @@ public void Read(byte[] mesh, XbimMatrix3D? transform = null) } } - /// - /// Calculates and sets the texture mapping - /// - private void TextureMapping() + public void AddTextureMapping(IEnumerable textureCoordinates) { - if (HasFrontTexture || HasBackTexture) - { - _unfrozenTextureCoordinates.AddRange(this._textureMapping.GetTextureMap(_unfrozenPositions)); - } + this._unfrozenTextureCoordinates.AddRange(textureCoordinates); } ///