├── 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 | |
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 |
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
--------------------------------------------------------------------------------