- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files
- Directories
- Examples

# MeshBuilder/MeshBuilder.cpp

    //**************************************************************************/
    // Copyright (c) 2011 Autodesk, Inc.
    // All rights reserved.
    //
    // Use of this software is subject to the terms of the Autodesk license
    // agreement provided at the time of installation or download, or which
    // otherwise accompanies this software in either electronic or hard copy form.
    //
    //**************************************************************************/
    // DESCRIPTION: Mesh Builder
    // CREATED: May 2011
    //**************************************************************************/

    #include <QtCore/QObject>
    #include "MeshBuilder.h"

    using namespace mudbox;

    // Register this plugin. The "Initializer" method will be called when the plugin is loaded.
    MB_PLUGIN( "MeshBuilder", "Build Simple Meshes", "Autodesk", "http://www.mudbox3d.com", Initializer );

    // This function will be called then the plugin is loaded.
    void Initializer(void)
    {
        // Add a menu entry for this operation.
        Kernel()->Interface()->AddCallbackMenuItem( mudbox::Interface::menuMesh, QString::null, QObject::tr("Build Simple Meshes"), Execute);
    }

    void Execute(void)
    {
        // Build the triangle plane mesh object, and name it.
        Mesh *pTriPlane = BuildTrianglePlane();
        pTriPlane->SetName("TriPlane");

        // Create a geometry object, which will be used as a container class for the mesh.
        // The geometry class can hold multiple levels of mesh.
        Geometry *pGeoPlane = CreateInstance<Geometry>();
        pGeoPlane->SetName("TriPlane Geometry");

        // Add the mesh that you created to the geometry object.  This mesh
        // is now the "level 0" mesh of the geometry.
        if (SubdivisionLevel *pTriPlaneSL = dynamic_cast<SubdivisionLevel *>(pTriPlane))
        {
            // This mesh can be subdivided to add additional levels;
            // use the "Mesh"->"Add New Subdivision Level" menu item.
            pGeoPlane->AddLevel(pTriPlaneSL);
            pGeoPlane->SetActiveLevel(pTriPlaneSL);
        }
        // Add the newly-created triangle plane to the scene.
        Kernel()->Scene()->AddGeometry(pGeoPlane);

        // Next, we build the quad cube mesh, and create a new geometry object
        // to hold it.  This is the same as above.
        Mesh *pQuadCube = BuildQuadCube();
        pQuadCube->SetName("QuadCube");
        Geometry *pGeoCube = dynamic_cast<Geometry *>(Geometry::CreateInstances());
        pGeoCube->SetName("QuadCube Geometry");
        SubdivisionLevel *pQuadCubeSL0 = dynamic_cast<SubdivisionLevel *>(pQuadCube);
        MB_ASSERT(pQuadCubeSL0);
        pGeoCube->AddLevel(pQuadCubeSL0); // to be level 0

        // Now we are going to create some additional subdivision levels for this cube
        // manually, to demonstrate how this can be done.
        SubdivisionLevel *pQuadCubeSL1 = pQuadCubeSL0->Subdivide(false, false, false); // Linear subdivision.
        pGeoCube->AddLevel(pQuadCubeSL1); // to be level 1
        SubdivisionLevel *pQuadCubeSL2 = pQuadCubeSL1->Subdivide(false, true, false); // Catmull-Clark subdivision.
        pGeoCube->AddLevel(pQuadCubeSL2); // to be level 2
        pGeoCube->SetActiveLevel(pQuadCubeSL2);
        Kernel()->Scene()->AddGeometry(pGeoCube);

        Kernel()->Scene()->SetActiveGeometry(pGeoCube);

        Kernel()->ViewPort()->Redraw(); // redraw the 3d view to display the new objects
        Kernel()->Interface()->RefreshUI();        // ensure that the new geometries will appear in the Object List.
    }

    Mesh *BuildTrianglePlane()
    // This method creates a mesh object comprising a triangle plane.
    {
        // Create an empty mesh object.
        Mesh *pMesh = Kernel()->Scene()->CreateMesh(Topology::typeTriangular);

        MB_ASSERT(pMesh->VertexCount()       == 0);  // demonstrating that there are no vertices (yet)
        MB_ASSERT(pMesh->VertexNormalCount() == 0);  // and no normals
        MB_ASSERT(pMesh->TCCount()           == 0);  // and no texture coordinates (UVs)
        MB_ASSERT(pMesh->FaceCount()         == 0);  // and no faces

        // Create a list of vertices for the mesh (required). Each face has
        // a 3d coordinate.
        //v3______ v2
        //  |    /|
        //  |  /  |
        //v0|/____|v1
        pMesh->SetVertexCount(4);
        pMesh->SetVertexPosition(0, Vector(-400, 0, 0));
        pMesh->SetVertexPosition(1, Vector(-200, 0, 0));
        pMesh->SetVertexPosition(2, Vector(-200, 200, 0));
        pMesh->SetVertexPosition(3, Vector(-400, 200, 0));
        MB_ASSERT(pMesh->VertexCount() == 4);

        // Create a list of faces (required).  Each face is a list of indices
        // into the vertex list, defining the corners of the face, counter-clockwise.
        pMesh->SetFaceCount(2);            // create 2 faces

        // The arguments to this next method are:
        //     The index of the face;
        //     Which corner of the face (a number from 0 to 2)
        //     The index of the vertex in the vertex list
        pMesh->SetTriangleIndex(0, 0, 0);  // triangle one.
        pMesh->SetTriangleIndex(0, 1, 1);
        pMesh->SetTriangleIndex(0, 2, 2);
        pMesh->SetTriangleIndex(1, 0, 0);  // triangle two.
        pMesh->SetTriangleIndex(1, 1, 2);
        pMesh->SetTriangleIndex(1, 2, 3);
        MB_ASSERT(pMesh->FaceCount() == 2);

        // Optionally, you can add texture coordinates (UVs) to your
        // mesh programmatically.  (If you don't, you can always add them
        // later using the menu command "Mesh" > "Create UVs".
        //
        //   t3______ t4        t5
        //  |    /       /|
        //  |  /       /  |
        //   t0|/     t1/____| t2
        //
        // A texture coordinate is set for each corner of each face in the
        // mesh.  Note that the same texture coordinate can be shared by
        // all the faces sharing a vertex.
        //
        // First, make your list of texture coordinates.
        pMesh->SetTCCount(6);
        pMesh->SetVertexTC(0, TC(0.1f, 0.1f)); // TC not allow to cross 1,2,3,...
        pMesh->SetVertexTC(1, TC(1.1f, 0.1f));
        pMesh->SetVertexTC(2, TC(1.9f, 0.1f));
        pMesh->SetVertexTC(3, TC(0.1f, 0.9f));
        pMesh->SetVertexTC(4, TC(0.9f, 0.9f));
        pMesh->SetVertexTC(5, TC(1.9f, 0.9f));
        MB_ASSERT(pMesh->TCCount() == 6);

        // Now, point the corners of each triangular face into the texture
        // coordinate list.  The arguments to this method are:
        //     - the index of the face
        //     - the number of the face corner (from 0 to 2)
        //     - the index into the list of texture coordinates
        pMesh->SetTriangleTCI(0, 0, 0);
        pMesh->SetTriangleTCI(0, 1, 4);
        pMesh->SetTriangleTCI(0, 2, 3);
        pMesh->SetTriangleTCI(1, 0, 1);
        pMesh->SetTriangleTCI(1, 1, 2);
        pMesh->SetTriangleTCI(1, 2, 5);

        MB_ASSERT(pMesh->HasTC() == true);

        // Build the internal tables that tell us which faces are beside which others.
        // (This is required)
        pMesh->RecalculateAdjacency();

        // Calculate the normals (you don't need to set them manually, although that is also an option.)
        pMesh->RecalculateNormals();

        return pMesh;
    }

    Mesh *BuildQuadCube()
    {
        // Create an empty mesh object
        Mesh *pMesh = Kernel()->Scene()->CreateMesh(Topology::typeQuadric);

        // Add a list of 8 vertices to it
        pMesh->SetVertexCount(8);
        pMesh->SetVertexPosition(0, Vector(100, 0, 300));
        pMesh->SetVertexPosition(1, Vector(300, 0, 300));
        pMesh->SetVertexPosition(2, Vector(300, 0, 100));
        pMesh->SetVertexPosition(3, Vector(100, 0, 100));
        pMesh->SetVertexPosition(4, Vector(100, 200, 300));
        pMesh->SetVertexPosition(5, Vector(300, 200, 300));
        pMesh->SetVertexPosition(6, Vector(300, 200, 100));
        pMesh->SetVertexPosition(7, Vector(100, 200, 100));

        // Create the 6 faces of the cube.
        // Each face is a list of indices into the vertex list, defining
        // the corners of the face, counter-clockwise.
        //
        pMesh->SetFaceCount(6);
        unsigned int aFaceIndices[] = {
            0, 1, 5, 4, 2, 3, 7, 6, 1, 2, 6, 5, 3, 0, 4, 7, 4, 5, 6, 7, 1, 0, 3, 2
        };
        unsigned int iFIdx = 0;
        for (unsigned int iF = 0; iF < 6; ++iF)
        {
            pMesh->SetQuadIndex(iF, 0, aFaceIndices[iFIdx++]);
            pMesh->SetQuadIndex(iF, 1, aFaceIndices[iFIdx++]);
            pMesh->SetQuadIndex(iF, 2, aFaceIndices[iFIdx++]);
            pMesh->SetQuadIndex(iF, 3, aFaceIndices[iFIdx++]);
        }

        // Build the internal tables that tell us which faces are beside which others.
        // (This is required)
        pMesh->RecalculateAdjacency();

        // Calculate the normals
        pMesh->RecalculateNormals();

        MB_ASSERT(pMesh->HasTC() == false); // we don't set the tc values of this mesh manually.

        return pMesh;
    }