3
votes

I am trying to visualize a point cloud of ~170000 points using WPF's Viewport3D control. After generating the 3D point coordinates I create a triangle with a certain size at each point and add it to a Model3DGroup object which I append to my Viewport aftwerwards.

My problem is that the code below responsible for this takes 3 seconds alone to run. After the Model3DGroup has been added to the Viewport the UI is frozen for another 3-5 seconds more.

How can I make this work faster? Also if Viewport3D can't handle models of this number can anyone recommend an alternative way of visualizing a point cloud in a WPF control?

        viewport.Children.Clear();

        Model3DGroup triangles = new Model3DGroup();
        foreach (Point3D point in workspace.PointCloud)
        {
            double x = point.X;
            double y = point.Y;
            double z = point.Z;

            Point3D p1 = new Point3D(x + 0.005, y, z);
            Point3D p2 = new Point3D(x, y + 0.005, z);

            MeshGeometry3D mymesh = new MeshGeometry3D();
            mymesh.Positions.Add(point);
            mymesh.Positions.Add(p1);
            mymesh.Positions.Add(p2);
            mymesh.TriangleIndices.Add(0);
            mymesh.TriangleIndices.Add(1);
            mymesh.TriangleIndices.Add(2);

            Vector3D Normal = GeometryHelper.CalculateTraingleNormal(p0, p1, p2);
            mymesh.Normals.Add(Normal);
            mymesh.Normals.Add(Normal);
            mymesh.Normals.Add(Normal);

            Material Material = new DiffuseMaterial(
                new SolidColorBrush(Colors.Red) { Opacity = 0.5 });
            GeometryModel3D model = new GeometryModel3D(
                mymesh, Material);

            triangles.Children.Add(model);
        }

        ModelVisual3D modelVisual = new ModelVisual3D();
        modelVisual.Content = triangles;
        viewport.Children.Add(modelVisual);
2
Even after your optimization efforts, I don't believe you will see the results you are searching for. You may be better served with a pure native solution and D3D. Looks like a fun project. Good luck. - Jeff

2 Answers

1
votes

Per This Page:

Create different models only when they require different Materials or Transforms. Otherwise, try to coalesce many GeometryModel3D instances with the same Materials and Transforms into a few larger GeometryModel3D and MeshGeometry3D instances.

Instead of creating multiple MeshGeometry3D create just one and add it to a single GeometryModel3D. Add that single GeometeryModel3D to your ModelVisual3D. This should significantly improve the performance of your model (I've experienced this myself).

For additional speed improvements you may be able to create your positions in parallel (Parallel.ForEach Example)

      List<Point3D> points = new List<Point3D>();
      Parallel.ForEach(workspace.PointCloud, point =>
      {
        //Do Work
      }
      );
      Point3DCollection p3d = new Point3DCollection(points);
      mymesh.Positions = p3d;

I haven't tested this code. There may be some additional work required to get it to work in parallel. Be sure to create the points in triplets, otherwise you'll get points in a very weird order which will create some crazy triangles.

You can skip the specifying of TriangleIndices as they are inferred if not specified. Although I doubt that will buy you much processing time and I'm unsure if it has performance impacts later.

0
votes

I had an issue similar to this and solved it by using https://github.com/jeremjlr/MurphyDisplay

It has examples, can be embedded in WPF, works perfectly to display point clouds and can do other things.