Hardcoded Cube
Here we will see how to create a mesh from code and how to diplay it through an entity.
No external files are loaded.
The code could be put in the onBeginScene method or anywhere else but be sure that you call it only one time. So if you happen to put it in the update() function be sure to use a bool flag to avoid its recalling.
Contents |
Creating the mesh
//create mesh MMesh * mesh = MMesh::getNew(); //new mesh mesh->allocSubMeshs(1); MSubMesh * smeshs = mesh->getSubMeshs(); MVector3 * vertices = smeshs[0].allocVertices(8); //8 vertices because it's a cube MVector3 * normals = smeshs[0].allocNormals(8); float sz = 2.0f; //size of the cube const float sqrt13 = 0.577350269f; //sqrt(1/3), used for the normals //create vertices and normals vertices[0] = MVector3(-sz,-sz,sz); normals[0] = MVector3(-sqrt13,-sqrt13,sqrt13); vertices[1] = MVector3(sz,-sz,sz); normals[1] = MVector3(sqrt13,-sqrt13,sqrt13); vertices[2] = MVector3(sz,sz,sz); normals[2] = MVector3(sqrt13,sqrt13,sqrt13); vertices[3] = MVector3(-sz,sz,sz); normals[3] = MVector3(-sqrt13,sqrt13,sqrt13); vertices[4] = MVector3(-sz,-sz,-sz); normals[4] = MVector3(-sqrt13,-sqrt13,-sqrt13); vertices[5] = MVector3(sz,-sz,-sz); normals[5] = MVector3(sqrt13,-sqrt13,-sqrt13); vertices[6] = MVector3(sz,sz,-sz); normals[6] = MVector3(sqrt13,sqrt13,-sqrt13); vertices[7] = MVector3(-sz,sz,-sz); normals[7] = MVector3(-sqrt13,sqrt13,-sqrt13);
Now we have to create the triangles, basing on the vertices that we've made; triangles are created telling what vertices they will create from. For example the first triangle that I create here below will use the vertices 0, 2, and 3. To complete the face of the cube we need a second triangle. It will use the vertices 0, 1, and 2. This list of vertices is called "indices", and we can set them all in a row:
smeshs[0].allocIndices(36,M_USHORT); unsigned short * indices = (unsigned short *)smeshs[0].getIndices(); unsigned short indicesVal[36] = { 0,2,3, 0,1,2, 1,6,2, 1,5,6, 4,6,5, 4,7,6, 0,7,4, 0,3,7, 0,5,1, 0,4,5, 2,7,3, 2,6,7 }; memcpy(indices,indicesVal,sizeof(unsigned short)*36); //copy the indices in the actual place of memory we've allocated above
Of course, making a visual scheme of the vertices can help knowing which vertices we should pick up.
Materials
//material mesh->allocMaterials(1); //we only need one material MMaterial * material = mesh->addNewMaterial(); //we have already allocated the material, now just do addNewMaterial(); no need to specify the number, //this function gets no parameters material->setBlendMode(M_BLENDING_ALPHA); //let's set the blending mode to ALPHA so we can make the cube partially transparent material->setOpacity(0.30f); //we make the cube transparent just for the sake of it; 0.30 alpha value means very transparent material->setShininess(50.0f); material->setCustomValue(0.0f); material->setDiffuse(MVector3(0.8f,0.8f,0.8f)); material->setSpecular(MVector3(0.8f,0.8f,0.8f)); material->setEmit(MVector3(0,0,0)); material->setCustomColor(MVector3(0,0,0));
Bounding box
//bounding box MBox3d *mbox = smeshs[0].getBoundingBox(); mbox->min = MVector3(-sz,-sz,0); mbox->max = MVector3(sz,sz,sz*2); mesh->updateBoundingBox(); //this won't do anything if we don't explicitly set the bounding box as done above
Display
There are various ways you can display a mesh.
The M_PRIMITIVE_MODE tells the engine how to display the primitives (points, lines, triangles). The most used is of course M_PRIMITIVE_TRIANGLES, since standard meshes are made of triangles. But you could also use M_PRIMITIVE_LINES: this will show no faces, it will just connect the vertices with lines; so you could use it to show the wireframe of the mesh. Things like this could be used for debugging purposes or to obtain weird effects.
You can even combine displays, allocating more than one and giving them different properties to obtain even more complex and interesting results.
An important property is the CullMode. Backface culling is important for the game performances. This shouldn't be used when you create a mesh with an external software because you are supposed to correctly set the culling beforehand. But since we're creating the mesh from scratch we have to specify if we need some culling. Of course we don't want backfaces since we're making a closed cube, but that's no problem because M_CULL_BACK is the default CullMode. See http://en.wikipedia.org/wiki/Back-face_culling
//display smeshs[0].allocDisplays(1); MDisplay * display = smeshs[0].addNewDisplay(M_PRIMITIVE_TRIANGLES,0,36); display->setMaterial(mesh->getMaterial(0)); //assigning the material; we know that its index is zero, because we've created only one material //display->setCullMode(M_CULL_BACK); no need, it's M_CULL_BACK by default
Entity creation and mesh assignment
//create the entity MMeshRef * mref = MMeshRef::getNew(mesh,""); MOEntity * hardcodedEntity = scene->addNewEntity(mref); hardcodedEntity->setPosition(MVector3(0,0,0)); //set the entity at the center of the world
Physics
To understand the following code, see Creating and updating physics objects.
//physics MPhysicsProperties *phyProps = hardcodedEntity->createPhysicsProperties(); phyProps->setCollisionShape(M_COLLISION_SHAPE_BOX); phyProps->setMass(1.0f); phyProps->setFriction(1.00f); phyProps->setRestitution(0.01f); phyProps->setLinearDamping(0.01f); phyProps->setAngularDamping(0.01f); phyProps->setAngularFactor(0.0f); phyProps->setLinearFactor(MVector3(1,1,1)); scene->prepareCollisionShape(hardcodedEntity); scene->prepareCollisionObject(hardcodedEntity);
And we're done!