]> gitweb.ps.run Git - cloth_sim/blob - Scripts/main.js
fix exploding behaviour
[cloth_sim] / Scripts / main.js
1 \r
2 \r
3 function addLights(scene){\r
4   scene.add(new THREE.AmbientLight(0x222222));\r
5 \r
6   const light1 = new THREE.PointLight(0xffffff, 1, 50);\r
7   light1.position.set(15, 1, 40);\r
8   scene.add(light1);\r
9 \r
10   const light2 = new THREE.PointLight(0xffffff, 1, 50);\r
11   light2.position.set(-15, 0, 40);\r
12   scene.add(light2);\r
13 \r
14   const light3 = new THREE.PointLight(0xffffff, 1, 50);\r
15   light3.position.set(0, -1, 40);\r
16   scene.add(light3);\r
17 }\r
18 \r
19 /**\r
20  * setup THREE JS Scene, Camera and Renderer\r
21  */\r
22 function setup_scene(canvasSpace) {\r
23   const scene = new THREE.Scene();\r
24   const camera = new THREE.PerspectiveCamera(75, window.innerWidth / (window.innerHeight - canvasSpace), 0.1, 1000);\r
25   const renderer = new THREE.WebGLRenderer();\r
26   /** size canvas to leave some space for UI */\r
27   renderer.setSize(window.innerWidth, window.innerHeight - canvasSpace);\r
28   renderer.antialias = true;\r
29   /** embed canvas in HTML */\r
30   document.getElementById("threejscontainer").appendChild(renderer.domElement);\r
31 \r
32   /** add orbit controls */\r
33   const controls = new THREE.OrbitControls(camera, renderer.domElement);\r
34   controls.target.set(0, 0, 0);\r
35   controls.update();\r
36 \r
37   /** add scene background */\r
38   const loader = new THREE.TextureLoader();\r
39   const texture = loader.load(\r
40     'Textures/tears_of_steel_bridge_2k.jpg',\r
41     () => {\r
42       const rt = new THREE.WebGLCubeRenderTarget(texture.image.height);\r
43       rt.fromEquirectangularTexture(renderer, texture);\r
44       scene.background = rt;\r
45     });\r
46 \r
47   /** add flag pole */\r
48   const geometry = new THREE.CylinderGeometry(0.02, 0.02, 5, 32);\r
49   const material = new THREE.MeshStandardMaterial({color: 0xffffff});\r
50   const cylinder = new THREE.Mesh(geometry, material);\r
51   cylinder.position.set(-0.5, -2.25, 0);\r
52   scene.add(cylinder);\r
53 \r
54   /** add global light */\r
55   const directionalLight = new THREE.DirectionalLight(0xffffff, 1);\r
56   scene.add(directionalLight);\r
57 \r
58   /** position camera */\r
59   camera.position.z = 2;\r
60   addLights(scene);\r
61   return [scene, camera, renderer];\r
62 }\r
63 \r
64 /** call "init" when document is fully loaded */\r
65 document.body.onload = init;\r
66 \r
67 function init() {\r
68   let mousePos = new THREE.Vector2();\r
69   \r
70   /**\r
71    * Space left empty under canvas\r
72    * for UI elements\r
73    */\r
74   const canvasSpace = 200;\r
75 \r
76   /** Constant Frame Time */\r
77   const frameTime = 1000.0 / 200.0;\r
78 \r
79   /** Setup scene */\r
80   let [scene, camera, renderer] = setup_scene(canvasSpace);\r
81   \r
82   const loader = new THREE.TextureLoader();\r
83   //Red color: 0xC70039\r
84 \r
85   const cloth = new Cloth(1, 0.5, 20, 20);\r
86   const clothGeometry = cloth.generateGeometry();\r
87   const clothMaterial = new THREE.MeshStandardMaterial({ map: loader.load('Textures/hsrm2.png'), color: {type: "c", value: new THREE.Color(0xffffff)}, side: THREE.DoubleSide, flatShading: false, transparent: true });\r
88   //const clothMaterial = new THREE.MeshStandardMaterial({ color: 0xC70039, side: THREE.DoubleSide, flatShading: false });\r
89   const clothMesh = new THREE.Mesh(clothGeometry, clothMaterial);\r
90   scene.add(clothMesh);\r
91   \r
92   document.getElementById("windToggle").checked = options.wind;\r
93   document.getElementById("windToggle").onchange = (e) => {\r
94     options.wind = e.target.checked;\r
95   };\r
96 \r
97   let raycaster = new THREE.Raycaster();\r
98   let intersects;\r
99   let windKeyDown = false;\r
100   let dragKeyDown = false;\r
101   let draggedIndex = -1;\r
102   /**\r
103    * function called every frame\r
104    * @param {number} dt - time passed since last frame in ms\r
105    */\r
106   function animate(dt) {\r
107     cloth.simulate(dt / 1000);\r
108 \r
109     cloth.updateGeometry(clothGeometry);\r
110     \r
111     raycaster.setFromCamera(new THREE.Vector2((mousePos.x / w) * 2 - 1, ((h - mousePos.y) / h) * 2 - 1), camera);\r
112 \r
113     intersects = raycaster.intersectObject(clothMesh);\r
114 \r
115     if (intersects.length > 0) {\r
116       if (windKeyDown)\r
117         cloth.blow(camera.position, intersects);\r
118       if (dragKeyDown && draggedIndex == -1)\r
119         draggedIndex = intersects[0].face.a;\r
120     }\r
121     if (dragKeyDown && draggedIndex != -1)\r
122       cloth.drag(calculateMousePosToWorld(mousePos), draggedIndex);\r
123     setTimeout(() => {\r
124       animate(frameTime);\r
125     }, frameTime);\r
126     renderer.render(scene, camera);\r
127   }\r
128 \r
129 \r
130   /** add callback for window resize */\r
131   let canvas = document.getElementsByTagName("canvas")[0];\r
132   let w = window.innerWidth;\r
133   let h = window.innerHeight - canvasSpace;\r
134   let resize = function () {\r
135     w = window.innerWidth;\r
136     h = window.innerHeight - canvasSpace;\r
137     canvas.width = w;\r
138     canvas.height = h;\r
139   }\r
140   window.onresize = resize;\r
141   resize();\r
142 \r
143   /**\r
144    * if canvas has been successfully initialized\r
145    * start rendering\r
146    */\r
147   if (canvas.getContext) {\r
148     animate(frameTime);\r
149   }\r
150 \r
151   \r
152 \r
153   /** add mouse move callback */\r
154   canvas.onmousemove = (evt) => {\r
155     mousePos.x = evt.clientX;\r
156     mousePos.y = evt.clientY;\r
157   };\r
158 \r
159   /**\r
160    * Prevent context menu while blowing wind\r
161    */\r
162   canvas.addEventListener('contextmenu', function(evt) { \r
163     evt.preventDefault();\r
164   }, false);\r
165 \r
166   document.onkeydown = (evt) => {\r
167     if (evt.code === "KeyW")\r
168       windKeyDown = true;\r
169     if (evt.code === "KeyD")\r
170       dragKeyDown = true;\r
171   };\r
172 \r
173   document.onkeyup = (evt) => {\r
174     if (evt.code === "KeyW")\r
175       windKeyDown = false;\r
176     if (evt.code === "KeyD") {\r
177       dragKeyDown = false;\r
178       draggedIndex = -1;\r
179     }\r
180   };\r
181 \r
182   function calculateMousePosToWorld(mousePos){\r
183     var vec = new THREE.Vector3(); // create once and reuse\r
184     var pos = new THREE.Vector3(); // create once and reuse\r
185 \r
186     vec.set(\r
187       (mousePos.x / window.innerWidth) * 2 - 1,\r
188     - (mousePos.y / window.innerHeight) * 2 + 1,\r
189       0.5);\r
190 \r
191     vec.unproject(camera);\r
192 \r
193     vec.sub(camera.position).normalize();\r
194 \r
195     var distance = - camera.position.z / vec.z;\r
196 \r
197     pos.copy(camera.position).add(vec.multiplyScalar(distance));\r
198     return pos;\r
199   }\r
200 }