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); }
// This method created curve with tube lines but instead of using TubeLineVisual3D // here we create a series of MeshGeometry3D objects - one for each line segment. // Then we combine all those segments into one MeshGeometry3D and use it to create GeometryModel3D. // This can greatly improve performance because GeometryModel3D can be drawn with only one draw call on graphics card. // What is more is that the GeometryModel3D can be frozen. // This means that this method can be executed on background thread and then the GeometryModel3D can be passed to UI thread. private void CreateCurveWithMeshes() { // Create curve through those points var controlPoints = new Point3D[] { new Point3D(100, 50, 20), new Point3D(250, 50, 0), new Point3D(250, 50, 200), new Point3D(350, 50, 200) }; var bezierCurve = Ab3d.Utilities.BezierCurve.CreateFromCurvePositions(controlPoints); // To create curve through specified points we must first convert the points into a bezierCurve (curve that has tangents defined for each point) var curvePositions = bezierCurve.CreateBezierCurve(_curveSegmentsBetweenControlPoints); int selectedSegmentsCount = GetSelectedSegmentsCount(); // meshes list will hold MeshGeometry3D for each curve segment var meshes = new List <MeshGeometry3D>(curvePositions.Count); Point3D previousCurvePosition = curvePositions[0]; for (int i = 1; i < curvePositions.Count; i++) { Point3D curvePosition = curvePositions[i]; var tubeLineMesh3D = new Ab3d.Meshes.TubeLineMesh3D(startPosition: previousCurvePosition, endPosition: curvePosition, radius: 1, segments: selectedSegmentsCount, generateTextureCoordinates: false); var meshGeometry = tubeLineMesh3D.Geometry; meshes.Add(meshGeometry); previousCurvePosition = curvePosition; } // Combine all meshes into one MeshGeometry3D var combinedMeshGeometry = Ab3d.Utilities.MeshUtils.CombineMeshes(meshes); // Create one GeometryModel3D var geometryModel3D = new GeometryModel3D(combinedMeshGeometry, CreateMaterial(Brushes.GreenYellow)); geometryModel3D.Freeze(); MeshTubeLinesVisual.Content = geometryModel3D; }
private void CreateInstancedTubePath() { // Create curve through those points var controlPoints = new Point3D[] { new Point3D(-200, 50, 150), new Point3D(0, 50, 20), new Point3D(150, 50, 0), new Point3D(150, 50, 200), new Point3D(250, 50, 200) }; // To create curve through specified points we must first convert the points into a bezierCurve (curve that has tangents defined for each point). // The curve is created with 10 points per segments - 10 points between two control points. var bezierCurve = Ab3d.Utilities.BezierCurve.CreateFromCurvePositions(controlPoints); var curvePositions = bezierCurve.CreateBezierCurve(positionsPerSegment: 10); // Convert Point3D to Vector3 var dxCurvePositions = curvePositions.Select(p => p.ToVector3()).ToList(); // Setup InstanceData var instanceData = new InstanceData[curvePositions.Count]; // 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); }