Hardcoded Cube

From MaratisWiki
Jump to: navigation, search

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!

Personal tools
Namespaces
Variants
Actions
Navigation
Toolbox