|
1 /* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim: set ts=2 et sw=2 tw=80: */ |
|
3 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 "use strict"; |
|
7 |
|
8 /** |
|
9 * This worker handles picking, given a set of vertices and a ray (calculates |
|
10 * the intersection points and offers back information about the closest hit). |
|
11 * |
|
12 * Used in the TiltVisualization.Presenter object. |
|
13 */ |
|
14 self.onmessage = function TWP_onMessage(event) |
|
15 { |
|
16 let data = event.data; |
|
17 let vertices = data.vertices; |
|
18 let ray = data.ray; |
|
19 |
|
20 let intersection = null; |
|
21 let hit = []; |
|
22 |
|
23 // calculates the squared distance between two points |
|
24 function dsq(p1, p2) { |
|
25 let xd = p2[0] - p1[0]; |
|
26 let yd = p2[1] - p1[1]; |
|
27 let zd = p2[2] - p1[2]; |
|
28 |
|
29 return xd * xd + yd * yd + zd * zd; |
|
30 } |
|
31 |
|
32 // check each stack face in the visualization mesh for intersections with |
|
33 // the mouse ray (using a ray picking algorithm) |
|
34 for (let i = 0, len = vertices.length; i < len; i += 36) { |
|
35 |
|
36 // the front quad |
|
37 let v0f = [vertices[i], vertices[i + 1], vertices[i + 2]]; |
|
38 let v1f = [vertices[i + 3], vertices[i + 4], vertices[i + 5]]; |
|
39 let v2f = [vertices[i + 6], vertices[i + 7], vertices[i + 8]]; |
|
40 let v3f = [vertices[i + 9], vertices[i + 10], vertices[i + 11]]; |
|
41 |
|
42 // the back quad |
|
43 let v0b = [vertices[i + 24], vertices[i + 25], vertices[i + 26]]; |
|
44 let v1b = [vertices[i + 27], vertices[i + 28], vertices[i + 29]]; |
|
45 let v2b = [vertices[i + 30], vertices[i + 31], vertices[i + 32]]; |
|
46 let v3b = [vertices[i + 33], vertices[i + 34], vertices[i + 35]]; |
|
47 |
|
48 // don't do anything with degenerate quads |
|
49 if (!v0f[0] && !v1f[0] && !v2f[0] && !v3f[0]) { |
|
50 continue; |
|
51 } |
|
52 |
|
53 // for each triangle in the stack box, check for the intersections |
|
54 if (self.intersect(v0f, v1f, v2f, ray, hit) || // front left |
|
55 self.intersect(v0f, v2f, v3f, ray, hit) || // front right |
|
56 self.intersect(v0b, v1b, v1f, ray, hit) || // left back |
|
57 self.intersect(v0b, v1f, v0f, ray, hit) || // left front |
|
58 self.intersect(v3f, v2b, v3b, ray, hit) || // right back |
|
59 self.intersect(v3f, v2f, v2b, ray, hit) || // right front |
|
60 self.intersect(v0b, v0f, v3f, ray, hit) || // top left |
|
61 self.intersect(v0b, v3f, v3b, ray, hit) || // top right |
|
62 self.intersect(v1f, v1b, v2b, ray, hit) || // bottom left |
|
63 self.intersect(v1f, v2b, v2f, ray, hit)) { // bottom right |
|
64 |
|
65 // calculate the distance between the intersection hit point and camera |
|
66 let d = dsq(hit, ray.origin); |
|
67 |
|
68 // we're picking the closest stack in the mesh from the camera |
|
69 if (intersection === null || d < intersection.distance) { |
|
70 intersection = { |
|
71 // each mesh stack is composed of 12 vertices, so there's information |
|
72 // about a node once in 12 * 3 = 36 iterations (to avoid duplication) |
|
73 index: i / 36, |
|
74 distance: d |
|
75 }; |
|
76 } |
|
77 } |
|
78 } |
|
79 |
|
80 self.postMessage(intersection); |
|
81 close(); |
|
82 }; |
|
83 |
|
84 /** |
|
85 * Utility function for finding intersections between a ray and a triangle. |
|
86 */ |
|
87 self.intersect = (function() { |
|
88 |
|
89 // creates a new instance of a vector |
|
90 function create() { |
|
91 return new Float32Array(3); |
|
92 } |
|
93 |
|
94 // performs a vector addition |
|
95 function add(aVec, aVec2, aDest) { |
|
96 aDest[0] = aVec[0] + aVec2[0]; |
|
97 aDest[1] = aVec[1] + aVec2[1]; |
|
98 aDest[2] = aVec[2] + aVec2[2]; |
|
99 return aDest; |
|
100 } |
|
101 |
|
102 // performs a vector subtraction |
|
103 function subtract(aVec, aVec2, aDest) { |
|
104 aDest[0] = aVec[0] - aVec2[0]; |
|
105 aDest[1] = aVec[1] - aVec2[1]; |
|
106 aDest[2] = aVec[2] - aVec2[2]; |
|
107 return aDest; |
|
108 } |
|
109 |
|
110 // performs a vector scaling |
|
111 function scale(aVec, aVal, aDest) { |
|
112 aDest[0] = aVec[0] * aVal; |
|
113 aDest[1] = aVec[1] * aVal; |
|
114 aDest[2] = aVec[2] * aVal; |
|
115 return aDest; |
|
116 } |
|
117 |
|
118 // generates the cross product of two vectors |
|
119 function cross(aVec, aVec2, aDest) { |
|
120 let x = aVec[0]; |
|
121 let y = aVec[1]; |
|
122 let z = aVec[2]; |
|
123 let x2 = aVec2[0]; |
|
124 let y2 = aVec2[1]; |
|
125 let z2 = aVec2[2]; |
|
126 |
|
127 aDest[0] = y * z2 - z * y2; |
|
128 aDest[1] = z * x2 - x * z2; |
|
129 aDest[2] = x * y2 - y * x2; |
|
130 return aDest; |
|
131 } |
|
132 |
|
133 // calculates the dot product of two vectors |
|
134 function dot(aVec, aVec2) { |
|
135 return aVec[0] * aVec2[0] + aVec[1] * aVec2[1] + aVec[2] * aVec2[2]; |
|
136 } |
|
137 |
|
138 let edge1 = create(); |
|
139 let edge2 = create(); |
|
140 let pvec = create(); |
|
141 let tvec = create(); |
|
142 let qvec = create(); |
|
143 let lvec = create(); |
|
144 |
|
145 // checks for ray-triangle intersections using the Fast Minimum-Storage |
|
146 // (simplified) algorithm by Tomas Moller and Ben Trumbore |
|
147 return function intersect(aVert0, aVert1, aVert2, aRay, aDest) { |
|
148 let dir = aRay.direction; |
|
149 let orig = aRay.origin; |
|
150 |
|
151 // find vectors for two edges sharing vert0 |
|
152 subtract(aVert1, aVert0, edge1); |
|
153 subtract(aVert2, aVert0, edge2); |
|
154 |
|
155 // begin calculating determinant - also used to calculate the U parameter |
|
156 cross(dir, edge2, pvec); |
|
157 |
|
158 // if determinant is near zero, ray lines in plane of triangle |
|
159 let inv_det = 1 / dot(edge1, pvec); |
|
160 |
|
161 // calculate distance from vert0 to ray origin |
|
162 subtract(orig, aVert0, tvec); |
|
163 |
|
164 // calculate U parameter and test bounds |
|
165 let u = dot(tvec, pvec) * inv_det; |
|
166 if (u < 0 || u > 1) { |
|
167 return false; |
|
168 } |
|
169 |
|
170 // prepare to test V parameter |
|
171 cross(tvec, edge1, qvec); |
|
172 |
|
173 // calculate V parameter and test bounds |
|
174 let v = dot(dir, qvec) * inv_det; |
|
175 if (v < 0 || u + v > 1) { |
|
176 return false; |
|
177 } |
|
178 |
|
179 // calculate T, ray intersects triangle |
|
180 let t = dot(edge2, qvec) * inv_det; |
|
181 |
|
182 scale(dir, t, lvec); |
|
183 add(orig, lvec, aDest); |
|
184 return true; |
|
185 }; |
|
186 }()); |