15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Copyright (C) 2007 Apple Inc. All rights reserved. 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Redistribution and use in source and binary forms, with or without 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * modification, are permitted provided that the following conditions 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * are met: 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 1. Redistributions of source code must retain the above copyright 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * notice, this list of conditions and the following disclaimer. 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 2. Redistributions in binary form must reproduce the above copyright 10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * notice, this list of conditions and the following disclaimer in the 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * documentation and/or other materials provided with the distribution. 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * 13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 14116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)function createVector(x,y,z) { 275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return new Array(x,y,z); 285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 296d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 306d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)function sqrLengthVector(self) { 31116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return self[0] * self[0] + self[1] * self[1] + self[2] * self[2]; 326d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)} 336d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)function lengthVector(self) { 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Math.sqrt(self[0] * self[0] + self[1] * self[1] + self[2] * self[2]); 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)function addVector(self, v) { 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self[0] += v[0]; 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self[1] += v[1]; 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self[2] += v[2]; 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self; 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)function subVector(self, v) { 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self[0] -= v[0]; 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self[1] -= v[1]; 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self[2] -= v[2]; 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self; 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)function scaleVector(self, scale) { 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self[0] *= scale; 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self[1] *= scale; 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self[2] *= scale; 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self; 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)function normaliseVector(self) { 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var len = Math.sqrt(self[0] * self[0] + self[1] * self[1] + self[2] * self[2]); 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self[0] /= len; 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self[1] /= len; 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self[2] /= len; 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self; 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)function add(v1, v2) { 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return new Array(v1[0] + v2[0], v1[1] + v2[1], v1[2] + v2[2]); 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)function sub(v1, v2) { 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return new Array(v1[0] - v2[0], v1[1] - v2[1], v1[2] - v2[2]); 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)function scalev(v1, v2) { 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return new Array(v1[0] * v2[0], v1[1] * v2[1], v1[2] * v2[2]); 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)function dot(v1, v2) { 80010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]; 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)function scale(v, scale) { 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return [v[0] * scale, v[1] * scale, v[2] * scale]; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)function cross(v1, v2) { 88eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return [v1[1] * v2[2] - v1[2] * v2[1], 89eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch v1[2] * v2[0] - v1[0] * v2[2], 90010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) v1[0] * v2[1] - v1[1] * v2[0]]; 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)function normalise(v) { 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var len = lengthVector(v); 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return [v[0] / len, v[1] / len, v[2] / len]; 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)function transformMatrix(self, v) { 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var vals = self; 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var x = vals[0] * v[0] + vals[1] * v[1] + vals[2] * v[2] + vals[3]; 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var y = vals[4] * v[0] + vals[5] * v[1] + vals[6] * v[2] + vals[7]; 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var z = vals[8] * v[0] + vals[9] * v[1] + vals[10] * v[2] + vals[11]; 1046d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return [x, y, z]; 1056d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)} 1066d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 1076d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)function invertMatrix(self) { 1086d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) var temp = new Array(16); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var tx = -self[3]; 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var ty = -self[7]; 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var tz = -self[11]; 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (h = 0; h < 3; h++) 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (v = 0; v < 3; v++) 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) temp[h + v * 4] = self[v + h * 4]; 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < 11; i++) 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self[i] = temp[i]; 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self[3] = tx * self[0] + ty * self[1] + tz * self[2]; 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self[7] = tx * self[4] + ty * self[5] + tz * self[6]; 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self[11] = tx * self[8] + ty * self[9] + tz * self[10]; 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return self; 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Triangle intersection using barycentric coord method 1256d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)function Triangle(p1, p2, p3) { 1266d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) var edge1 = sub(p3, p1); 1276d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) var edge2 = sub(p2, p1); 1286d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) var normal = cross(edge1, edge2); 1296d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (Math.abs(normal[0]) > Math.abs(normal[1])) 1306d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (Math.abs(normal[0]) > Math.abs(normal[2])) 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.axis = 0; 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.axis = 2; 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (Math.abs(normal[1]) > Math.abs(normal[2])) 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.axis = 1; 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.axis = 2; 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var u = (this.axis + 1) % 3; 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var v = (this.axis + 2) % 3; 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var u1 = edge1[u]; 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var v1 = edge1[v]; 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var u2 = edge2[u]; 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var v2 = edge2[v]; 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.normal = normalise(normal); 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.nu = normal[u] / normal[this.axis]; 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.nv = normal[v] / normal[this.axis]; 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.nd = dot(normal, p1) / normal[this.axis]; 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var det = u1 * v2 - v1 * u2; 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.eu = p1[u]; 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.ev = p1[v]; 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.nu1 = u1 / det; 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.nv1 = -v1 / det; 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.nu2 = v2 / det; 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.nv2 = -u2 / det; 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.material = [0.7, 0.7, 0.7]; 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Triangle.prototype.intersect = function(orig, dir, near, far) { 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var u = (this.axis + 1) % 3; 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var v = (this.axis + 2) % 3; 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var d = dir[this.axis] + this.nu * dir[u] + this.nv * dir[v]; 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var t = (this.nd - orig[this.axis] - this.nu * orig[u] - this.nv * orig[v]) / d; 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (t < near || t > far) 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return null; 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var Pu = orig[u] + t * dir[u] - this.eu; 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var Pv = orig[v] + t * dir[v] - this.ev; 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var a2 = Pv * this.nu1 + Pu * this.nv1; 1706d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (a2 < 0) 1716d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return null; 1726d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) var a3 = Pu * this.nu2 + Pv * this.nv2; 1736d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (a3 < 0) 1746d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return null; 1756d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 1766d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if ((a2 + a3) > 1) 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return null; 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return t; 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)function Scene(a_triangles) { 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.triangles = a_triangles; 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.lights = []; 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.ambient = [0,0,0]; 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this.background = [0.8,0.8,1]; 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)var zero = new Array(0,0,0); 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Scene.prototype.intersect = function(origin, dir, near, far) { 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var closest = null; 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (i = 0; i < this.triangles.length; i++) { 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var triangle = this.triangles[i]; 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var d = triangle.intersect(origin, dir, near, far); 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (d == null || d > far || d < near) 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) far = d; 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) closest = triangle; 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!closest) 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return [this.background[0],this.background[1],this.background[2]]; 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var normal = closest.normal; 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var hit = add(origin, scale(dir, far)); 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (dot(dir, normal) > 0) 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) normal = [-normal[0], -normal[1], -normal[2]]; 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 208f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) var colour = null; 209f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (closest.shader) { 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) colour = closest.shader(closest, hit, dir); 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) colour = closest.material; 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // do reflection 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var reflected = null; 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (colour.reflection > 0.001) { 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var reflection = addVector(scale(normal, -2*dot(dir, normal)), dir); 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reflected = this.intersect(hit, reflection, 0.0001, 1000000); 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (colour.reflection >= 0.999999) 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return reflected; 222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var l = [this.ambient[0], this.ambient[1], this.ambient[2]]; 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (var i = 0; i < this.lights.length; i++) { 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var light = this.lights[i]; 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var toLight = sub(light, hit); 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var distance = lengthVector(toLight); 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scaleVector(toLight, 1.0/distance); 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) distance -= 0.0001; 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (this.blocked(hit, toLight, distance)) 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var nl = dot(normal, toLight); 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (nl > 0) 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) addVector(l, scale(light.colour, nl)); 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) l = scalev(l, colour); 23890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (reflected) { 23990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) l = addVector(scaleVector(l, 1 - colour.reflection), scaleVector(reflected, colour.reflection)); 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return l; 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Scene.prototype.blocked = function(O, D, far) { 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var near = 0.0001; 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var closest = null; 247f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) for (i = 0; i < this.triangles.length; i++) { 248f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) var triangle = this.triangles[i]; 249010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) var d = triangle.intersect(O, D, near, far); 250f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (d == null || d > far || d < near) 251f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) continue; 252f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return true; 253f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// this camera code is from notes i made ages ago, it is from *somewhere* -- i cannot remember where 2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// that somewhere is 2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)function Camera(origin, lookat, up) { 2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) var zaxis = normaliseVector(subVector(lookat, origin)); 263116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch var xaxis = normaliseVector(cross(up, zaxis)); 264116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch var yaxis = normaliseVector(cross(xaxis, subVector([0,0,0], zaxis))); 2655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) var m = new Array(16); 2665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) m[0] = xaxis[0]; m[1] = xaxis[1]; m[2] = xaxis[2]; 267116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch m[4] = yaxis[0]; m[5] = yaxis[1]; m[6] = yaxis[2]; 2685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) m[8] = zaxis[0]; m[9] = zaxis[1]; m[10] = zaxis[2]; 2695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) invertMatrix(m); 2705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) m[3] = 0; m[7] = 0; m[11] = 0; 2715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) this.origin = origin; 2725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) this.directions = new Array(4); 2736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) this.directions[0] = normalise([-0.7, 0.7, 1]); 2746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) this.directions[1] = normalise([ 0.7, 0.7, 1]); 275116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch this.directions[2] = normalise([ 0.7, -0.7, 1]); 276116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch this.directions[3] = normalise([-0.7, -0.7, 1]); 277116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch this.directions[0] = transformMatrix(m, this.directions[0]); 278116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch this.directions[1] = transformMatrix(m, this.directions[1]); 2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this.directions[2] = transformMatrix(m, this.directions[2]); 2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) this.directions[3] = transformMatrix(m, this.directions[3]); 2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Camera.prototype.generateRayPair = function(y) { 2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) rays = new Array(new Object(), new Object()); 2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) rays[0].origin = this.origin; 2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) rays[1].origin = this.origin; 287010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) rays[0].dir = addVector(scale(this.directions[0], y), scale(this.directions[3], 1 - y)); 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rays[1].dir = addVector(scale(this.directions[1], y), scale(this.directions[2], 1 - y)); 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rays; 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)function renderRows(camera, scene, pixels, width, height, starty, stopy) { 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (var y = starty; y < stopy; y++) { 2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) var rays = camera.generateRayPair(y / height); 2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (var x = 0; x < width; x++) { 2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) var xp = x / width; 2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) var origin = addVector(scale(rays[0].origin, xp), scale(rays[1].origin, 1 - xp)); 2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) var dir = normaliseVector(addVector(scale(rays[0].dir, xp), scale(rays[1].dir, 1 - xp))); 2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) var l = scene.intersect(origin, dir); 3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) pixels[y][x] = l; 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3037dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch} 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Camera.prototype.render = function(scene, pixels, width, height) { 3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) var cam = this; 3075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) var row = 0; 3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) renderRows(cam, scene, pixels, width, height, 0, height); 3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 311868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 312c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 313c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)function raytraceScene() 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){ 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var startDate = new Date().getTime(); 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var numTriangles = 2 * 6; 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var triangles = new Array();//numTriangles); 3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) var tfl = createVector(-10, 10, -10); 3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) var tfr = createVector( 10, 10, -10); 3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) var tbl = createVector(-10, 10, 10); 3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) var tbr = createVector( 10, 10, 10); 3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) var bfl = createVector(-10, -10, -10); 3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) var bfr = createVector( 10, -10, -10); 3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) var bbl = createVector(-10, -10, 10); 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var bbr = createVector( 10, -10, 10); 3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // cube!!! 3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // front 329010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) var i = 0; 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) triangles[i++] = new Triangle(tfl, tfr, bfr); 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) triangles[i++] = new Triangle(tfl, bfr, bfl); 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // back 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) triangles[i++] = new Triangle(tbl, tbr, bbr); 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) triangles[i++] = new Triangle(tbl, bbr, bbl); 3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // triangles[i-1].material = [0.7,0.2,0.2]; 3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // triangles[i-1].material.reflection = 0.8; 3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // left 3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) triangles[i++] = new Triangle(tbl, tfl, bbl); 3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // triangles[i-1].reflection = 0.6; 3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) triangles[i++] = new Triangle(tfl, bfl, bbl); 3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // triangles[i-1].reflection = 0.6; 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // right 3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) triangles[i++] = new Triangle(tbr, tfr, bbr); 3457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch triangles[i++] = new Triangle(tfr, bfr, bbr); 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // top 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) triangles[i++] = new Triangle(tbl, tbr, tfr); 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) triangles[i++] = new Triangle(tbl, tfr, tfl); 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // bottom 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) triangles[i++] = new Triangle(bbl, bbr, bfr); 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) triangles[i++] = new Triangle(bbl, bfr, bfl); 352010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) //Floor!!!! 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var green = createVector(0.0, 0.4, 0.0); 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var grey = createVector(0.4, 0.4, 0.4); 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) grey.reflection = 1.0; 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var floorShader = function(tri, pos, view) { 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var x = ((pos[0]/32) % 2 + 2) % 2; 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var z = ((pos[2]/32 + 0.3) % 2 + 2) % 2; 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (x < 1 != z < 1) { 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) //in the real world we use the fresnel term... 362010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) // var angle = 1-dot(view, tri.normal); 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // angle *= angle; 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // angle *= angle; 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // angle *= angle; 3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) //grey.reflection = angle; 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return grey; 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return green; 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var ffl = createVector(-1000, -30, -1000); 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var ffr = createVector( 1000, -30, -1000); 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var fbl = createVector(-1000, -30, 1000); 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) var fbr = createVector( 1000, -30, 1000); 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) triangles[i++] = new Triangle(fbl, fbr, ffr); 376 triangles[i-1].shader = floorShader; 377 triangles[i++] = new Triangle(fbl, ffr, ffl); 378 triangles[i-1].shader = floorShader; 379 380 var _scene = new Scene(triangles); 381 _scene.lights[0] = createVector(20, 38, -22); 382 _scene.lights[0].colour = createVector(0.7, 0.3, 0.3); 383 _scene.lights[1] = createVector(-23, 40, 17); 384 _scene.lights[1].colour = createVector(0.7, 0.3, 0.3); 385 _scene.lights[2] = createVector(23, 20, 17); 386 _scene.lights[2].colour = createVector(0.7, 0.7, 0.7); 387 _scene.ambient = createVector(0.1, 0.1, 0.1); 388 // _scene.background = createVector(0.7, 0.7, 1.0); 389 390 var size = 30; 391 var pixels = new Array(); 392 for (var y = 0; y < size; y++) { 393 pixels[y] = new Array(); 394 for (var x = 0; x < size; x++) { 395 pixels[y][x] = 0; 396 } 397 } 398 399 var _camera = new Camera(createVector(-40, 40, 40), createVector(0, 0, 0), createVector(0, 1, 0)); 400 _camera.render(_scene, pixels, size, size); 401 402 return pixels; 403} 404 405function arrayToCanvasCommands(pixels) 406{ 407 var s = '<canvas id="renderCanvas" width="30px" height="30px"></canvas><scr' + 'ipt>\nvar pixels = ['; 408 var size = 30; 409 for (var y = 0; y < size; y++) { 410 s += "["; 411 for (var x = 0; x < size; x++) { 412 s += "[" + pixels[y][x] + "],"; 413 } 414 s+= "],"; 415 } 416 s += '];\n var canvas = document.getElementById("renderCanvas").getContext("2d");\n\ 417\n\ 418\n\ 419 var size = 30;\n\ 420 canvas.fillStyle = "red";\n\ 421 canvas.fillRect(0, 0, size, size);\n\ 422 canvas.scale(1, -1);\n\ 423 canvas.translate(0, -size);\n\ 424\n\ 425 if (!canvas.setFillColor)\n\ 426 canvas.setFillColor = function(r, g, b, a) {\n\ 427 this.fillStyle = "rgb("+[Math.floor(r * 255), Math.floor(g * 255), Math.floor(b * 255)]+")";\n\ 428 }\n\ 429\n\ 430for (var y = 0; y < size; y++) {\n\ 431 for (var x = 0; x < size; x++) {\n\ 432 var l = pixels[y][x];\n\ 433 canvas.setFillColor(l[0], l[1], l[2], 1);\n\ 434 canvas.fillRect(x, y, 1, 1);\n\ 435 }\n\ 436}</scr' + 'ipt>'; 437 438 return s; 439} 440 441testOutput = arrayToCanvasCommands(raytraceScene()); 442