private InstancedMeshGeometryVisual3D AddInstancedTubePath(Point3DCollection spiralPositionCollection, Color4 tubeColor) { // Setup InstanceData var instanceData = new InstanceData[spiralPositionCollection.Count]; // Convert to list of Vector3 var dxCurvePositions = spiralPositionCollection.Select(p => p.ToVector3()).ToList(); // NOTE: // When a tube path is created from a lot of positions, // then it is worth to transform the following loop into Parallel.For loop. var startPosition = dxCurvePositions[0]; for (int i = 1; i < dxCurvePositions.Count; i++) { var endPosition = dxCurvePositions[i]; var direction = endPosition - startPosition; var length = direction.Length(); // length will be used for x scale var scale = new Vector3(length, 1, 1); //direction.Normalize(); // Because we already have length, we can quickly normalize with simply dividing by length direction /= length; instanceData[i].World = Common.MatrixUtils.GetMatrixFromNormalizedDirection(direction, startPosition, scale); instanceData[i].DiffuseColor = Color4.White; startPosition = endPosition; } // Create tube mesh with normalized radius (=1) and from (0,0,0) to (1,0,0). // This mesh is then transformed to connect positions along the path var tubeLineMesh3D = new Ab3d.Meshes.TubeLineMesh3D(startPosition: new Point3D(0, 0, 0), endPosition: new Point3D(1, 0, 0), radius: 1, segments: 8, generateTextureCoordinates: false).Geometry; // Create InstancedMeshGeometryVisual3D var instancedMeshGeometryVisual3D = new InstancedMeshGeometryVisual3D(tubeLineMesh3D); instancedMeshGeometryVisual3D.InstancesData = instanceData; // Set IsSolidColorMaterial to render tube instances with solid color without any shading based on lighting instancedMeshGeometryVisual3D.IsSolidColorMaterial = true; // Add instancedMeshGeometryVisual3D to the scene MainViewport.Children.Add(instancedMeshGeometryVisual3D); return(instancedMeshGeometryVisual3D); }