Avoiding seam in 3D cylinder model

3d, texture-mapping, textures, uv-mapping, wpf

Solution

When you create your image brush try setting the TileMode to TileMode.Tile and ViewportUnits to BrushMappingMode.Absolute. If that still doesn't work then post a follow-up comment here and I'll try to reproduce it on my end.

Problem

I have this texture representing internal area of a pipe: I have created a simple cylinder model (`GeometryModel3D`) by dissecting the above texture to a grid of points and than wrapping this to form a cylinder, then mapping the above texture to it (each square on a grid having two triangles): The left and right edges of the texture meet at the above black seam line, which is unwanted. I could not use single vertex point for smooth continuation there, because that point corresponds to both 0 and 360 degrees which is single angle, but two distinct points on edges of the 2D texture. So I have used pairs of vertices on the same location but each corresponding to different point in the source texture. Is there anything I can do to hide the seam line? Model creation code: ``` private void SceneViewerWindowOnLoaded(object sender, RoutedEventArgs e) { var imageSource = new BitmapImage(new Uri("pack://application:,,,/Resources/out1.jpg")); var meshGeometry3D = new MeshGeometry3D(); double circumference = imageSource.PixelWidth; double radius = (circumference / (2.0 * Math.PI)); double angleSegment = (2.0 * Math.PI / SegmentCountTrans); double sizeSegmentLong = ((double)imageSource.PixelHeight / SegmentCountLong); double sizeSegmentTrans = ((double)imageSource.PixelWidth / SegmentCountTrans); for (int indexSegmentLong = 0; indexSegmentLong < SegmentCountLong; indexSegmentLong++) { double depth = (indexSegmentLong * sizeSegmentLong); for (int indexSegmentTrans = 0; indexSegmentTrans < SegmentCountTrans; indexSegmentTrans++) { meshGeometry3D.Positions.Add(GetVertexPosition(indexSegmentTrans, depth, radius, angleSegment)); meshGeometry3D.TextureCoordinates.Add(new Point(indexSegmentTrans * sizeSegmentTrans, depth)); } // add one extra vertex representing 360 degrees for complete wrap-around meshGeometry3D.Positions.Add(GetVertexPosition(SegmentCountTrans, depth, radius, angleSegment)); meshGeometry3D.TextureCoordinates.Add(new Point(SegmentCountTrans * sizeSegmentTrans, depth)); } meshGeometry3D.TriangleIndices.Clear(); for (int indexSegmentLong = 0; indexSegmentLong < (SegmentCountLong - 1); indexSegmentLong++) { for (int indexSegmentTrans = 0; indexSegmentTrans < SegmentCountTrans; indexSegmentTrans++) { int indexCurrent = (indexSegmentLong * (SegmentCountTrans + 1) + indexSegmentTrans); meshGeometry3D.TriangleIndices.Add(indexCurrent); meshGeometry3D.TriangleIndices.Add(indexCurrent + 1); meshGeometry3D.TriangleIndices.Add(indexCurrent + SegmentCountTrans + 1); meshGeometry3D.TriangleIndices.Add(indexCurrent + SegmentCountTrans + 1); meshGeometry3D.TriangleIndices.Add(indexCurrent + 1); meshGeometry3D.TriangleIndices.Add(indexCurrent + SegmentCountTrans + 2); } } var geometryModel3D = new GeometryModel3D { Geometry = meshGeometry3D, Material = new DiffuseMaterial { Brush = new ImageBrush(imageSource) } }; this.SceneViewer.Model = geometryModel3D; } private static Point3D GetVertexPosition(int indexSegmentAngle, double depth, double radius, double angleSegment) { double angle = (StartAngle + indexSegmentAngle * angleSegment); return new Point3D( radius * Math.Cos(angle), radius * Math.Sin(angle), -depth); } ``` XAML code for the `Viewport3D` element containing the model: ``` <Viewport3D x:Name="Viewport3D"> <Viewport3D.Camera> <PerspectiveCamera x:Name="Camera" Position="0.0,0.0,0.0" LookDirection="0.0,0.0,-1.0" UpDirection="0.0,1.0,0.0" FieldOfView="90"/> </Viewport3D.Camera> <ModelVisual3D> <ModelVisual3D.Content> <AmbientLight Color="White"/> </ModelVisual3D.Content> </ModelVisual3D> <ModelVisual3D x:Name="ModelVisualModel"/> </Viewport3D> ```

Original source