├── LICENSE ├── README.md ├── _config.yml ├── helperFns.js ├── main.html ├── pictures ├── boids1.png └── boids2.png ├── textures └── wood_texture.jpg └── three.min.js /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Lucien David 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # THREE.js Crowd Animation 2 | 3 | A demonstration of a THREE.js crowd animation scene. 4 | You can quickly visualize it here. 5 | 6 | ## The scene 7 | 8 | A light bulb swings left to right inside a wooden room, and a group of boids are following the bulb, 9 | as moths would do. 10 | The camera travels around the room with a slow motion when coming closer to the light. 11 | 12 | Left ... | ... and right 13 | --------------------------|-------------------------- 14 | ![](./pictures/boids1.png)|![](./pictures/boids2.png) 15 | 16 | ## The crowd settings 17 | 18 | I decided of the following parameters to modulate the direction of boids (in order of priority) 19 | * Avoid the collision with the light at all costs 20 | * Pursuie the light 21 | * Avoid collisions between boids 22 | * Ensure boids are moving in the same direction 23 | * Ensure boids are flying close enough to eachother 24 | 25 | # How to make it work 26 | 27 | To make it work, download the repo, then use the following process: https://threejs.org/docs/index.html#manual/en/introduction/How-to-run-things-locally 28 | 29 | To sum it up, just run a localhost on your machine (I personally use python -m http.server), then go to your localhost on your browser and just admire the result. 30 | 31 | If you have any suggestion, do not hesitate and leave a comment or a pull request, I'd be happy to add it to the project. 32 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /helperFns.js: -------------------------------------------------------------------------------- 1 | // INIT FUNCTION: I recommend you to play with the boid motion parameters, it is quite funny 2 | 3 | function initParameters() { 4 | 5 | // BULB PARAMETERS : 6 | // gravity constant, time, light intensity, pulsation of an approximate simple pendulum (small oscillations hypothesis), motion Ratio to decide 7 | // of the speed ratio with real life (motionRatio = 1) at max speed, shiftRatio to decide how strong the wire bends around its middle point, and roomSize 8 | g = 9.81 9 | t = 0 10 | lightIntensity = 2 11 | theta = view.theta0*Math.PI/180; 12 | length = view.length 13 | z0 = view.z0 14 | theorethicalPulse = Math.sqrt(g/length) 15 | motionRatio = 3 16 | w0 = theorethicalPulse*motionRatio 17 | shiftRatio = 1/10 18 | roomSize = 150 19 | 20 | // BOIDS MOTION PARAMETERS : 21 | // boids SpeedScale, number of boids, width of repartition of boids at t=0, surrounding distance, minimum distance to light, and continuityRatio, 22 | // the proportion of old speed vector kept in the new one 23 | SpeedScale = 1 24 | numberOfBoids = 50 25 | boidSize = 0.4 26 | startWidth = 200 27 | surrounding_distance = 1.5 28 | minDistanceLight = 1.5 29 | continuityRatio = 0.7 30 | 31 | // CAMERA MOTION PARAMETERS : 32 | // up camera motion boolean, period and pulsation of rotation, ellipse axe sizes, initial height, z(t) parameters, proportion of lookAt vectors (see updateCamera) 33 | goingUp = true 34 | T = 15 35 | omega = 2*Math.PI/(60*T) 36 | a = view.eye[0] 37 | b = 40 38 | z1 = view.eye[2] 39 | zcons = z1 40 | zstep = (z0-2*z1)/(60*T) 41 | p = 1 42 | 43 | // TIME DILATATION PARAMETERS : 44 | // alpha = the time dilatation incrementing time, oscillating from maxTimeDilatation to minTimeDilatation at pulse angular speed 45 | // (pulse is defined such as it has a T/2 period and reaches minimum at T/4, thus when the camera is the closest to the bulb) with amp Amplitude with an additive 46 | // constant cons (defined such as its max is maxTimeDilatation, reached every even*T/4 time, and its min is minTimeDilatation, reached every odd*T/4 time) 47 | alpha = 1 48 | maxTimeDilatation = 1 49 | minTimeDilatation = 0.25 50 | pulse = 4*Math.PI/(60*T) 51 | amp = (maxTimeDilatation - minTimeDilatation)/2 52 | cons = maxTimeDilatation - amp 53 | 54 | } 55 | 56 | function init() { 57 | initParameters(); 58 | // Build scene 59 | container = document.getElementById( 'container' ); 60 | 61 | view.camera = new THREE.PerspectiveCamera( view.fov, window.innerWidth / window.innerHeight, view.near, view.far ); 62 | view.camera.position.fromArray( view.eye ); 63 | view.camera.up.fromArray( view.up ); 64 | 65 | scene = new THREE.Scene(); 66 | 67 | // Create bulb mesh attached to a light + a weak ambient hemisphere light 68 | let geometry = new THREE.SphereGeometry( 1, 32, 32 ); 69 | var material = new THREE. MeshStandardMaterial({color:0x000000,emissive:0xffffff,emissiveIntensity:lightIntensity}); 70 | bulb = new THREE.Mesh( geometry, material ); 71 | light = new THREE.PointLight(0xF5DCAF,lightIntensity,Infinity,2) 72 | light.power = lightIntensity*20000 73 | light.position.set(0,length*Math.sin(theta),z0-length*Math.cos(theta)) 74 | light.add(bulb) 75 | light.castShadow = true; 76 | hemiLight = new THREE.HemisphereLight( 0xddeeff, 0x0f0e0d, 0.1 ); 77 | scene.add(hemiLight) 78 | scene.add(light) 79 | 80 | // Create the wire linking the bulb to the roof 81 | var curveObject = drawSpline(light.position,{x:0,y:0,z:z0},0xffffff); 82 | scene.add(curveObject) 83 | 84 | // Create the room 85 | var room = createRoom(z0) 86 | scene.add(room) 87 | 88 | //create a group of boids 89 | boids = new THREE.Group() 90 | for (let i=0;i= 0) 136 | if (Math.floor(t/(T*60))%2 == 0){ 137 | if (goingUp == false){ 138 | goingUp=true; 139 | console.log("going up") 140 | } 141 | zcons=z1; 142 | zstep=(z0-2*z1)/(60*T); 143 | } 144 | else if (Math.floor(t/(T*60))%2 == 1){ 145 | if (goingUp == true){ 146 | goingUp=false; 147 | console.log("going down") 148 | } 149 | zcons=z0-z1; 150 | zstep=(2*z1-z0)/(60*T); 151 | } 152 | 153 | // Boids update relies on next bulb position, thus update boids positions before bulb position 154 | animateBoids(); 155 | animateBulb(); 156 | 157 | // Update the camera position 158 | animateCamera(); 159 | 160 | render(); 161 | requestAnimationFrame( animate ); 162 | 163 | 164 | } 165 | 166 | function animateBulb(){ 167 | 168 | // Recompute theta (motionRatio is an arbitrary parameter set to make the motion realistic) 169 | theta = Math.PI/180*view.theta0*Math.cos(w0*t/60) 170 | light.position.set(0,length*Math.sin(theta),z0-length*Math.cos(theta)) 171 | 172 | scene.children[2] = drawSpline(light.position,{x:0,y:0,z:z0},0xffffff) 173 | } 174 | 175 | function animateBoids(){ 176 | 177 | for (let i=0;iminDistanceLight 465 | 466 | 467 | } 468 | 469 | // Return all the boids surrounding boid (distance from boid inferior to surrounding_distance) 470 | function surroundingBoids(boid, surrounding_distance){ 471 | 472 | let res = [] 473 | let boidPosition = new THREE.Vector3(boid.position.x,boid.position.y,boid.position.z) 474 | var currentBoid, currentBoidPosition, distance 475 | 476 | for (let i=0;i 2 | 3 | 4 | three.js assignment 2 5 | 6 | 7 | 30 | 31 | 32 | 33 |
34 |
three.js - assignment 2 - webgl
35 | 36 | 37 | 79 | 80 | -------------------------------------------------------------------------------- /pictures/boids1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LuluDavid/THREE.js-Crowd-Animation/a308296bce912150047eaffe00fa4c3da8db785b/pictures/boids1.png -------------------------------------------------------------------------------- /pictures/boids2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LuluDavid/THREE.js-Crowd-Animation/a308296bce912150047eaffe00fa4c3da8db785b/pictures/boids2.png -------------------------------------------------------------------------------- /textures/wood_texture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LuluDavid/THREE.js-Crowd-Animation/a308296bce912150047eaffe00fa4c3da8db785b/textures/wood_texture.jpg --------------------------------------------------------------------------------