1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/browser/devtools/tilt/TiltWorkerPicker.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,186 @@ 1.4 +/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 +"use strict"; 1.10 + 1.11 +/** 1.12 + * This worker handles picking, given a set of vertices and a ray (calculates 1.13 + * the intersection points and offers back information about the closest hit). 1.14 + * 1.15 + * Used in the TiltVisualization.Presenter object. 1.16 + */ 1.17 +self.onmessage = function TWP_onMessage(event) 1.18 +{ 1.19 + let data = event.data; 1.20 + let vertices = data.vertices; 1.21 + let ray = data.ray; 1.22 + 1.23 + let intersection = null; 1.24 + let hit = []; 1.25 + 1.26 + // calculates the squared distance between two points 1.27 + function dsq(p1, p2) { 1.28 + let xd = p2[0] - p1[0]; 1.29 + let yd = p2[1] - p1[1]; 1.30 + let zd = p2[2] - p1[2]; 1.31 + 1.32 + return xd * xd + yd * yd + zd * zd; 1.33 + } 1.34 + 1.35 + // check each stack face in the visualization mesh for intersections with 1.36 + // the mouse ray (using a ray picking algorithm) 1.37 + for (let i = 0, len = vertices.length; i < len; i += 36) { 1.38 + 1.39 + // the front quad 1.40 + let v0f = [vertices[i], vertices[i + 1], vertices[i + 2]]; 1.41 + let v1f = [vertices[i + 3], vertices[i + 4], vertices[i + 5]]; 1.42 + let v2f = [vertices[i + 6], vertices[i + 7], vertices[i + 8]]; 1.43 + let v3f = [vertices[i + 9], vertices[i + 10], vertices[i + 11]]; 1.44 + 1.45 + // the back quad 1.46 + let v0b = [vertices[i + 24], vertices[i + 25], vertices[i + 26]]; 1.47 + let v1b = [vertices[i + 27], vertices[i + 28], vertices[i + 29]]; 1.48 + let v2b = [vertices[i + 30], vertices[i + 31], vertices[i + 32]]; 1.49 + let v3b = [vertices[i + 33], vertices[i + 34], vertices[i + 35]]; 1.50 + 1.51 + // don't do anything with degenerate quads 1.52 + if (!v0f[0] && !v1f[0] && !v2f[0] && !v3f[0]) { 1.53 + continue; 1.54 + } 1.55 + 1.56 + // for each triangle in the stack box, check for the intersections 1.57 + if (self.intersect(v0f, v1f, v2f, ray, hit) || // front left 1.58 + self.intersect(v0f, v2f, v3f, ray, hit) || // front right 1.59 + self.intersect(v0b, v1b, v1f, ray, hit) || // left back 1.60 + self.intersect(v0b, v1f, v0f, ray, hit) || // left front 1.61 + self.intersect(v3f, v2b, v3b, ray, hit) || // right back 1.62 + self.intersect(v3f, v2f, v2b, ray, hit) || // right front 1.63 + self.intersect(v0b, v0f, v3f, ray, hit) || // top left 1.64 + self.intersect(v0b, v3f, v3b, ray, hit) || // top right 1.65 + self.intersect(v1f, v1b, v2b, ray, hit) || // bottom left 1.66 + self.intersect(v1f, v2b, v2f, ray, hit)) { // bottom right 1.67 + 1.68 + // calculate the distance between the intersection hit point and camera 1.69 + let d = dsq(hit, ray.origin); 1.70 + 1.71 + // we're picking the closest stack in the mesh from the camera 1.72 + if (intersection === null || d < intersection.distance) { 1.73 + intersection = { 1.74 + // each mesh stack is composed of 12 vertices, so there's information 1.75 + // about a node once in 12 * 3 = 36 iterations (to avoid duplication) 1.76 + index: i / 36, 1.77 + distance: d 1.78 + }; 1.79 + } 1.80 + } 1.81 + } 1.82 + 1.83 + self.postMessage(intersection); 1.84 + close(); 1.85 +}; 1.86 + 1.87 +/** 1.88 + * Utility function for finding intersections between a ray and a triangle. 1.89 + */ 1.90 +self.intersect = (function() { 1.91 + 1.92 + // creates a new instance of a vector 1.93 + function create() { 1.94 + return new Float32Array(3); 1.95 + } 1.96 + 1.97 + // performs a vector addition 1.98 + function add(aVec, aVec2, aDest) { 1.99 + aDest[0] = aVec[0] + aVec2[0]; 1.100 + aDest[1] = aVec[1] + aVec2[1]; 1.101 + aDest[2] = aVec[2] + aVec2[2]; 1.102 + return aDest; 1.103 + } 1.104 + 1.105 + // performs a vector subtraction 1.106 + function subtract(aVec, aVec2, aDest) { 1.107 + aDest[0] = aVec[0] - aVec2[0]; 1.108 + aDest[1] = aVec[1] - aVec2[1]; 1.109 + aDest[2] = aVec[2] - aVec2[2]; 1.110 + return aDest; 1.111 + } 1.112 + 1.113 + // performs a vector scaling 1.114 + function scale(aVec, aVal, aDest) { 1.115 + aDest[0] = aVec[0] * aVal; 1.116 + aDest[1] = aVec[1] * aVal; 1.117 + aDest[2] = aVec[2] * aVal; 1.118 + return aDest; 1.119 + } 1.120 + 1.121 + // generates the cross product of two vectors 1.122 + function cross(aVec, aVec2, aDest) { 1.123 + let x = aVec[0]; 1.124 + let y = aVec[1]; 1.125 + let z = aVec[2]; 1.126 + let x2 = aVec2[0]; 1.127 + let y2 = aVec2[1]; 1.128 + let z2 = aVec2[2]; 1.129 + 1.130 + aDest[0] = y * z2 - z * y2; 1.131 + aDest[1] = z * x2 - x * z2; 1.132 + aDest[2] = x * y2 - y * x2; 1.133 + return aDest; 1.134 + } 1.135 + 1.136 + // calculates the dot product of two vectors 1.137 + function dot(aVec, aVec2) { 1.138 + return aVec[0] * aVec2[0] + aVec[1] * aVec2[1] + aVec[2] * aVec2[2]; 1.139 + } 1.140 + 1.141 + let edge1 = create(); 1.142 + let edge2 = create(); 1.143 + let pvec = create(); 1.144 + let tvec = create(); 1.145 + let qvec = create(); 1.146 + let lvec = create(); 1.147 + 1.148 + // checks for ray-triangle intersections using the Fast Minimum-Storage 1.149 + // (simplified) algorithm by Tomas Moller and Ben Trumbore 1.150 + return function intersect(aVert0, aVert1, aVert2, aRay, aDest) { 1.151 + let dir = aRay.direction; 1.152 + let orig = aRay.origin; 1.153 + 1.154 + // find vectors for two edges sharing vert0 1.155 + subtract(aVert1, aVert0, edge1); 1.156 + subtract(aVert2, aVert0, edge2); 1.157 + 1.158 + // begin calculating determinant - also used to calculate the U parameter 1.159 + cross(dir, edge2, pvec); 1.160 + 1.161 + // if determinant is near zero, ray lines in plane of triangle 1.162 + let inv_det = 1 / dot(edge1, pvec); 1.163 + 1.164 + // calculate distance from vert0 to ray origin 1.165 + subtract(orig, aVert0, tvec); 1.166 + 1.167 + // calculate U parameter and test bounds 1.168 + let u = dot(tvec, pvec) * inv_det; 1.169 + if (u < 0 || u > 1) { 1.170 + return false; 1.171 + } 1.172 + 1.173 + // prepare to test V parameter 1.174 + cross(tvec, edge1, qvec); 1.175 + 1.176 + // calculate V parameter and test bounds 1.177 + let v = dot(dir, qvec) * inv_det; 1.178 + if (v < 0 || u + v > 1) { 1.179 + return false; 1.180 + } 1.181 + 1.182 + // calculate T, ray intersects triangle 1.183 + let t = dot(edge2, qvec) * inv_det; 1.184 + 1.185 + scale(dir, t, lvec); 1.186 + add(orig, lvec, aDest); 1.187 + return true; 1.188 + }; 1.189 +}());