Selection in 3D Graphics Environments
Christine Albert and Lindsey Press

Because the ultimate goal of our research is to select objects in complex 3D graphics scenes, our next step is to significantly increase the number of cubes displayed in the scene. We also want to make these objects move so that it more directly relates to a graphics scene that would be seen in real situations, like a video game. Below is our step-by-step tutorial on how to create this scene, with around 600 moving cubes.

Step 1- Create a cube class which initiates the center of the cube, assigns it a scale value and color, an angle, and a model matrix, as well as creating a cubes array with 600 indicies to store the cubes
class Cube
{
public:
glm::vec3 center;
GLfloat scale, color;
glm::vec2 angle;
glm::mat4 model;
};
Cube cubes[NUMCUBES];
...

Step 2- Randomly generate positions and scale factors for multiple cubes, ensure different locations and sizes
void GenerateRandomCubes()
{
srand(time(NULL)); //Initialize the random number generator
for(int i = 0; i < NUMCUBES; i++)
{
  cubes[i].center.z = 0.01+rand() % (GLint)FAR; //Ensure z coordinate is not zero and set z value of cube's center to a random value smaller than far keep it in view of the camera
  GLint maxy = 4*(1+glm::tan(FOV/2)*cubes[i].center.z);
  GLint maxx = maxy*SCREEN_SIZE.x / SCREENSIZE.y;
  cubes[i].center.x = -maxx/2 + (rand() % maxx) + rand() / RANDMAX; //set x value of cube's center
  cubes[i].center.y = -maxy/2 + (rand() % maxy) + rand() / RANDMAX; //set y value of cube's center
  cubes[i].scale = rand() / RANDMAX * 0.4; //randomly assign scaling factor
  cubes[i].color = (20 + rand() % 230)/255.0; //create different color variations among cubes
  cubes[i].angle[0] = 0;
  cubes[i].angle[1] = 0;
}
}
...

Step 3- Update the scene for each of the 600 cubes so that the model matrix is scaled to a random size within a specific range and then translated based off of the center.x, center.y, and center.z(values instantiated in the cube class) coordinates so that the cubes move throughout the scene
static void Update(GLfloat deltaz)
{
int i;
glm::mat4 model;
for(int i = 0; i < NUMCUBES; i++)
{
  model = glm::scale(glm::mat4(), glm::vec3(cubes[i].scale, cubes[i].scale, cubes[i].scale));
  model = model * glm::translate(glm::mat4(), glm::vec3(cubes[i].center.x, cubes[i].center.y, cubes[i].center.z-deltaz));
  cubes[i].model = model;
}
}
...

Step 4- Reset the z coordinate of each cube and then render the scene so that it appears as if the scene restarted ones the cubes go out of view of the camera
while((glfwGetKey(gWindow, GLFW_KEY_ESCAPE)! = GLFW_PRESS) && !glfWindowShouldClose(gWindow))
{
glfwPollEvents();
Update(deltaz);
Render();
deltaz = deltaz + 0.05;
if(deltaz > FAR) deltaz = 0.0;
  GLenum error = glGetError();
if(error != GL_NO_ERROR)
  std.ceer<< "OpenGL Error" << error << std.endl;
}
...

Step 5- Inside of the render function, this for loop is the most important because it sets the model matrix to each of the 600 cubes and is responsible for actually drawing the objects on the screen. Every object in OpenGL is drawn in the form of trianges, and the parameters after the GL_TRIANGLES call ensure that each vertice is drawn to create a complete cube
for(int i = 0; i < NUMCUBES; i++)
{
  gProgram->setUniform("model", cubes[i].model);
  glDrawArrays(GL_TRIANGLES, 0, 6*2*3);
}

The resulting graphics scene is:

Many Multicolor Cubes