MeshBuilder/MeshBuilder.cpp

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)
// Calculate the normals (you don't need to set them manually, although that is also an option.)
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)
// Calculate the normals
pMesh->RecalculateNormals();
MB_ASSERT(pMesh->HasTC() == false); // we don't set the tc values of this mesh manually.
return pMesh;
}