Building a Minecraft clone from scratch

Role

Engineer

Duration

4 weeks

Tools

OpenGL, C++, GLSL, Qt

Overview

This is the final project for my Computer Graphics course at Penn, CIS 5600: Interactive Computer Graphics, and it was produced during the final 4 weeks of the semester. I worked on a three-person team with my partners Zain Khan and Daniel Alexander to build a Minecraft clone called Mini-Minecraft from scratch using C++ and OpenGL. Mini-Minecraft features a voxel engine that enables procedural terrain generation, multithreaded terrain rendering, chunk management, Raycast-based sky backgrounds, day and night cycles, real-time rendering, player physics, crafting GUI, textures, and animations. My main contributions to the project involve two major areas.

First, I helped with procedural terrain generation, focusing on using 2D and 3D noise to generate natural biomes such as grasslands, mountains, and caves.

Second, I focused on environment effects - swimming physics (collision detection), and post-processing visuals (underwater and under-lava fog), Raycast-based features (sky backgrounds with day and night cycles, Blinn-Phong lighting from dynamic water waves), and distance fog.

In addition, I helped debug and fix integration issues for terrain rendering and textures, such as transparent block rendering at the edges of chunks.

Procedural Biomes

For the grassland biome, I used two FBM noise values to create a 2D displacement vector to distort the coordinates for the Perlin noise function. Next, I overlaid Voronoi noise on top of the previous noise to create a patchy pattern for the hills. For the mountain biome, I used similar two FBM noise and the Perlin noise, what I did differently for the mountains is that I shifted the height range down and then I utilized smooth step with a range of 0.1 to 0.8 to create steeper contours. I helped the biomes transition by getting a blend factor using Perlin noise at a large scale and then normalizing to the [0, 1] range. The factor will help biomes transition over a wide area. I used the blend factor to determine if an area is pure grassland (when t < 0.25) or pure mountain (when t > 0.75), or transitions (0.25 ≤ t ≤ 0.75).

Project Cover

Cave Systems

I used a Perlin noise algorithm by sampling eight surflets in each corner of a 3D grid cell to create the 3D noise that can be used to determine the location of caves. I added a height ratio calculation into the noise evaluation such that there are fewer caves near the ground level and more caves the further into the depths you go. I added coefficients inside of the Perlin noise calculation to emphasize horizontal chambers over vertical chambers. Lastly, I tried to increase horizontal connectivity by using a sign function to warp the vertical distribution of the frequency of caves to be more wave-like, such that there are fewer straight-up and down caves. For blocks that have noise values that satisfy the threshold requirement, they are replaced by either empty or lava blocks, depending on the depth value. To make cave openings more natural, I added code that checks for dirt walls and turns them into rock so that cave openings look less like dirt holes.

Project Cover

Liquid Physics and Post-Processing

The post-process pipeline allows the rendering of an overlay for the player's head beneath water and lava. For collision detection, I added boolean indicators of whether the player is in a liquid or not. If the player is, their movement is slowed. The water blocks and lava blocks are also ignored by the collision system since they are not considered to be solid. I also toggled the physics with a liquid speed multiplier for the cases where the user is in liquid. For the post-processing, I created a quad over the initially rendered 3D world and a frame buffer to feed the world render into and then using the texture from the frame buffer. For the water and lava post-processing effects, I made the screen have either a more blue or red hue that also has decreased opacity.

Project Cover

Raycast Sky with Day/Night Cycle

I implemented a sky shader that uses information about sun positions that vary depending on the time tick variable. Using the sun position as well as the viewing angle, the shader interpolates between four stages of sky color settings (day, night, sunset, and dusk). The sky shader also features a rendering of sun, moon, and stars. The stars and the cloudy patterns in the sky are created using fractal Brownian motion with several octaves as well as Worley noise. These elements get to transition smoothly using smoothset functions. Special considerations of directional lighting in the sky are taken during the sunset/dusk phases, where the sky color based on the direction that the player is facing towards or away from the sun using a dot product function. I implemented dynamic lighting on the blocks depending on the sun and moon lighting position during the day/night cycle by working inside the instanced fragment file and blending the color palettes of the four time periods (day, sunset, dusk, and night) using weights based on the sun/moon's height. For each of the time periods, I played with the ambient light levels, light multipliers, and color tints to achieve a beautiful aesthetic.

Project Cover

Water Surfaces and Light Reflections

I added specialized effects for water surfaces including Blinn-Phong specular highlights that vary in intensity and sharpness depending on the day-night cycle. I did this by distorting the vertices for water surfaces by building new logics in the instanced vertex shader. I added displacement to the upper surfaces of water blocks. I used sin and cos waves based on the time variable and then calculated a perturbed normal vector for water surfaces by sampling neighboring points to determine the gradient of the wave height. Then, I constructed a new normal reflecting the surface orientation at each vertex. Then I also passed the view direction vector for each vertex onto the fragment shader, which will be used for the Blinn-Phong calculations.

Project Cover

Distance-Based Fog

Lastly, I implemented distance-based fog with colors that change based on the time of day. The fog color is dynamically calculated by blending four different color pallets using the time-of-day weights that were already calculated in the instanced shader (dayWeight, sunsetWeight, duskWeight, and nightWeight). I used a linear fog equation where (fogEnd - distance) / (fogEnd - fogStart) creates a gradient that equals 1.0 at fogStart (no fog) and 0.0 at fogEnd (maximum fog), which is then clamped to ensure the fog multiplier value stays within the [0,1] range. The fog begins at a distance of 124 units from the camera (fogStart) and reaches maximum density at 228 units (fogEnd). The mix function will help interpolate the fog color with the original fragment.