# Sunshiny Shower **Repository Path**: l-wy/sunshiny-shower ## Basic Information - **Project Name**: Sunshiny Shower - **Description**: A Processing Project for UCAS Data Structure Course 2021 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 2 - **Forks**: 0 - **Created**: 2021-07-15 - **Last Updated**: 2022-04-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Sunshiny Shower A Processing Project for UCAS Data Structure Course 2021 ## Demand Analysis 1. Random determination of the location of the raindrop in the air, the visibility of the landing process, the location of the water entry, the color, the maximum water circle, etc.. 2. The simultaneous demonstration of multiple rain spots on the screen according to random parameters and states of existence at various levels. 3. The ability to adjust parameters controlling the density of rain points, state changes, etc. 4. **Additional requirement 1:** Adding the "lightning and thunder" scene in "Night rain on the pond". 5. **Additional requirement 2:** Adding the scene of "rain and wind" in "Night rain on the pond". 7. **Additional Requirement 3:** Adding the scene of "mild rain and wind" and "strong storm" in "Rain in the pond". 8. **Additional Requirement 4: **Change "pond rain" to "lotus pond rain", and change the sound and splash effect of raindrops. ## The Rain Model **The Rain Model** is powered by a linked-list-based **Queue** implementation. Each item in the queue contains the value of the stored object (`this.item`), and a reference to the next queue item (`this.next`). The **Queue**, implemented based on a linked list, saves a reference to the head of the queue (`this.head`), a reference to the tail of the queue (`this.tail`) and the number of items currently in the queue (`this.length`). ``` JavaScript class QueueNode { constructor(value) { this.item = value; this.next = null; } // Create Node } // Queue Node class Queue { constructor() { this.head = null; this.tail = null; this.length = 0; } // Initialize Queue enqueue(value) {...} dequeue() {...} } // Trival Queue Implementation ``` Before each frame is rendered on the screen, a random number is generated and compared against the user defined threshold, which decides whether new rain drops will be appended in the next frame of the animation. A group of rain drops will be appended if the random number generated satisfies the user defined threshold. Specially, the number of rain drops appened before each frame is rendered also has its randomization nature. Rain drops appended are initialized at the same height, even though they differ in the horizontal location and color. After the initialization, the rain drops are appended at the end of the **Queue**. ``` JavaScript if ((Canva.RainDrops.length < Rain.MaxNum) // If More Rain Drops Can be Appended to the World && (eventTrigger < 0.5*Number(Rain.Emiter.value))) { // If the Random Number Satisfies the User Defined Threshold for (let count = 0, num = Math.random()*Rain.Groups; count < num; count++) // Initialize a Group of Rain Drops to be Appended Canva.RainDrops.enqueue(new RainDrop()); } // Generate Rain Drops for the World ``` Note that the total number of rain drops may suppass the maximal number defined after the initialization, which is considered **natural** since the number of rain drops in the actual world fluctuates around a certain amount. When rendering the current frame, each rain drop is dequeued and tested against the corresponding altitude of the terrain. If the rain drop hasn't reached the ground, its new location will be calculated with respect to gravitation and wind speed before been enqueued at the tail of the **Queue**. If the rain drop has reached the ground, however, different terrain animations will be triggered according to whether the rain descends on the pond or the land. In addition, each rain drop has a chance to "revive" after reaching "the end of its lifetime". This mechanism is designed to simulate the natural world where rain ceases gradually and slowly, rather than abruptly. ``` JavaScript for (let count = 0; count < length; count++) { // For Every Rain Drop Currently in the Queue const drop = Canva.RainDrops.dequeue(); const surf = Canva.Terrain.surface(drop.location[0], drop.location[2]); if (drop.location[1] > surf[0]) { // Trigger Terrain Animation if the Rain Drop Has Reached the Ground const animate = (surf[0] < 0) ? new Splash(drop.location[0], surf[0], drop.location[2], drop.color) : new Ripple(drop.location[0], drop.location[2], 8, drop.color); Canva.Terrain.meshActions.enqueue(animate); // Test and Revive the Rain Drop if ((Canva.RainDrops.length < Rain.MaxNum) // If More Rain Drops Can be Appended to the World && (Math.random() < Rain.Revive)) { // Revive When the Condition is Satisfied Canva.RainDrops.enqueue(new RainDrop()); } // Generate Rain Drops } // Remove Rain Drop and Trigger Animation else { const shiftW = Number(World.WindStr.value)*(Math.random() - 0.5)/3; const shiftD = Number(World.WindStr.value)*(Math.random() - 0.5)/4; // Add Fluctuation to Simulate Air Flow Disturbance drop.render(); drop.descend(WindW + shiftW, WindD + shiftD); Canva.RainDrops.enqueue(drop); } // Render and Generate Next Location } // Render Rain Drops for the World ``` The **Queue** data structure has been chosen to power **The Rain Model** for several reasons: 1) **Queue** is not only easy to implement but also provides high convenience since the organization of all rain drops in the air involves huge number of insertion and removal operations, which take place when rain drops either reach the ground or are initialized. 2) **Queue** simulates the descending process of rain drops, where rain drops generated early in time are less distant from the ground than those generated later. The height of rain drops in the air reflects their position in the queue. Newly generated rain drops are appended to the tail of the queue as they are at the highest altitude. Rain drops near the head of the queue represent those who will reach the ground in an instant. 3) **Queue** can be shifted and applied to other animations, such as ripples and water splashes after the rain drops on the ground. 4) **Queue** can be conveniently combined with randomization to naturally mimic rain in the natural world. ## Procedural Terrain **Procedural Terrain Generation** in this project is implemented using **Perlin Noise**. ## Current Stage - ***(Completed)*** Basic Procedural Terrain Generation - ***(Completed)*** Basic Model for Raining Effect - ***(Completed)*** Basic Sound Effect System - More Detailed Documentation for the Project ## Result of Project ![figure1_main_interface](.\doc\pics\figure1_main_interface.jpg) `Figure 1: main_interface` Users can adjust the sliders below to change parameters such as rainfall, wind speed, wind direction and viewing angle. ![figure2_comparsion_of_different_rainforce](.\doc\pics\figure2_comparsion_of_different_rainforce.jpg) `Figure 2: comparision_of_different_rainforce` As shown in Figure 2, the sky gradually becomes darker as the amount of rain increases. ![figure3_comparision_of_wind_direction](.\doc\pics\figure3_comparision_of_wind_direction.jpg) `Figure 3: comparision_of_different_WindDirection` ![figure4_lightening](.\doc\pics\figure4_lightening.jpg) `Figure 4: effect_of_lightening` ![figure5_different_camera_views](.\doc\pics\figure5_different_camera_views.jpg) `Figure 5: another_camera_vie_of_this_scene` ## Usage 1) Git clone **this** repository. 2) Double click and open `sunshinyshower.html` under the `source` directory directly in the browser(Chrome,Firefox or Safari), sit back, and play with adjustable parameters. 3) ***(Optional)*** Load `develop.html` under the `source` directory with a local server and visit the webpage in the browser. ## Contributors - ***Zhao Yuanhao*** completed the model of the rain, procedural terrain generation and the final animation. He also contributed most lines of code to the `sunshinyshower` project. - ***Li Wenyi*** proposed ideas for the model of the rain, processed audio files for sound effects and designed the front end interface. ## Acknowledgement Special thanks for everyone who has contributed his/her wisdom to the development of **p5.js**, without which this project wouldn't be made possible.