Lighthouse
Water Simulation in GLSL
Collaborated with Kewen Huang, Kaihao Tian
My Role: Water Simulation | Integration
Scripting in GLSL
1 week
Dartmouth Computer Graphics Class
2023
We created an ocean scene complete with a towering lighthouse, whose beams of light shone like god rays. We wanted to capture the essence of the ocean, which often plays a central role in many epic journeys, while also providing a sense of safety and comfort to lost souls at sea. With our dynamic skybox, procedurally generated clouds, and realistic water simulation, we were able to create an immersive experience that left a lasting impression on our audience.
Skybox
At first, we tried to create a skybox using the cubemap texture as described in the tutorial by loading six 2D images into a single texture. However, some of the libraries we are supposed to import are not recognized for some reason. After some fruitless effort, we switched to using a box and manually pasting 6 textures on each of its sides. However, this also did not work out, as the albedo channel of my mesh is somehow lost. Eventually, we decided to do the sky background using a sphere skydome. I first created a sphere mesh with reversed normal in Maya, and loaded the obj file as the skydome mesh. Then, I created a shader that renders a 360 png image solely based on its vertex color and the uv of the sphere, without the influence of any light source.
The next step is to make the skybox achieve a day-night cycle. To do this, I modified the fragment shader so that it takes in two different textures and interpolates between them using a mix function. The parameter of the function takes the vertex color of both textures and a blend value retrieved from the absolute value of sin(iTime), which ranges from 0 to 1. We also made the skybox rotate by using a rotation matrix in the vertex shader.
Cloud and Lighthouse
Initially, we attempted to create clouds using worley noise, but found that it lacked the desired effect of making the clouds appear stretched out and was too uniform. As a result, we switched to using perlin noise in the shaders to procedurally generate the cloud model, similar to the approach we used in assignment 4 using the hash2 function, perlin_noise function, noiseOctave function, and height function. For the height function, we experimented with various mathematical formulas and adjusted different values to create a more natural and realistic shape for the clouds. Eventually, we settled on the following mathematical model to generate the cloud shape.
One challenge we had was to create a cloud that appears faintly discernible. We initially attempted to use the ray marching function, as it is a commonly used method for simulating cloud effects. However, we encountered difficulties in trying to achieve the desired effect, so we ultimately decided to use alpha blending. To determine the alpha value for the cloud, we first calculated the noise value using the noiseOctave function, but with more iterations to create a smoother effect. We then raised the noise value to certain power constants and scaled it to increase its intensity. Next, we made the cloud appear to move in the same direction as the skybox by adding the iTime variable to the position values. Additionally, we synchronized the color of the cloud with that of the skybox by using the mix function with the iTime variable.
To create the lighthouse, we first modeled it in Maya, using a cone shape for the lights. We then created alpha textures for the cone as well as specular and albedo textures for the lighthouse in Photoshop. In the fragment shader, we loaded each texture to be used for the alpha channel, specular coefficients, and base color. To mimic the effect of the light, we animated the alpha values by adding the sine function of iTime multiplied by 3, and then adding 3*0.5. We also animated the position of the light source to rotate with the cone light and made the diffuse values lerp between 1 and 0.65 to correspond with our day-night cycle.
Challenges
During the integration process, we encountered a significant challenge when the alpha blending didn't seem to work as expected. We found that when the alpha value was set to 0, it showed the background color instead of the skybox. Interestingly, we discovered that the alpha blending worked on some objects in the scene while others didn't, even though we used the same method to enable alpha blending on all our objects. After some troubleshooting, we wondered if the order in which each object was added to the scene mattered in rendering transparent objects, and we found out that it does. Therefore, we re-arranged the objects to be loaded in the desired order to achieve the desired effect.
Water
There were two parts for the water effect: motion and color. For the motion, we initially planned to use perlin noise in assignment 4 to simulate the waves. However, we realized that perlin noise couldn’t simulate the waves motion well due to its randomness. In order to solve this problem, we used sin to create waves and set amplitude, wavelength, base height, wave direction and speed to be variables. In order to add some dynamics, we applied noiseOctave to amplitude, wave direction and wavelength.
After finishing the motion simulation with basic lighting, we realized that the color is also important. We added alpha blend and specularity to the water. To better simulate the reflection on the water, we adjusted the alpha value of water to make sure the y-axis mirrored skybox can be seen through the water.
When we integrated all of the parts together, we realized that we need to adjust light and color for each part to match together. We spent much time together on fixing color, lighting and timing to increase the visual aesthetics.
Contribution
Kaihao, Kewen, and Diana each had specific responsibilities in this project. Kaihao was responsible for creating the dynamic skybox, Kewen was responsible for the cloud and lighthouse, and Diana was responsible for the water animation and lighting.