The goal of this project was to learn and implement different graphics algorithms. Algorithms implemented include a basic ray tracer, sky sphere, environment mapper, grass generation/rendering, bloom, and alpha blending. You can run our project here (contact me for access to the github repository).
March 2021
(3 weeks)
Developer
C++
C
OpenGL
Programming shaders
Ray tracing
Maya
Mira Ram
Wylie Kasai
Tanli Su
Varsha Iyer
To address the theme of “A reason to love this world,” our team created a scene featuring rocky ruins under a starry aurora sky. We were inspired by the works of Loika/3 Days March when deciding on the artistic direction. Although the scene features old pillars, we wanted to create a peaceful environment around it through the starry aurora sky, fireflies, and peaceful body of water, hence “A reason to love this world.” Below is our initial sketch:
We used a sky sphere by putting all of our objects inside a large sphere generated analytically. The aurora and stars were generated in the sky sphere shader. The colors were calculated only for points with a z-coordinate greater than 0, since we only care about the top half of the sky sphere.
The aurora shader mixes 3 colors (green, navy blue, purple) and these three colors change over time using the GLSL mix() function. The aurora also uses hermite interpolation to blend the colors over time. A sin function is used to create motion for the aurora, calculating the distance of the uv coordinates on the sphere.
The stars are generated using a perlin noise function. We added a rotation to the stars within the hash function, which moves the stars in circles and creates an appearance of twinkling.
We generated water using a perlin noise function. However, rather than using the same hash function used for a terrain, a different one was used to create lower peaks and less jagged edges. Using absolute value in our function created different peaks than the ones generally used for a terrain (such as power or square root). The hash function used for rotating the stars was slightly modified for moving the water and creating waves; using sin and cosine, we undulated the heights.
We used environment mapping to reflect the color of the sky onto the surface of the water and create a more appealing visual effect. This was implemented in the fragment shader of the water. We first calculate the ray reflected off the surface of the water using the incident ray (the ray from the camera position to the vertex position) and the normal ray. We use the GLSL function refract() to calculate the refraction, with refractive indices 1.0 for air and 1.33 for water. Then, we calculate the position of the point where the reflected ray intersects the sky sphere, and we determine the color of that point using the same calculation as for the aurora sky sphere shader. Lastly, we add this color to the final color of the water surface.
We first built a terrain for the grass to be on using a perlin noise function. This terrain was very similar to implementations in Assignment 3, except that we made lower peaks to create a flatter, but textured ground. The mix() function was also used to add variations in color for the different darker and lighter elements of the ground.
Rather than use a grass mesh model that would quickly become expensive after repeated many times, we opted for an intersection of three textured panels to create the illusion of tufts of grass. This process starts with three square panels that intersect in the middle, with the second and third panels rotated 120º and 240º degrees around their vertical axis. Then, each panel is UV mapped to the same location so that the same texture may be used.
We used a random hash function to procedurally generate many of these grass tufts in main.cpp. This low-cost implementation plays a key role in keeping the scene rendering fast. We then used the texture() function in the fragment shader to map the UV to a loaded albedo texture with the grass. We had to modify the Add_Texture_From_File() function to read a 4th channel - the alpha channel - from the .png file so that the grass did not have an unwanted background. Once all three panels are textured and in the scene, they feign the appearance of 3D grass at a much lower cost for the GPU.
We wanted to create realistic, but cost efficient fireflies which would move similarly to how real fireflies would, in all directions. After looking at various firefly effects on shaders, we stumbled upon a 2D firefly effect which used bloom.
To generate the bloom effect and create a concentrated flow, we used separate point lights for each firefly as a 2D particle overlay over the scene based on a shadertoy algorithm. Each firefly/sphere position and glow intensity is generated using two separate hash functions for the number of spheres specified as a constant at the beginning of the fragment shader. The amount of glow (bloom) around each sphere point is determined using a distance function.
We decided on using this 2D effect on a vertical plane, instead of using 3D spheres, to save rendering time. To see the rest of the scene, we enabled alpha values and lowered the opacity of the plane so that it would be transparent.
These elements were modeled in Maya and imported into the scene. The shaders for the modeled elements included a normal mapping function based on the implementation from Assignment 3. Colored lighting was also added to match the changing colors of the aurora.
We wanted to create realistic water which moved, glimmered and refracted similarly to real bodies of water.
We initially tried various hash functions from online to create the perfect water effect from perlin noise. We quickly realised that using terrain hash functions would create crashing waves when undulating the heights. After trying out various techniques, we realized that the absolute value function would create realistic, calming water waves. We also lowered the heights of the waves to make the water more peaceful looking.
We used ambient, diffuse, and specular lighting for the water. We found that the specular lighting was particularly useful for creating realistic water because it made the water shimmer nicely, especially when animated. Lastly, using environment mapping to reflect the color of the sky onto the water helped us create a realistic and visually appealing water surface.
Despite rendering our fireflies as particles on a 2D plane, we still wanted to have a 3D effect with the fireflies and create a sense of depth. To do so, we added 2 sets of fireflies. Set 1 of the fireflies moved along the x and z directions. Set 2 of the fireflies, however, would also get larger and smaller (using the clamp and sin functions) to make it appear as if the fireflies are getting closer and farther. This resembled a depth of field.
A list of my contributions for this group project: