Milestone 3: https://vimeo.com/941331245?share=copy
Milestone 2: https://vimeo.com/939284267?share=copy
Milestone 1: https://vimeo.com/932727233?share=copy
Joyce - Day and night cycle (procedural sky, realistic stars, terrain coloring/lighting, interpolated horizon colors)
I implemented procedural sky with day night cycle, a moving sun, small realistic stars at night, interpolated horizon colors with worley noise, and matching terrain coloring/lighting. I started with the given raytracedSky code and first added day/night cycles with ticks, an additional hardcoded daytime interval for sky coloring with a uvToDaytime function. Then I added a moving sun with colors based on sunrise/sunset that affects the nearby sky colors, and used the sky's sun and color to modify the light direction and color used to render terrain in lambert.frag.glsl. Finally, I also added a addStars helper function to randmoly add small moving white stars to the skycolor at night. A big challenge was integrating the sky shader to all the existing shaders in mygl.cpp. It would either not render at all, or only the sky would render and none of the other shaders would be visible. I was able to fix this by isolating the sky shader draw function within glDisable(GL_DEPTH_TEST) and glEnable(GL_DEPTH_TEST) to make sure it didn't affect any of the other shaders. I also really wanted to implement sound, but was stuck at an error of not being able to find QSound, I tried reinstalling QtMultimedia, including multimedia in my .pro file, and running QMake and rebuilding the project, but in the end still could not figure it out.
To load the texture image I used the given texture.cpp/texture.h from lecture and hw 5, and also added a .src file with the png files copied into the project. Then to apply the texture to the surfaces, I had to modify lambert.frag.glsl to have a sampler2D var for the texture and uv coordinates passed from lambert.vert.glsl. This also included modifying shaderprogram.cpp to support uv variables. In chunk, I defined a texture atlas blockToUVMapping mapping block types to the corresponding uv coordinates on the texture png, and incorporated it into the chunk create vbo function when assigning the vertex data. Also had to create two separate VBOs to support opaque vs transparent blocks, and a separate drawInterleavedT function within shaderprogram.cpp. For the "animatable" flag for LAVA and WATER blocks, I just included it within the uv by making it a vec4 and checking if the uv.z value was 1 to animate it within the lambert.frag.glsl using a time variable incremented within shaderprogram.cpp.
I struggled a lot with getting textures to properly map onto block surfaces, this was due to not being able to identify the correct problems to debug since I focused on error logs printed about the fs_UV not being passed properly and u_Texture not being able to be found, which turned out to be caused by shaders other than Lambert when called. So I was overlooking variables used by the new Lambert shader, and not Instance/Flat previously, like "u_Model" and "u_ModelInvTr" which were not being set up in myGL when painting, among other issues.
I modified the input bundle to include spacePressed and had to add additional qPressed, ePressed,fPressed values within entity to implement the specified player movements. Then I implemented within Player::processInputs to adjust the acceleration values and camera rotation, and Player::computePhysics to update the position accordingly. I set gravity to -80.f to realistically account for player weight, and initial velocity before adding acceleration to *=0.95 to account for friction and drag, and baseAcceleration=40.f. Then I used the gridMarch function from lecture slides to support terrain collision as the ray casting function, which was done through updateCollisionMovement function which checks for collisions by grid marching every axis of the player's dimensions (height of 2.0f, width of 0.8f). Lastly, I implemented removing and adding blocks by ray casting center forward using gridMarch to modify blocks within 3 units from the player.
The main bugs I struggled with were first how to update (add/destroy)block without having chunk inheritance from Drawable and creatVBOdata done, which I temporarily fixed by adding m_chunkVBOsNeedUpdating = true in setGlobalBlockAt. However this was later changed when we merged. I was also struggling with partially phasing into some blocks during terrain collision, which I fixed by thoroughly iterating through the three axis using player dimension bounds to ensure that all bounds were covered.
Additional Biomes: I added desert and tundra biomes, where deserts are only sand (no water), and tundras are all snow, and water is replaced with ice. I tried interpolating between biomes by using noise functions for moisture and temperature, but whenever I tried generating new terrain my program would crash. Instead, I scaled down the size of the biomes by a lot to check if my interpolation worked, which caused each biome to look a little strange. I did hard code each biome to check that they worked, though.
Water Waves: I originally tried implementing a completely new shader for the surface of the water before I realized it would be easier to implement as a conditional in the lambert shader. I distorted the surface of WATER blocks in the vertex shader by checking if fs_UV.z was 1, which was how we determined if the block was animatable, and then used multiple sine waves to create natural looking waves. I didn't have enough time to implement Blinn Phong shading.
Post-process Camera Overlay: I used 2D fractal brownian motion from the lecture slides and played around with different sine and cosine functions until I got the warped UV values that I liked. I wanted smoother curves for when the player was in WATER, and faster and smaller noise for when the player was in LAVA to simulate heatwaves.
Fog: I implemented view fog by modifying the lambert shader. I then calculated the fog factor based on the distance from the camera to the fragment. I then mixed the output color with the fog color based on the distance.
TNT: I implemented a particle system that utilizes billboarding to render the particles. It supports animation for the TNT explosion. The TNT can be placed with the 1 key and will explode a 5x5x5 cube of blocks around it. The TNT flashes with the lambert shader.
Redstone: I attempted to implement redstone, but did not have time to completely implement. I realized how much of a pain it would be to cover all cases (e.g redstone torches powering blocks, redstone on the sides of blocks, redoing the hitboxes since redstone are on the surface of blocks, animation, torch and level 3d models). Opted to focus my efforts on the TNT instead as it seemed more interesting.
I made some adjustments to the grasslands and mountain biomes to make them more random and realistic to the actual Minecraft biomes. To implement caves, I first added bedrock and lava as blocks and made it so that bedrock cannot be destroyed. Then I added the code for 3D Perlin Noise given in the Noise Functions slides into the noise functions class and decided what blocks go where in the terrain class. Then I edited the player class collisions with water and lava so that the player's gravity and acceleration matched the instructions. My biggest struggle was getting the post-process shaders to work when the player was in water or lava. I didn't really understand the pipeline at first and was just following the process used in HW5. This led to a lot of issues, most notably since the quad class from HW5 used vec3s for position and vec2s for uv when our code uses vec4s for both, which caused the screen spanning quadrangle coordinates to be warped.
I implemented multithreading using the QMutex and QThreadPool. Much of my implementation is the same as shown in lecture. I spawned a new worker for each terrain zone and spawned a worker for each chunk in the zone. Although this works, I'm not happy with how the chunks load in from top left to bottom right in each zone. For MS 3, I will try to implement a priority queue that will load the chunks in order of closest to the player.
Creating VBO for chunks takes the same approach taught in class. Drawing the interleaved VBO is done using drawInterleaved() in ShaderProgram. This is is also self-explanatory.
To generate new terrain, I took a BFS type approach where I traverse through the neighboring chunks until a depth of 2 and generate new chunks if they don't exist yet. This alone will generate chunks that are more than 16 chunks away from the player. To prevent this, I am checking which quadrant of the chunk the player is in and only branching out to the neighboring chunks in that quadrant.
I implemented the noise functions in the NoiseFunctions class. Using the code in the “Noise Functions” lecture slides, I used Worley noise and fractal brownian motion to get the height in the grassland biome. At first I was only using Worley, but I had issues with the grassland noise function not being random enough, so I combined Worley with FBM so the noise function would look more natural. The slides for Noise Functions used a 2/3 FBM, 1/3 Worley LERP, which is what I ended up using. For the mountain biome height, I implemented Perlin noise within FBM calculations and used trial and error to find the right frequency, amplitude, and octave values. To interpolate between the two biomes, I followed the writeup’s implementation with Perlin noise and smoothstep and returned a vec2 containing the interpolated height and the blend factor between the two biomes.
In the terrain class, I implemented generateTerrain by getting the height from the NoiseFunctions class and making sure the value falls between the acceptable Y values (0 to 255), and then I set the appropriate block type according to the blend factor. I added the new block type, SNOW, into the chunk class.