]> gitweb.ps.run Git - cloth_sim/blob - Scripts/main.js
Code refactoring
[cloth_sim] / Scripts / main.js
1 import { Face, Spring, Cloth } from './cloth.js';\r
2 \r
3 function addLights(scene){\r
4   \r
5   scene.add( new THREE.AmbientLight( 0x222222 ) );\r
6 \r
7   const light1 = new THREE.PointLight( 0xffffff, 1, 50 );\r
8   light1.position.set( 15, 1, 40 );\r
9   scene.add( light1 );\r
10 \r
11   const light2 = new THREE.PointLight( 0xffffff, 1, 50 );\r
12   light2.position.set( -15, 0, 40 );\r
13   scene.add( light2 );\r
14 \r
15   const light3 = new THREE.PointLight( 0xffffff, 1, 50 );\r
16   light3.position.set( 0, -1, 40 );\r
17   scene.add( light3 );\r
18   \r
19 }\r
20 \r
21 /**\r
22  * setup THREE JS Scene, Camera and Renderer\r
23  */\r
24 function setup_scene(canvasSpace) {\r
25   const scene = new THREE.Scene();\r
26   const camera = new THREE.PerspectiveCamera(75, window.innerWidth / (window.innerHeight - canvasSpace), 0.1, 1000);\r
27   const renderer = new THREE.WebGLRenderer();\r
28   /** size canvas to leave some space for UI */\r
29   renderer.setSize(window.innerWidth, window.innerHeight - canvasSpace);\r
30   /** embed canvas in HTML */\r
31   document.getElementById("threejscontainer").appendChild(renderer.domElement);\r
32 \r
33   /** add global light */\r
34   const directionalLight = new THREE.DirectionalLight(0xffffff, 1);\r
35   scene.add(directionalLight);\r
36 \r
37   /** position camera */\r
38   camera.position.y = 5;\r
39   camera.position.z = 10;\r
40   addLights(scene);\r
41   return [scene, camera, renderer];\r
42 }\r
43 \r
44 /** call "init" when document is fully loaded */\r
45 document.body.onload = init;\r
46 \r
47 function init() {\r
48   let mousePos = new THREE.Vector2();\r
49   let previousClothSimulation;\r
50   \r
51   /**\r
52    * Space left empty under canvas\r
53    * for UI elements\r
54    */\r
55   const canvasSpace = 200;\r
56 \r
57   /** Constant Frame Time */\r
58   const frameTime = 1000.0 / 60.0;\r
59 \r
60   /** Setup scene */\r
61   let [scene, camera, renderer] = setup_scene(canvasSpace);\r
62   \r
63   /** setup cloth and generate debug mesh */\r
64   let cloth = new Cloth();\r
65   cloth.createBasic(10, 10, 10, 10);\r
66   //cloth.createDebugMesh(scene);\r
67 \r
68 \r
69   const material = new THREE.MeshStandardMaterial({ color: 0xC70039, side: THREE.DoubleSide, flatShading: false });\r
70   const mesh = new THREE.Mesh(cloth.geometry, material);\r
71 \r
72   scene.add(mesh);\r
73 \r
74 \r
75   \r
76   let raycaster = new THREE.Raycaster();\r
77   let intersects;\r
78   let rightMousePressed;\r
79   /**\r
80    * function called every frame\r
81    * @param {number} dt - time passed since last frame in ms\r
82    */\r
83   function animate(dt) {\r
84     cloth.simulate(dt/1000);\r
85 \r
86     raycaster.setFromCamera( new THREE.Vector2((mousePos.x / w) * 2 - 1, ((h - mousePos.y) / h) * 2 - 1), camera );\r
87 \r
88     intersects = raycaster.intersectObject( mesh );\r
89 \r
90     if ( intersects.length > 0 && rightMousePressed) {\r
91       cloth.wind(intersects);\r
92     }\r
93     setTimeout(() => {\r
94       animate(frameTime);\r
95     }, frameTime);\r
96     renderer.render(scene, camera);\r
97   }\r
98 \r
99 \r
100   /** add callback for window resize */\r
101   let canvas = document.getElementsByTagName("canvas")[0];\r
102   let w = window.innerWidth;\r
103   let h = window.innerHeight - canvasSpace;\r
104   let resize = function () {\r
105     w = window.innerWidth;\r
106     h = window.innerHeight - canvasSpace;\r
107     canvas.width = w;\r
108     canvas.height = h;\r
109   }\r
110   window.onresize = resize;\r
111   resize();\r
112 \r
113   /**\r
114    * if canvas has been successfully initialized\r
115    * start rendering\r
116    */\r
117   if (canvas.getContext) {\r
118     animate(performance.now());\r
119   }\r
120 \r
121   \r
122 \r
123   /** add mouse move callback */\r
124   canvas.onmousemove = (evt) => {\r
125     mousePos.x = evt.clientX;\r
126     mousePos.y = evt.clientY;\r
127 \r
128     cloth.mouseMove(calculateMousePosToWorld(evt));\r
129   };\r
130 \r
131   /**\r
132    * Prevent context menu while blowing wind\r
133    */\r
134   canvas.addEventListener('contextmenu', function(evt) { \r
135     evt.preventDefault();\r
136   }, false);\r
137 \r
138 \r
139   canvas.onmousedown = (evt) => {\r
140 \r
141     // Check mouse click\r
142     rightMousePressed = evt.button == 2;\r
143     \r
144     if(intersects.length > 0 && evt.button == 0){\r
145       cloth.mousePress(intersects);\r
146     } \r
147   }\r
148   \r
149   canvas.onmouseup = (evt) => {\r
150     cloth.mouseRelease();\r
151     rightMousePressed = false;\r
152   }\r
153 \r
154   function calculateMousePosToWorld(evt){\r
155     var vec = new THREE.Vector3(); // create once and reuse\r
156     var pos = new THREE.Vector3(); // create once and reuse\r
157 \r
158     vec.set(\r
159       ( evt.clientX / window.innerWidth ) * 2 - 1,\r
160     - ( evt.clientY / window.innerHeight ) * 2 + 1,\r
161       0.5 );\r
162 \r
163     vec.unproject( camera );\r
164 \r
165     vec.sub( camera.position ).normalize();\r
166 \r
167     var distance = - camera.position.z / vec.z;\r
168 \r
169     pos.copy( camera.position ).add( vec.multiplyScalar( distance ) );\r
170     return pos;\r
171   }\r
172 }