Group thousands of Quads into a single Mesh object

Suppose you have a big set of Quads (hundreds of thousands) like in the following image:

Capture.PNG

If you add individual Quad entities to the ViewportLayout you would get a very bad framerate due to the huge number of entities.

A better approach is to create a single Mesh object from the big set of Quads, this way you would gain the benefits of using hardware acceleration by creating a single display list (or vertex buffer object as shown below) for the whole set of Quads.

If you want to individually select the quad entities (in order to transform, delete, or perform some other actions on them), you should override some methods (as shown below) to allow the selection of the quads inside the mesh.

For this purpose, you should keep a keep a list of the selected quads inside the mesh and, in order to draw them, override the Draw method so that it first draws all the quads and then draws the selected ones over it.

In attachment there are two projects with the code for Eyeshot6 and Eyeshot 7: these samples create a single Mesh object made of two quads and implement the selection independently for each quad.

The main part is the MyMesh class derived from Mesh, created for this purpose.

It uses the Vertex Buffer Objects (if they are available on the graphics card) to speed up the Entity.Compile() and it overrides the following methods to support the drawing of the Quads and their selection

  • Compile(), Draw(), DrawSelected(),
  • IsCrossing(), InsideOrCrossingFrustum(), ThroughTriangle(), IsCrossingScreenPolygon(), InsideOrCrossingScreenPolygon(), ThroughTriangleScreenPolygon(), AllVerticesInFrustum(), AllVerticesInScreenPolygon(): to compute the quads selected by the various selection modes.

  • DrawForSelection(): necessary for the Quads selection in the SelectVisiblebyPick and SelectVisibleByBox selection modes.
For the visible selection, you should derive the ViewportLayout class and override the GetVisibleEntitiesFromBackBuffer() method to get the indices of the selected quads and assign them to the MyMesh object.

 

    class MyViewportLayout : ViewportLayout 
    { 
        protected override int[] GetVisibleEntitiesFromBackBuffer<T>(IList<T> entList, Viewport viewport, Rectangle selectionBox, bool firstOnly)
        { 
            if (entList != Entities) 

                return base.GetVisibleEntitiesFromBackBuffer(entList, viewport, selectionBox, firstOnly);

            // Reads the visible Quads from the back buffer and selects them
            for (int i = 0; i < entList.Count; i++)
            { 
                if (entList[i] is MyMesh)
                { 
                    MyMesh myMesh = entList[i] as MyMesh; 
                    int[] indices = base.GetVisibleEntitiesFromBackBuffer(entList, viewport, selectionBox, firstOnly);

                    // Select the quads 
                    myMesh.SelectQuads(indices); 
                    break; 
                } 
            } 

            return new int[0]; 
        } 
    }

 

Finally create the MyMesh object with the quads vertices, triangles and normals:

 

        private void Form1_Load(object sender, EventArgs e)
        { 
            DrawQuadsVBO(viewportLayout1); 
        } 

        private static void DrawQuadsVBO(ViewportLayout vp)
        { 
            List<IndexTriangle> triangles = new List<IndexTriangle>(); 
            List<Vector3D> normals = new List<Vector3D>(); 

            // Create a mesh with 2 quads 
            Point3D[] ptQuads = new Point3D[8]
            { 
                new Point3D(0, 0, 0), new Point3D(10, 0, 0), new Point3D(10, 10, 0), new Point3D(0, 10, 0),
                new Point3D(15, 0, 0), new Point3D(25, 0, 0), new Point3D(25, 10, 0), new Point3D(15, 10, 0),
            }; 

            int nQuads = 2;

            for (int i = 0, countVertices = 0; i < nQuads; i++, countVertices += 4)
            { 
                // get the vertices coordinates for the quad 
                Point3D pt1 = ptQuads[countVertices]; 
                Point3D pt2 = ptQuads[countVertices + 1]; 
                Point3D pt3 = ptQuads[countVertices + 2]; 
                Point3D pt4 = ptQuads[countVertices + 3]; 

                triangles.Add(new IndexTriangle(countVertices, countVertices + 1, countVertices + 2));
                triangles.Add(new IndexTriangle(countVertices, countVertices + 2, countVertices + 3));

                Vector3D diff = Vector3D.Subtract(pt2, pt1); 
                Vector3D diff2 = Vector3D.Subtract(pt3, pt1); 

                Vector3D normal = Vector3D.Cross(diff, diff2); 
                normal.Normalize(); 

                normals.Add(normal); // Add just one normal because I'm using quads internally

                vp.ZoomFit(); 
            } 

            // Create the MyMesh object and add it to the ViewportLayout. 
            Mesh mesh = new MyMesh(vp, meshNatureType.Plain); 
            mesh.Vertices = ptQuads; 
            mesh.Triangles = triangles.ToArray(); 
            mesh.Normals = normals.ToArray(); 
            mesh.ColorMethod = devDept.Eyeshot.Entities.colorMethodType.byEntity; 
            mesh.Color = Color.Red; 
            mesh.LightWeight = true; 
            mesh.EdgeStyle = meshEdgeStyleType.None; 

            vp.Entities.Add(mesh); 

            vp.ZoomFit(); 
        }

 

Have more questions? Submit a request

3 Comments

  • 0
    Avatar
    Daniel

    Would I be able to use this and also be able to to selectively turn off (make invisible) some of the quads?

  • 0
    Avatar
    Luca Cornazzani

    To turn off some of the quads you should rebuild the display list or the VBO without them (Compile method).

  • 0
    Avatar
    Leonid Semenov

    We remade this example for version 8.0.321.

    After updating to version 8.0.367, example don't work

    Whether it is possible to receive a working example for the new version?

Please sign in to leave a comment.