Overview
In the following series of articles we are going to augment our physics simulation with rigid body dynamics. In laymens terms a rigid body is an object whose deformation under pressure can be ignored. Meaning points on or within its surface will always be the same distance apart. Most objects we interact with in everyday life fall into this category. The main difference between rigid body motion and what we’ve implemented so far is rigid bodies can rotate.
However before we get to any of that we need to address an issue. Namely that up until this point we’ve only been dealing with spheres, which are rotationally symetric. There’s not much point in implementing rotational physics if our entities look the same under rotations. To that end we will put together a simple rectangular prism, ie.) a box.
Rectangular prism
In general rectangular prisms are characterized by 3 side lengths and a position for their center. Since we’ll be working in model coordinates we can assume the center to be the origin. For our purposes length will be measured along the axis, width the axis, and height the axis.
#ifndef RECTANGULAR_PRISM_H
#define RECTANGULAR_PRISM_h
#include <model.h>
#include <physics_entity.h>
#include <vector3G.h>
#include <material.h>
class RectangularPrism : public Model, public PhysicsEntity
{
private:
GLuint m_length;
GLuint m_width;
GLuint m_height;
void GenerateMesh();
public:
RectangularPrism(GLuint length, GLuint width, GLuint height, Vector3Gf postion, Vector3Gf velocity, GLfloat mass, Material material);
/**
Loads the next position and velocity values from their respective buffers
**/
void OnUpdateFromBuffers();
};
#endif
The only interesting method is GenerateMesh
include <rectangular_prism.h>
#include <iostream>
RectangularPrism::RectangularPrism(GLuint length, GLuint width, GLuint height, Vector3Gf position, Vector3Gf velocity, GLfloat mass, Material material) : Model(), PhysicsEntity(position,velocity,mass)
{
m_length = length;
m_width = width;
m_height = height;
m_model_matrix.col(3) << position(0), position(1), position(2), 1.0f;
GenerateMesh();
m_material = material;
}
void RectangularPrism::GenerateMesh()
{
List3df vertices(8,3);
List3di faces(12,3);
GLfloat l = (GLfloat)m_length/2.0f;
GLfloat w = (GLfloat)m_width/2.0f;
GLfloat h = (GLfloat)m_height/2.0f;
// front face
vertices.row(0) = Vector3Gf(-l,-w,h); // bottom left
vertices.row(1) = Vector3Gf(-l, w,h); // top left
vertices.row(2) = Vector3Gf( l,-w,h); // bottom right
vertices.row(3) = Vector3Gf( l, w,h); // top right
// back face
vertices.row(4) = Vector3Gf(-l,-w,-h); // bottom left
vertices.row(5) = Vector3Gf(-l, w,-h); // top left
vertices.row(6) = Vector3Gf( l,-w,-h); // bottom right
vertices.row(7) = Vector3Gf( l, w,-h); // top right
// front face
faces.row(0) = Vector3Gi(0,2,1);
faces.row(1) = Vector3Gi(2,3,1);
// back face
faces.row(2) = Vector3Gi(6,4,7);
faces.row(3) = Vector3Gi(4,5,7);
// left face
faces.row(4) = Vector3Gi(4,0,5);
faces.row(5) = Vector3Gi(0,1,5);
// right face
faces.row(6) = Vector3Gi(2,6,3);
faces.row(7) = Vector3Gi(6,7,3);
// bottom face
faces.row(8) = Vector3Gi(4,2,0);
faces.row(9) = Vector3Gi(4,6,2);
// top face
faces.row(10) = Vector3Gi(3,7,1);
faces.row(11) = Vector3Gi(7,5,1);
m_mesh = Mesh(vertices,faces);
}
void RectangularPrism::OnUpdateFromBuffers()
{
m_model_matrix.setIdentity();
m_model_matrix.col(3) << m_position(0), m_position(1), m_position(2), 1.0f;
}
Generate mesh works by first placing the vertices that represent the corners of the prism into the vertex list. From there it adds the $12$ faces by specifying vertex indices in counter clockwise order.
You’ll notice that in contrast to how we built our sphere mesh we reused vertices in multiple faces. In addition to being more memory efficent this should result in smoother lighting on the surface.
Results
Here’s the code