1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jit-test/tests/v8-v5/check-raytrace.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,935 @@ 1.4 +// The ray tracer code in this file is written by Adam Burmister. It 1.5 +// is available in its original form from: 1.6 +// 1.7 +// http://labs.flog.nz.co/raytracer/ 1.8 +// 1.9 +// It has been modified slightly by Google to work as a standalone 1.10 +// benchmark, but the all the computational code remains 1.11 +// untouched. This file also contains a copy of parts of the Prototype 1.12 +// JavaScript framework which is used by the ray tracer. 1.13 + 1.14 +//var RayTrace = new BenchmarkSuite('RayTrace', 932666, [ 1.15 +// new Benchmark('RayTrace', renderScene) 1.16 +//]); 1.17 + 1.18 + 1.19 +// Variable used to hold a number that can be used to verify that 1.20 +// the scene was ray traced correctly. 1.21 +var checkNumber; 1.22 + 1.23 + 1.24 +// ------------------------------------------------------------------------ 1.25 +// ------------------------------------------------------------------------ 1.26 + 1.27 +// The following is a copy of parts of the Prototype JavaScript library: 1.28 + 1.29 +// Prototype JavaScript framework, version 1.5.0 1.30 +// (c) 2005-2007 Sam Stephenson 1.31 +// 1.32 +// Prototype is freely distributable under the terms of an MIT-style license. 1.33 +// For details, see the Prototype web site: http://prototype.conio.net/ 1.34 + 1.35 + 1.36 +var Class = { 1.37 + create: function() { 1.38 + return function() { 1.39 + this.initialize.apply(this, arguments); 1.40 + } 1.41 + } 1.42 +}; 1.43 + 1.44 + 1.45 +Object.extend = function(destination, source) { 1.46 + for (var property in source) { 1.47 + destination[property] = source[property]; 1.48 + } 1.49 + return destination; 1.50 +}; 1.51 + 1.52 + 1.53 +// ------------------------------------------------------------------------ 1.54 +// ------------------------------------------------------------------------ 1.55 + 1.56 +// The rest of this file is the actual ray tracer written by Adam 1.57 +// Burmister. It's a concatenation of the following files: 1.58 +// 1.59 +// flog/color.js 1.60 +// flog/light.js 1.61 +// flog/vector.js 1.62 +// flog/ray.js 1.63 +// flog/scene.js 1.64 +// flog/material/basematerial.js 1.65 +// flog/material/solid.js 1.66 +// flog/material/chessboard.js 1.67 +// flog/shape/baseshape.js 1.68 +// flog/shape/sphere.js 1.69 +// flog/shape/plane.js 1.70 +// flog/intersectioninfo.js 1.71 +// flog/camera.js 1.72 +// flog/background.js 1.73 +// flog/engine.js 1.74 + 1.75 + 1.76 +/* Fake a Flog.* namespace */ 1.77 +if(typeof(Flog) == 'undefined') var Flog = {}; 1.78 +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; 1.79 + 1.80 +Flog.RayTracer.Color = Class.create(); 1.81 + 1.82 +Flog.RayTracer.Color.prototype = { 1.83 + red : 0.0, 1.84 + green : 0.0, 1.85 + blue : 0.0, 1.86 + 1.87 + initialize : function(r, g, b) { 1.88 + if(!r) r = 0.0; 1.89 + if(!g) g = 0.0; 1.90 + if(!b) b = 0.0; 1.91 + 1.92 + this.red = r; 1.93 + this.green = g; 1.94 + this.blue = b; 1.95 + }, 1.96 + 1.97 + add : function(c1, c2){ 1.98 + var result = new Flog.RayTracer.Color(0,0,0); 1.99 + 1.100 + result.red = c1.red + c2.red; 1.101 + result.green = c1.green + c2.green; 1.102 + result.blue = c1.blue + c2.blue; 1.103 + 1.104 + return result; 1.105 + }, 1.106 + 1.107 + addScalar: function(c1, s){ 1.108 + var result = new Flog.RayTracer.Color(0,0,0); 1.109 + 1.110 + result.red = c1.red + s; 1.111 + result.green = c1.green + s; 1.112 + result.blue = c1.blue + s; 1.113 + 1.114 + result.limit(); 1.115 + 1.116 + return result; 1.117 + }, 1.118 + 1.119 + subtract: function(c1, c2){ 1.120 + var result = new Flog.RayTracer.Color(0,0,0); 1.121 + 1.122 + result.red = c1.red - c2.red; 1.123 + result.green = c1.green - c2.green; 1.124 + result.blue = c1.blue - c2.blue; 1.125 + 1.126 + return result; 1.127 + }, 1.128 + 1.129 + multiply : function(c1, c2) { 1.130 + var result = new Flog.RayTracer.Color(0,0,0); 1.131 + 1.132 + result.red = c1.red * c2.red; 1.133 + result.green = c1.green * c2.green; 1.134 + result.blue = c1.blue * c2.blue; 1.135 + 1.136 + return result; 1.137 + }, 1.138 + 1.139 + multiplyScalar : function(c1, f) { 1.140 + var result = new Flog.RayTracer.Color(0,0,0); 1.141 + 1.142 + result.red = c1.red * f; 1.143 + result.green = c1.green * f; 1.144 + result.blue = c1.blue * f; 1.145 + 1.146 + return result; 1.147 + }, 1.148 + 1.149 + divideFactor : function(c1, f) { 1.150 + var result = new Flog.RayTracer.Color(0,0,0); 1.151 + 1.152 + result.red = c1.red / f; 1.153 + result.green = c1.green / f; 1.154 + result.blue = c1.blue / f; 1.155 + 1.156 + return result; 1.157 + }, 1.158 + 1.159 + limit: function(){ 1.160 + this.red = (this.red > 0.0) ? ( (this.red > 1.0) ? 1.0 : this.red ) : 0.0; 1.161 + this.green = (this.green > 0.0) ? ( (this.green > 1.0) ? 1.0 : this.green ) : 0.0; 1.162 + this.blue = (this.blue > 0.0) ? ( (this.blue > 1.0) ? 1.0 : this.blue ) : 0.0; 1.163 + }, 1.164 + 1.165 + distance : function(color) { 1.166 + var d = Math.abs(this.red - color.red) + Math.abs(this.green - color.green) + Math.abs(this.blue - color.blue); 1.167 + return d; 1.168 + }, 1.169 + 1.170 + blend: function(c1, c2, w){ 1.171 + var result = new Flog.RayTracer.Color(0,0,0); 1.172 + result = Flog.RayTracer.Color.prototype.add( 1.173 + Flog.RayTracer.Color.prototype.multiplyScalar(c1, 1 - w), 1.174 + Flog.RayTracer.Color.prototype.multiplyScalar(c2, w) 1.175 + ); 1.176 + return result; 1.177 + }, 1.178 + 1.179 + brightness : function() { 1.180 + var r = Math.floor(this.red*255); 1.181 + var g = Math.floor(this.green*255); 1.182 + var b = Math.floor(this.blue*255); 1.183 + return (r * 77 + g * 150 + b * 29) >> 8; 1.184 + }, 1.185 + 1.186 + toString : function () { 1.187 + var r = Math.floor(this.red*255); 1.188 + var g = Math.floor(this.green*255); 1.189 + var b = Math.floor(this.blue*255); 1.190 + 1.191 + return "rgb("+ r +","+ g +","+ b +")"; 1.192 + } 1.193 +} 1.194 +/* Fake a Flog.* namespace */ 1.195 +if(typeof(Flog) == 'undefined') var Flog = {}; 1.196 +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; 1.197 + 1.198 +Flog.RayTracer.Light = Class.create(); 1.199 + 1.200 +Flog.RayTracer.Light.prototype = { 1.201 + position: null, 1.202 + color: null, 1.203 + intensity: 10.0, 1.204 + 1.205 + initialize : function(pos, color, intensity) { 1.206 + this.position = pos; 1.207 + this.color = color; 1.208 + this.intensity = (intensity ? intensity : 10.0); 1.209 + }, 1.210 + 1.211 + getIntensity: function(distance){ 1.212 + if(distance >= intensity) return 0; 1.213 + 1.214 + return Math.pow((intensity - distance) / strength, 0.2); 1.215 + }, 1.216 + 1.217 + toString : function () { 1.218 + return 'Light [' + this.position.x + ',' + this.position.y + ',' + this.position.z + ']'; 1.219 + } 1.220 +} 1.221 +/* Fake a Flog.* namespace */ 1.222 +if(typeof(Flog) == 'undefined') var Flog = {}; 1.223 +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; 1.224 + 1.225 +Flog.RayTracer.Vector = Class.create(); 1.226 + 1.227 +Flog.RayTracer.Vector.prototype = { 1.228 + x : 0.0, 1.229 + y : 0.0, 1.230 + z : 0.0, 1.231 + 1.232 + initialize : function(x, y, z) { 1.233 + this.x = (x ? x : 0); 1.234 + this.y = (y ? y : 0); 1.235 + this.z = (z ? z : 0); 1.236 + }, 1.237 + 1.238 + copy: function(vector){ 1.239 + this.x = vector.x; 1.240 + this.y = vector.y; 1.241 + this.z = vector.z; 1.242 + }, 1.243 + 1.244 + normalize : function() { 1.245 + var m = this.magnitude(); 1.246 + return new Flog.RayTracer.Vector(this.x / m, this.y / m, this.z / m); 1.247 + }, 1.248 + 1.249 + magnitude : function() { 1.250 + return Math.sqrt((this.x * this.x) + (this.y * this.y) + (this.z * this.z)); 1.251 + }, 1.252 + 1.253 + cross : function(w) { 1.254 + return new Flog.RayTracer.Vector( 1.255 + -this.z * w.y + this.y * w.z, 1.256 + this.z * w.x - this.x * w.z, 1.257 + -this.y * w.x + this.x * w.y); 1.258 + }, 1.259 + 1.260 + dot : function(w) { 1.261 + return this.x * w.x + this.y * w.y + this.z * w.z; 1.262 + }, 1.263 + 1.264 + add : function(v, w) { 1.265 + return new Flog.RayTracer.Vector(w.x + v.x, w.y + v.y, w.z + v.z); 1.266 + }, 1.267 + 1.268 + subtract : function(v, w) { 1.269 + if(!w || !v) throw 'Vectors must be defined [' + v + ',' + w + ']'; 1.270 + return new Flog.RayTracer.Vector(v.x - w.x, v.y - w.y, v.z - w.z); 1.271 + }, 1.272 + 1.273 + multiplyVector : function(v, w) { 1.274 + return new Flog.RayTracer.Vector(v.x * w.x, v.y * w.y, v.z * w.z); 1.275 + }, 1.276 + 1.277 + multiplyScalar : function(v, w) { 1.278 + return new Flog.RayTracer.Vector(v.x * w, v.y * w, v.z * w); 1.279 + }, 1.280 + 1.281 + toString : function () { 1.282 + return 'Vector [' + this.x + ',' + this.y + ',' + this.z + ']'; 1.283 + } 1.284 +} 1.285 +/* Fake a Flog.* namespace */ 1.286 +if(typeof(Flog) == 'undefined') var Flog = {}; 1.287 +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; 1.288 + 1.289 +Flog.RayTracer.Ray = Class.create(); 1.290 + 1.291 +Flog.RayTracer.Ray.prototype = { 1.292 + position : null, 1.293 + direction : null, 1.294 + initialize : function(pos, dir) { 1.295 + this.position = pos; 1.296 + this.direction = dir; 1.297 + }, 1.298 + 1.299 + toString : function () { 1.300 + return 'Ray [' + this.position + ',' + this.direction + ']'; 1.301 + } 1.302 +} 1.303 +/* Fake a Flog.* namespace */ 1.304 +if(typeof(Flog) == 'undefined') var Flog = {}; 1.305 +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; 1.306 + 1.307 +Flog.RayTracer.Scene = Class.create(); 1.308 + 1.309 +Flog.RayTracer.Scene.prototype = { 1.310 + camera : null, 1.311 + shapes : [], 1.312 + lights : [], 1.313 + background : null, 1.314 + 1.315 + initialize : function() { 1.316 + this.camera = new Flog.RayTracer.Camera( 1.317 + new Flog.RayTracer.Vector(0,0,-5), 1.318 + new Flog.RayTracer.Vector(0,0,1), 1.319 + new Flog.RayTracer.Vector(0,1,0) 1.320 + ); 1.321 + this.shapes = new Array(); 1.322 + this.lights = new Array(); 1.323 + this.background = new Flog.RayTracer.Background(new Flog.RayTracer.Color(0,0,0.5), 0.2); 1.324 + } 1.325 +} 1.326 +/* Fake a Flog.* namespace */ 1.327 +if(typeof(Flog) == 'undefined') var Flog = {}; 1.328 +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; 1.329 +if(typeof(Flog.RayTracer.Material) == 'undefined') Flog.RayTracer.Material = {}; 1.330 + 1.331 +Flog.RayTracer.Material.BaseMaterial = Class.create(); 1.332 + 1.333 +Flog.RayTracer.Material.BaseMaterial.prototype = { 1.334 + 1.335 + gloss: 2.0, // [0...infinity] 0 = matt 1.336 + transparency: 0.0, // 0=opaque 1.337 + reflection: 0.0, // [0...infinity] 0 = no reflection 1.338 + refraction: 0.50, 1.339 + hasTexture: false, 1.340 + 1.341 + initialize : function() { 1.342 + 1.343 + }, 1.344 + 1.345 + getColor: function(u, v){ 1.346 + 1.347 + }, 1.348 + 1.349 + wrapUp: function(t){ 1.350 + t = t % 2.0; 1.351 + if(t < -1) t += 2.0; 1.352 + if(t >= 1) t -= 2.0; 1.353 + return t; 1.354 + }, 1.355 + 1.356 + toString : function () { 1.357 + return 'Material [gloss=' + this.gloss + ', transparency=' + this.transparency + ', hasTexture=' + this.hasTexture +']'; 1.358 + } 1.359 +} 1.360 +/* Fake a Flog.* namespace */ 1.361 +if(typeof(Flog) == 'undefined') var Flog = {}; 1.362 +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; 1.363 + 1.364 +Flog.RayTracer.Material.Solid = Class.create(); 1.365 + 1.366 +Flog.RayTracer.Material.Solid.prototype = Object.extend( 1.367 + new Flog.RayTracer.Material.BaseMaterial(), { 1.368 + initialize : function(color, reflection, refraction, transparency, gloss) { 1.369 + this.color = color; 1.370 + this.reflection = reflection; 1.371 + this.transparency = transparency; 1.372 + this.gloss = gloss; 1.373 + this.hasTexture = false; 1.374 + }, 1.375 + 1.376 + getColor: function(u, v){ 1.377 + return this.color; 1.378 + }, 1.379 + 1.380 + toString : function () { 1.381 + return 'SolidMaterial [gloss=' + this.gloss + ', transparency=' + this.transparency + ', hasTexture=' + this.hasTexture +']'; 1.382 + } 1.383 + } 1.384 +); 1.385 +/* Fake a Flog.* namespace */ 1.386 +if(typeof(Flog) == 'undefined') var Flog = {}; 1.387 +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; 1.388 + 1.389 +Flog.RayTracer.Material.Chessboard = Class.create(); 1.390 + 1.391 +Flog.RayTracer.Material.Chessboard.prototype = Object.extend( 1.392 + new Flog.RayTracer.Material.BaseMaterial(), { 1.393 + colorEven: null, 1.394 + colorOdd: null, 1.395 + density: 0.5, 1.396 + 1.397 + initialize : function(colorEven, colorOdd, reflection, transparency, gloss, density) { 1.398 + this.colorEven = colorEven; 1.399 + this.colorOdd = colorOdd; 1.400 + this.reflection = reflection; 1.401 + this.transparency = transparency; 1.402 + this.gloss = gloss; 1.403 + this.density = density; 1.404 + this.hasTexture = true; 1.405 + }, 1.406 + 1.407 + getColor: function(u, v){ 1.408 + var t = this.wrapUp(u * this.density) * this.wrapUp(v * this.density); 1.409 + 1.410 + if(t < 0.0) 1.411 + return this.colorEven; 1.412 + else 1.413 + return this.colorOdd; 1.414 + }, 1.415 + 1.416 + toString : function () { 1.417 + return 'ChessMaterial [gloss=' + this.gloss + ', transparency=' + this.transparency + ', hasTexture=' + this.hasTexture +']'; 1.418 + } 1.419 + } 1.420 +); 1.421 +/* Fake a Flog.* namespace */ 1.422 +if(typeof(Flog) == 'undefined') var Flog = {}; 1.423 +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; 1.424 +if(typeof(Flog.RayTracer.Shape) == 'undefined') Flog.RayTracer.Shape = {}; 1.425 + 1.426 +Flog.RayTracer.Shape.BaseShape = Class.create(); 1.427 + 1.428 +Flog.RayTracer.Shape.BaseShape.prototype = { 1.429 + position: null, 1.430 + material: null, 1.431 + 1.432 + initialize : function() { 1.433 + this.position = new Vector(0,0,0); 1.434 + this.material = new Flog.RayTracer.Material.SolidMaterial( 1.435 + new Flog.RayTracer.Color(1,0,1), 1.436 + 0, 1.437 + 0, 1.438 + 0 1.439 + ); 1.440 + }, 1.441 + 1.442 + toString : function () { 1.443 + return 'Material [gloss=' + this.gloss + ', transparency=' + this.transparency + ', hasTexture=' + this.hasTexture +']'; 1.444 + } 1.445 +} 1.446 +/* Fake a Flog.* namespace */ 1.447 +if(typeof(Flog) == 'undefined') var Flog = {}; 1.448 +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; 1.449 +if(typeof(Flog.RayTracer.Shape) == 'undefined') Flog.RayTracer.Shape = {}; 1.450 + 1.451 +Flog.RayTracer.Shape.Sphere = Class.create(); 1.452 + 1.453 +Flog.RayTracer.Shape.Sphere.prototype = { 1.454 + initialize : function(pos, radius, material) { 1.455 + this.radius = radius; 1.456 + this.position = pos; 1.457 + this.material = material; 1.458 + }, 1.459 + 1.460 + intersect: function(ray){ 1.461 + var info = new Flog.RayTracer.IntersectionInfo(); 1.462 + info.shape = this; 1.463 + 1.464 + var dst = Flog.RayTracer.Vector.prototype.subtract(ray.position, this.position); 1.465 + 1.466 + var B = dst.dot(ray.direction); 1.467 + var C = dst.dot(dst) - (this.radius * this.radius); 1.468 + var D = (B * B) - C; 1.469 + 1.470 + if(D > 0){ // intersection! 1.471 + info.isHit = true; 1.472 + info.distance = (-B) - Math.sqrt(D); 1.473 + info.position = Flog.RayTracer.Vector.prototype.add( 1.474 + ray.position, 1.475 + Flog.RayTracer.Vector.prototype.multiplyScalar( 1.476 + ray.direction, 1.477 + info.distance 1.478 + ) 1.479 + ); 1.480 + info.normal = Flog.RayTracer.Vector.prototype.subtract( 1.481 + info.position, 1.482 + this.position 1.483 + ).normalize(); 1.484 + 1.485 + info.color = this.material.getColor(0,0); 1.486 + } else { 1.487 + info.isHit = false; 1.488 + } 1.489 + return info; 1.490 + }, 1.491 + 1.492 + toString : function () { 1.493 + return 'Sphere [position=' + this.position + ', radius=' + this.radius + ']'; 1.494 + } 1.495 +} 1.496 +/* Fake a Flog.* namespace */ 1.497 +if(typeof(Flog) == 'undefined') var Flog = {}; 1.498 +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; 1.499 +if(typeof(Flog.RayTracer.Shape) == 'undefined') Flog.RayTracer.Shape = {}; 1.500 + 1.501 +Flog.RayTracer.Shape.Plane = Class.create(); 1.502 + 1.503 +Flog.RayTracer.Shape.Plane.prototype = { 1.504 + d: 0.0, 1.505 + 1.506 + initialize : function(pos, d, material) { 1.507 + this.position = pos; 1.508 + this.d = d; 1.509 + this.material = material; 1.510 + }, 1.511 + 1.512 + intersect: function(ray){ 1.513 + var info = new Flog.RayTracer.IntersectionInfo(); 1.514 + 1.515 + var Vd = this.position.dot(ray.direction); 1.516 + if(Vd == 0) return info; // no intersection 1.517 + 1.518 + var t = -(this.position.dot(ray.position) + this.d) / Vd; 1.519 + if(t <= 0) return info; 1.520 + 1.521 + info.shape = this; 1.522 + info.isHit = true; 1.523 + info.position = Flog.RayTracer.Vector.prototype.add( 1.524 + ray.position, 1.525 + Flog.RayTracer.Vector.prototype.multiplyScalar( 1.526 + ray.direction, 1.527 + t 1.528 + ) 1.529 + ); 1.530 + info.normal = this.position; 1.531 + info.distance = t; 1.532 + 1.533 + if(this.material.hasTexture){ 1.534 + var vU = new Flog.RayTracer.Vector(this.position.y, this.position.z, -this.position.x); 1.535 + var vV = vU.cross(this.position); 1.536 + var u = info.position.dot(vU); 1.537 + var v = info.position.dot(vV); 1.538 + info.color = this.material.getColor(u,v); 1.539 + } else { 1.540 + info.color = this.material.getColor(0,0); 1.541 + } 1.542 + 1.543 + return info; 1.544 + }, 1.545 + 1.546 + toString : function () { 1.547 + return 'Plane [' + this.position + ', d=' + this.d + ']'; 1.548 + } 1.549 +} 1.550 +/* Fake a Flog.* namespace */ 1.551 +if(typeof(Flog) == 'undefined') var Flog = {}; 1.552 +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; 1.553 + 1.554 +Flog.RayTracer.IntersectionInfo = Class.create(); 1.555 + 1.556 +Flog.RayTracer.IntersectionInfo.prototype = { 1.557 + isHit: false, 1.558 + hitCount: 0, 1.559 + shape: null, 1.560 + position: null, 1.561 + normal: null, 1.562 + color: null, 1.563 + distance: null, 1.564 + 1.565 + initialize : function() { 1.566 + this.color = new Flog.RayTracer.Color(0,0,0); 1.567 + }, 1.568 + 1.569 + toString : function () { 1.570 + return 'Intersection [' + this.position + ']'; 1.571 + } 1.572 +} 1.573 +/* Fake a Flog.* namespace */ 1.574 +if(typeof(Flog) == 'undefined') var Flog = {}; 1.575 +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; 1.576 + 1.577 +Flog.RayTracer.Camera = Class.create(); 1.578 + 1.579 +Flog.RayTracer.Camera.prototype = { 1.580 + position: null, 1.581 + lookAt: null, 1.582 + equator: null, 1.583 + up: null, 1.584 + screen: null, 1.585 + 1.586 + initialize : function(pos, lookAt, up) { 1.587 + this.position = pos; 1.588 + this.lookAt = lookAt; 1.589 + this.up = up; 1.590 + this.equator = lookAt.normalize().cross(this.up); 1.591 + this.screen = Flog.RayTracer.Vector.prototype.add(this.position, this.lookAt); 1.592 + }, 1.593 + 1.594 + getRay: function(vx, vy){ 1.595 + var pos = Flog.RayTracer.Vector.prototype.subtract( 1.596 + this.screen, 1.597 + Flog.RayTracer.Vector.prototype.subtract( 1.598 + Flog.RayTracer.Vector.prototype.multiplyScalar(this.equator, vx), 1.599 + Flog.RayTracer.Vector.prototype.multiplyScalar(this.up, vy) 1.600 + ) 1.601 + ); 1.602 + pos.y = pos.y * -1; 1.603 + var dir = Flog.RayTracer.Vector.prototype.subtract( 1.604 + pos, 1.605 + this.position 1.606 + ); 1.607 + 1.608 + var ray = new Flog.RayTracer.Ray(pos, dir.normalize()); 1.609 + 1.610 + return ray; 1.611 + }, 1.612 + 1.613 + toString : function () { 1.614 + return 'Ray []'; 1.615 + } 1.616 +} 1.617 +/* Fake a Flog.* namespace */ 1.618 +if(typeof(Flog) == 'undefined') var Flog = {}; 1.619 +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; 1.620 + 1.621 +Flog.RayTracer.Background = Class.create(); 1.622 + 1.623 +Flog.RayTracer.Background.prototype = { 1.624 + color : null, 1.625 + ambience : 0.0, 1.626 + 1.627 + initialize : function(color, ambience) { 1.628 + this.color = color; 1.629 + this.ambience = ambience; 1.630 + } 1.631 +} 1.632 +/* Fake a Flog.* namespace */ 1.633 +if(typeof(Flog) == 'undefined') var Flog = {}; 1.634 +if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {}; 1.635 + 1.636 +Flog.RayTracer.Engine = Class.create(); 1.637 + 1.638 +Flog.RayTracer.Engine.prototype = { 1.639 + canvas: null, /* 2d context we can render to */ 1.640 + 1.641 + initialize: function(options){ 1.642 + this.options = Object.extend({ 1.643 + canvasHeight: 100, 1.644 + canvasWidth: 100, 1.645 + pixelWidth: 2, 1.646 + pixelHeight: 2, 1.647 + renderDiffuse: false, 1.648 + renderShadows: false, 1.649 + renderHighlights: false, 1.650 + renderReflections: false, 1.651 + rayDepth: 2 1.652 + }, options || {}); 1.653 + 1.654 + this.options.canvasHeight /= this.options.pixelHeight; 1.655 + this.options.canvasWidth /= this.options.pixelWidth; 1.656 + 1.657 + /* TODO: dynamically include other scripts */ 1.658 + }, 1.659 + 1.660 + setPixel: function(x, y, color){ 1.661 + var pxW, pxH; 1.662 + pxW = this.options.pixelWidth; 1.663 + pxH = this.options.pixelHeight; 1.664 + 1.665 + if (this.canvas) { 1.666 + this.canvas.fillStyle = color.toString(); 1.667 + this.canvas.fillRect (x * pxW, y * pxH, pxW, pxH); 1.668 + } else { 1.669 + if (x === y) { 1.670 + checkNumber += color.brightness(); 1.671 + } 1.672 + // print(x * pxW, y * pxH, pxW, pxH); 1.673 + } 1.674 + }, 1.675 + 1.676 + renderScene: function(scene, canvas){ 1.677 + checkNumber = 0; 1.678 + /* Get canvas */ 1.679 + if (canvas) { 1.680 + this.canvas = canvas.getContext("2d"); 1.681 + } else { 1.682 + this.canvas = null; 1.683 + } 1.684 + 1.685 + var canvasHeight = this.options.canvasHeight; 1.686 + var canvasWidth = this.options.canvasWidth; 1.687 + 1.688 + for(var y=0; y < canvasHeight; y++){ 1.689 + for(var x=0; x < canvasWidth; x++){ 1.690 + var yp = y * 1.0 / canvasHeight * 2 - 1; 1.691 + var xp = x * 1.0 / canvasWidth * 2 - 1; 1.692 + 1.693 + var ray = scene.camera.getRay(xp, yp); 1.694 + 1.695 + var color = this.getPixelColor(ray, scene); 1.696 + 1.697 + this.setPixel(x, y, color); 1.698 + } 1.699 + } 1.700 + assertEq(checkNumber, 2321); 1.701 + }, 1.702 + 1.703 + getPixelColor: function(ray, scene){ 1.704 + var info = this.testIntersection(ray, scene, null); 1.705 + if(info.isHit){ 1.706 + var color = this.rayTrace(info, ray, scene, 0); 1.707 + return color; 1.708 + } 1.709 + return scene.background.color; 1.710 + }, 1.711 + 1.712 + testIntersection: function(ray, scene, exclude){ 1.713 + var hits = 0; 1.714 + var best = new Flog.RayTracer.IntersectionInfo(); 1.715 + best.distance = 2000; 1.716 + 1.717 + for(var i=0; i<scene.shapes.length; i++){ 1.718 + var shape = scene.shapes[i]; 1.719 + 1.720 + if(shape != exclude){ 1.721 + var info = shape.intersect(ray); 1.722 + if(info.isHit && info.distance >= 0 && info.distance < best.distance){ 1.723 + best = info; 1.724 + hits++; 1.725 + } 1.726 + } 1.727 + } 1.728 + best.hitCount = hits; 1.729 + return best; 1.730 + }, 1.731 + 1.732 + getReflectionRay: function(P,N,V){ 1.733 + var c1 = -N.dot(V); 1.734 + var R1 = Flog.RayTracer.Vector.prototype.add( 1.735 + Flog.RayTracer.Vector.prototype.multiplyScalar(N, 2*c1), 1.736 + V 1.737 + ); 1.738 + return new Flog.RayTracer.Ray(P, R1); 1.739 + }, 1.740 + 1.741 + rayTrace: function(info, ray, scene, depth){ 1.742 + // Calc ambient 1.743 + var color = Flog.RayTracer.Color.prototype.multiplyScalar(info.color, scene.background.ambience); 1.744 + var oldColor = color; 1.745 + var shininess = Math.pow(10, info.shape.material.gloss + 1); 1.746 + 1.747 + for(var i=0; i<scene.lights.length; i++){ 1.748 + var light = scene.lights[i]; 1.749 + 1.750 + // Calc diffuse lighting 1.751 + var v = Flog.RayTracer.Vector.prototype.subtract( 1.752 + light.position, 1.753 + info.position 1.754 + ).normalize(); 1.755 + 1.756 + if(this.options.renderDiffuse){ 1.757 + var L = v.dot(info.normal); 1.758 + if(L > 0.0){ 1.759 + color = Flog.RayTracer.Color.prototype.add( 1.760 + color, 1.761 + Flog.RayTracer.Color.prototype.multiply( 1.762 + info.color, 1.763 + Flog.RayTracer.Color.prototype.multiplyScalar( 1.764 + light.color, 1.765 + L 1.766 + ) 1.767 + ) 1.768 + ); 1.769 + } 1.770 + } 1.771 + 1.772 + // The greater the depth the more accurate the colours, but 1.773 + // this is exponentially (!) expensive 1.774 + if(depth <= this.options.rayDepth){ 1.775 + // calculate reflection ray 1.776 + if(this.options.renderReflections && info.shape.material.reflection > 0) 1.777 + { 1.778 + var reflectionRay = this.getReflectionRay(info.position, info.normal, ray.direction); 1.779 + var refl = this.testIntersection(reflectionRay, scene, info.shape); 1.780 + 1.781 + if (refl.isHit && refl.distance > 0){ 1.782 + refl.color = this.rayTrace(refl, reflectionRay, scene, depth + 1); 1.783 + } else { 1.784 + refl.color = scene.background.color; 1.785 + } 1.786 + 1.787 + color = Flog.RayTracer.Color.prototype.blend( 1.788 + color, 1.789 + refl.color, 1.790 + info.shape.material.reflection 1.791 + ); 1.792 + } 1.793 + 1.794 + // Refraction 1.795 + /* TODO */ 1.796 + } 1.797 + 1.798 + /* Render shadows and highlights */ 1.799 + 1.800 + var shadowInfo = new Flog.RayTracer.IntersectionInfo(); 1.801 + 1.802 + if(this.options.renderShadows){ 1.803 + var shadowRay = new Flog.RayTracer.Ray(info.position, v); 1.804 + 1.805 + shadowInfo = this.testIntersection(shadowRay, scene, info.shape); 1.806 + if(shadowInfo.isHit && shadowInfo.shape != info.shape /*&& shadowInfo.shape.type != 'PLANE'*/){ 1.807 + var vA = Flog.RayTracer.Color.prototype.multiplyScalar(color, 0.5); 1.808 + var dB = (0.5 * Math.pow(shadowInfo.shape.material.transparency, 0.5)); 1.809 + color = Flog.RayTracer.Color.prototype.addScalar(vA,dB); 1.810 + } 1.811 + } 1.812 + 1.813 + // Phong specular highlights 1.814 + if(this.options.renderHighlights && !shadowInfo.isHit && info.shape.material.gloss > 0){ 1.815 + var Lv = Flog.RayTracer.Vector.prototype.subtract( 1.816 + info.shape.position, 1.817 + light.position 1.818 + ).normalize(); 1.819 + 1.820 + var E = Flog.RayTracer.Vector.prototype.subtract( 1.821 + scene.camera.position, 1.822 + info.shape.position 1.823 + ).normalize(); 1.824 + 1.825 + var H = Flog.RayTracer.Vector.prototype.subtract( 1.826 + E, 1.827 + Lv 1.828 + ).normalize(); 1.829 + 1.830 + var glossWeight = Math.pow(Math.max(info.normal.dot(H), 0), shininess); 1.831 + color = Flog.RayTracer.Color.prototype.add( 1.832 + Flog.RayTracer.Color.prototype.multiplyScalar(light.color, glossWeight), 1.833 + color 1.834 + ); 1.835 + } 1.836 + } 1.837 + color.limit(); 1.838 + return color; 1.839 + } 1.840 +}; 1.841 + 1.842 + 1.843 +function renderScene(){ 1.844 + var scene = new Flog.RayTracer.Scene(); 1.845 + 1.846 + scene.camera = new Flog.RayTracer.Camera( 1.847 + new Flog.RayTracer.Vector(0, 0, -15), 1.848 + new Flog.RayTracer.Vector(-0.2, 0, 5), 1.849 + new Flog.RayTracer.Vector(0, 1, 0) 1.850 + ); 1.851 + 1.852 + scene.background = new Flog.RayTracer.Background( 1.853 + new Flog.RayTracer.Color(0.5, 0.5, 0.5), 1.854 + 0.4 1.855 + ); 1.856 + 1.857 + var sphere = new Flog.RayTracer.Shape.Sphere( 1.858 + new Flog.RayTracer.Vector(-1.5, 1.5, 2), 1.859 + 1.5, 1.860 + new Flog.RayTracer.Material.Solid( 1.861 + new Flog.RayTracer.Color(0,0.5,0.5), 1.862 + 0.3, 1.863 + 0.0, 1.864 + 0.0, 1.865 + 2.0 1.866 + ) 1.867 + ); 1.868 + 1.869 + var sphere1 = new Flog.RayTracer.Shape.Sphere( 1.870 + new Flog.RayTracer.Vector(1, 0.25, 1), 1.871 + 0.5, 1.872 + new Flog.RayTracer.Material.Solid( 1.873 + new Flog.RayTracer.Color(0.9,0.9,0.9), 1.874 + 0.1, 1.875 + 0.0, 1.876 + 0.0, 1.877 + 1.5 1.878 + ) 1.879 + ); 1.880 + 1.881 + var plane = new Flog.RayTracer.Shape.Plane( 1.882 + new Flog.RayTracer.Vector(0.1, 0.9, -0.5).normalize(), 1.883 + 1.2, 1.884 + new Flog.RayTracer.Material.Chessboard( 1.885 + new Flog.RayTracer.Color(1,1,1), 1.886 + new Flog.RayTracer.Color(0,0,0), 1.887 + 0.2, 1.888 + 0.0, 1.889 + 1.0, 1.890 + 0.7 1.891 + ) 1.892 + ); 1.893 + 1.894 + scene.shapes.push(plane); 1.895 + scene.shapes.push(sphere); 1.896 + scene.shapes.push(sphere1); 1.897 + 1.898 + var light = new Flog.RayTracer.Light( 1.899 + new Flog.RayTracer.Vector(5, 10, -1), 1.900 + new Flog.RayTracer.Color(0.8, 0.8, 0.8) 1.901 + ); 1.902 + 1.903 + var light1 = new Flog.RayTracer.Light( 1.904 + new Flog.RayTracer.Vector(-3, 5, -15), 1.905 + new Flog.RayTracer.Color(0.8, 0.8, 0.8), 1.906 + 100 1.907 + ); 1.908 + 1.909 + scene.lights.push(light); 1.910 + scene.lights.push(light1); 1.911 + 1.912 + var imageWidth = 100; // $F('imageWidth'); 1.913 + var imageHeight = 100; // $F('imageHeight'); 1.914 + var pixelSize = "5,5".split(','); // $F('pixelSize').split(','); 1.915 + var renderDiffuse = true; // $F('renderDiffuse'); 1.916 + var renderShadows = true; // $F('renderShadows'); 1.917 + var renderHighlights = true; // $F('renderHighlights'); 1.918 + var renderReflections = true; // $F('renderReflections'); 1.919 + var rayDepth = 2;//$F('rayDepth'); 1.920 + 1.921 + var raytracer = new Flog.RayTracer.Engine( 1.922 + { 1.923 + canvasWidth: imageWidth, 1.924 + canvasHeight: imageHeight, 1.925 + pixelWidth: pixelSize[0], 1.926 + pixelHeight: pixelSize[1], 1.927 + "renderDiffuse": renderDiffuse, 1.928 + "renderHighlights": renderHighlights, 1.929 + "renderShadows": renderShadows, 1.930 + "renderReflections": renderReflections, 1.931 + "rayDepth": rayDepth 1.932 + } 1.933 + ); 1.934 + 1.935 + raytracer.renderScene(scene, null, 0); 1.936 +} 1.937 + 1.938 +renderScene();