This was the final project for CIS560: Introduction to Computer Graphics and I worked on it with Isa Jiminez and Ben Leitner. The goal of the project was to create an interactive miniature version of Minecraft. I was in charge of handling the player physics, game state and engine updates, player swimming, multi-threading of terrain generation, creation of sandbox mode, and procedurally generated post-process shaders for weather. The project was done in C++ using OpenGL. The following sections further detail my sections of the project - the videos at right show the progress of our group.
The player needs to be able to move smoothly in 3D space bi-directionally along each coordinate axis as designated by keyboard (which accelerates the player) and mouse input (which changes the player's direction).
Defining states for the player was relatively trivial - the player needs a location and velocity in 3D space. Updating these values accordingly was more tricky. Key presses triggered flags which routinely updated acceleration to keep game play smooth. When no blocks were beneath the player, the player would fall to the ground naturally at a terminal velocity, as defined by the gravitational force downwards and drag force upwards. Collision detection was base on a ray-marching approach but simplified for block space - modularized by forecasting the player's final position as well as any intermediate blocks and moving the player along its path to the last non-colliding spot.
Minecraft is a first-person player game, so the game engine updates are handled as perceived by the player. The game engine thus operates on the status of the player and calls an OpenGL update on each iteration. There was, however, sandbox mode - in which the user can fly above or walk through ground (the aforementioned gravity and collision detection are ignored) which operated independently.
The Minecraft player can swim through water or lava. Both produce viscous drag forces proportional to the cubic of the player's velocity. They also originally caused tinted overlays on the by rendering a cube using its own VBO, and passing that into a new shader that does not use a view projection matrix. The overlays have a transparency of 30%. A post-process shader was also added to add water and fire effects in the respective terrains.
Since the Minecraft terrain is dense with many features, game latency can be dramatically decreased by multi-threading its generation. I used 16 threads to create 16 new chunks. The adjacent chunks are recomputed each time so the inside of the terrain remains hollowed out and optimized. To determine what elements should be added, the chunks are added to a QSet stored in MyGL and are iterated through on every timer update, then removed after addition.
Weather was imitated by procedurally placing both white and gray (rain) clouds in the sky. To reduce runtime, each chunk can have a maximum of one cloud, at a procedurally generated position within the chunk determined by a rand function of its x and z coordinates, which ensures it will get the same values every time. The type of cloud, or whether there is a cloud at all, is procedurally generated by a second noise function. The clouds are then expanded procedurally, using a noise function as well as a distance scale factor in a recursive call to determine whether a block in the cloud should be placed at a location. The player class was adapted to keep track of the closest non-empty block directly above the player. If this block is a rain cloud, then there is a rain overlay on the screen and if this block is a snow cloud, then there is a snow overlay. Taking this approach, rather than drawing the clouds above the terrain allows the user to place the clouds above them and get rain/snow when walking underneath. These effects were done with another post-process shader.