js/src/jit-test/tests/v8-v5/check-raytrace.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 // The ray tracer code in this file is written by Adam Burmister. It
michael@0 2 // is available in its original form from:
michael@0 3 //
michael@0 4 // http://labs.flog.nz.co/raytracer/
michael@0 5 //
michael@0 6 // It has been modified slightly by Google to work as a standalone
michael@0 7 // benchmark, but the all the computational code remains
michael@0 8 // untouched. This file also contains a copy of parts of the Prototype
michael@0 9 // JavaScript framework which is used by the ray tracer.
michael@0 10
michael@0 11 //var RayTrace = new BenchmarkSuite('RayTrace', 932666, [
michael@0 12 // new Benchmark('RayTrace', renderScene)
michael@0 13 //]);
michael@0 14
michael@0 15
michael@0 16 // Variable used to hold a number that can be used to verify that
michael@0 17 // the scene was ray traced correctly.
michael@0 18 var checkNumber;
michael@0 19
michael@0 20
michael@0 21 // ------------------------------------------------------------------------
michael@0 22 // ------------------------------------------------------------------------
michael@0 23
michael@0 24 // The following is a copy of parts of the Prototype JavaScript library:
michael@0 25
michael@0 26 // Prototype JavaScript framework, version 1.5.0
michael@0 27 // (c) 2005-2007 Sam Stephenson
michael@0 28 //
michael@0 29 // Prototype is freely distributable under the terms of an MIT-style license.
michael@0 30 // For details, see the Prototype web site: http://prototype.conio.net/
michael@0 31
michael@0 32
michael@0 33 var Class = {
michael@0 34 create: function() {
michael@0 35 return function() {
michael@0 36 this.initialize.apply(this, arguments);
michael@0 37 }
michael@0 38 }
michael@0 39 };
michael@0 40
michael@0 41
michael@0 42 Object.extend = function(destination, source) {
michael@0 43 for (var property in source) {
michael@0 44 destination[property] = source[property];
michael@0 45 }
michael@0 46 return destination;
michael@0 47 };
michael@0 48
michael@0 49
michael@0 50 // ------------------------------------------------------------------------
michael@0 51 // ------------------------------------------------------------------------
michael@0 52
michael@0 53 // The rest of this file is the actual ray tracer written by Adam
michael@0 54 // Burmister. It's a concatenation of the following files:
michael@0 55 //
michael@0 56 // flog/color.js
michael@0 57 // flog/light.js
michael@0 58 // flog/vector.js
michael@0 59 // flog/ray.js
michael@0 60 // flog/scene.js
michael@0 61 // flog/material/basematerial.js
michael@0 62 // flog/material/solid.js
michael@0 63 // flog/material/chessboard.js
michael@0 64 // flog/shape/baseshape.js
michael@0 65 // flog/shape/sphere.js
michael@0 66 // flog/shape/plane.js
michael@0 67 // flog/intersectioninfo.js
michael@0 68 // flog/camera.js
michael@0 69 // flog/background.js
michael@0 70 // flog/engine.js
michael@0 71
michael@0 72
michael@0 73 /* Fake a Flog.* namespace */
michael@0 74 if(typeof(Flog) == 'undefined') var Flog = {};
michael@0 75 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
michael@0 76
michael@0 77 Flog.RayTracer.Color = Class.create();
michael@0 78
michael@0 79 Flog.RayTracer.Color.prototype = {
michael@0 80 red : 0.0,
michael@0 81 green : 0.0,
michael@0 82 blue : 0.0,
michael@0 83
michael@0 84 initialize : function(r, g, b) {
michael@0 85 if(!r) r = 0.0;
michael@0 86 if(!g) g = 0.0;
michael@0 87 if(!b) b = 0.0;
michael@0 88
michael@0 89 this.red = r;
michael@0 90 this.green = g;
michael@0 91 this.blue = b;
michael@0 92 },
michael@0 93
michael@0 94 add : function(c1, c2){
michael@0 95 var result = new Flog.RayTracer.Color(0,0,0);
michael@0 96
michael@0 97 result.red = c1.red + c2.red;
michael@0 98 result.green = c1.green + c2.green;
michael@0 99 result.blue = c1.blue + c2.blue;
michael@0 100
michael@0 101 return result;
michael@0 102 },
michael@0 103
michael@0 104 addScalar: function(c1, s){
michael@0 105 var result = new Flog.RayTracer.Color(0,0,0);
michael@0 106
michael@0 107 result.red = c1.red + s;
michael@0 108 result.green = c1.green + s;
michael@0 109 result.blue = c1.blue + s;
michael@0 110
michael@0 111 result.limit();
michael@0 112
michael@0 113 return result;
michael@0 114 },
michael@0 115
michael@0 116 subtract: function(c1, c2){
michael@0 117 var result = new Flog.RayTracer.Color(0,0,0);
michael@0 118
michael@0 119 result.red = c1.red - c2.red;
michael@0 120 result.green = c1.green - c2.green;
michael@0 121 result.blue = c1.blue - c2.blue;
michael@0 122
michael@0 123 return result;
michael@0 124 },
michael@0 125
michael@0 126 multiply : function(c1, c2) {
michael@0 127 var result = new Flog.RayTracer.Color(0,0,0);
michael@0 128
michael@0 129 result.red = c1.red * c2.red;
michael@0 130 result.green = c1.green * c2.green;
michael@0 131 result.blue = c1.blue * c2.blue;
michael@0 132
michael@0 133 return result;
michael@0 134 },
michael@0 135
michael@0 136 multiplyScalar : function(c1, f) {
michael@0 137 var result = new Flog.RayTracer.Color(0,0,0);
michael@0 138
michael@0 139 result.red = c1.red * f;
michael@0 140 result.green = c1.green * f;
michael@0 141 result.blue = c1.blue * f;
michael@0 142
michael@0 143 return result;
michael@0 144 },
michael@0 145
michael@0 146 divideFactor : function(c1, f) {
michael@0 147 var result = new Flog.RayTracer.Color(0,0,0);
michael@0 148
michael@0 149 result.red = c1.red / f;
michael@0 150 result.green = c1.green / f;
michael@0 151 result.blue = c1.blue / f;
michael@0 152
michael@0 153 return result;
michael@0 154 },
michael@0 155
michael@0 156 limit: function(){
michael@0 157 this.red = (this.red > 0.0) ? ( (this.red > 1.0) ? 1.0 : this.red ) : 0.0;
michael@0 158 this.green = (this.green > 0.0) ? ( (this.green > 1.0) ? 1.0 : this.green ) : 0.0;
michael@0 159 this.blue = (this.blue > 0.0) ? ( (this.blue > 1.0) ? 1.0 : this.blue ) : 0.0;
michael@0 160 },
michael@0 161
michael@0 162 distance : function(color) {
michael@0 163 var d = Math.abs(this.red - color.red) + Math.abs(this.green - color.green) + Math.abs(this.blue - color.blue);
michael@0 164 return d;
michael@0 165 },
michael@0 166
michael@0 167 blend: function(c1, c2, w){
michael@0 168 var result = new Flog.RayTracer.Color(0,0,0);
michael@0 169 result = Flog.RayTracer.Color.prototype.add(
michael@0 170 Flog.RayTracer.Color.prototype.multiplyScalar(c1, 1 - w),
michael@0 171 Flog.RayTracer.Color.prototype.multiplyScalar(c2, w)
michael@0 172 );
michael@0 173 return result;
michael@0 174 },
michael@0 175
michael@0 176 brightness : function() {
michael@0 177 var r = Math.floor(this.red*255);
michael@0 178 var g = Math.floor(this.green*255);
michael@0 179 var b = Math.floor(this.blue*255);
michael@0 180 return (r * 77 + g * 150 + b * 29) >> 8;
michael@0 181 },
michael@0 182
michael@0 183 toString : function () {
michael@0 184 var r = Math.floor(this.red*255);
michael@0 185 var g = Math.floor(this.green*255);
michael@0 186 var b = Math.floor(this.blue*255);
michael@0 187
michael@0 188 return "rgb("+ r +","+ g +","+ b +")";
michael@0 189 }
michael@0 190 }
michael@0 191 /* Fake a Flog.* namespace */
michael@0 192 if(typeof(Flog) == 'undefined') var Flog = {};
michael@0 193 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
michael@0 194
michael@0 195 Flog.RayTracer.Light = Class.create();
michael@0 196
michael@0 197 Flog.RayTracer.Light.prototype = {
michael@0 198 position: null,
michael@0 199 color: null,
michael@0 200 intensity: 10.0,
michael@0 201
michael@0 202 initialize : function(pos, color, intensity) {
michael@0 203 this.position = pos;
michael@0 204 this.color = color;
michael@0 205 this.intensity = (intensity ? intensity : 10.0);
michael@0 206 },
michael@0 207
michael@0 208 getIntensity: function(distance){
michael@0 209 if(distance >= intensity) return 0;
michael@0 210
michael@0 211 return Math.pow((intensity - distance) / strength, 0.2);
michael@0 212 },
michael@0 213
michael@0 214 toString : function () {
michael@0 215 return 'Light [' + this.position.x + ',' + this.position.y + ',' + this.position.z + ']';
michael@0 216 }
michael@0 217 }
michael@0 218 /* Fake a Flog.* namespace */
michael@0 219 if(typeof(Flog) == 'undefined') var Flog = {};
michael@0 220 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
michael@0 221
michael@0 222 Flog.RayTracer.Vector = Class.create();
michael@0 223
michael@0 224 Flog.RayTracer.Vector.prototype = {
michael@0 225 x : 0.0,
michael@0 226 y : 0.0,
michael@0 227 z : 0.0,
michael@0 228
michael@0 229 initialize : function(x, y, z) {
michael@0 230 this.x = (x ? x : 0);
michael@0 231 this.y = (y ? y : 0);
michael@0 232 this.z = (z ? z : 0);
michael@0 233 },
michael@0 234
michael@0 235 copy: function(vector){
michael@0 236 this.x = vector.x;
michael@0 237 this.y = vector.y;
michael@0 238 this.z = vector.z;
michael@0 239 },
michael@0 240
michael@0 241 normalize : function() {
michael@0 242 var m = this.magnitude();
michael@0 243 return new Flog.RayTracer.Vector(this.x / m, this.y / m, this.z / m);
michael@0 244 },
michael@0 245
michael@0 246 magnitude : function() {
michael@0 247 return Math.sqrt((this.x * this.x) + (this.y * this.y) + (this.z * this.z));
michael@0 248 },
michael@0 249
michael@0 250 cross : function(w) {
michael@0 251 return new Flog.RayTracer.Vector(
michael@0 252 -this.z * w.y + this.y * w.z,
michael@0 253 this.z * w.x - this.x * w.z,
michael@0 254 -this.y * w.x + this.x * w.y);
michael@0 255 },
michael@0 256
michael@0 257 dot : function(w) {
michael@0 258 return this.x * w.x + this.y * w.y + this.z * w.z;
michael@0 259 },
michael@0 260
michael@0 261 add : function(v, w) {
michael@0 262 return new Flog.RayTracer.Vector(w.x + v.x, w.y + v.y, w.z + v.z);
michael@0 263 },
michael@0 264
michael@0 265 subtract : function(v, w) {
michael@0 266 if(!w || !v) throw 'Vectors must be defined [' + v + ',' + w + ']';
michael@0 267 return new Flog.RayTracer.Vector(v.x - w.x, v.y - w.y, v.z - w.z);
michael@0 268 },
michael@0 269
michael@0 270 multiplyVector : function(v, w) {
michael@0 271 return new Flog.RayTracer.Vector(v.x * w.x, v.y * w.y, v.z * w.z);
michael@0 272 },
michael@0 273
michael@0 274 multiplyScalar : function(v, w) {
michael@0 275 return new Flog.RayTracer.Vector(v.x * w, v.y * w, v.z * w);
michael@0 276 },
michael@0 277
michael@0 278 toString : function () {
michael@0 279 return 'Vector [' + this.x + ',' + this.y + ',' + this.z + ']';
michael@0 280 }
michael@0 281 }
michael@0 282 /* Fake a Flog.* namespace */
michael@0 283 if(typeof(Flog) == 'undefined') var Flog = {};
michael@0 284 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
michael@0 285
michael@0 286 Flog.RayTracer.Ray = Class.create();
michael@0 287
michael@0 288 Flog.RayTracer.Ray.prototype = {
michael@0 289 position : null,
michael@0 290 direction : null,
michael@0 291 initialize : function(pos, dir) {
michael@0 292 this.position = pos;
michael@0 293 this.direction = dir;
michael@0 294 },
michael@0 295
michael@0 296 toString : function () {
michael@0 297 return 'Ray [' + this.position + ',' + this.direction + ']';
michael@0 298 }
michael@0 299 }
michael@0 300 /* Fake a Flog.* namespace */
michael@0 301 if(typeof(Flog) == 'undefined') var Flog = {};
michael@0 302 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
michael@0 303
michael@0 304 Flog.RayTracer.Scene = Class.create();
michael@0 305
michael@0 306 Flog.RayTracer.Scene.prototype = {
michael@0 307 camera : null,
michael@0 308 shapes : [],
michael@0 309 lights : [],
michael@0 310 background : null,
michael@0 311
michael@0 312 initialize : function() {
michael@0 313 this.camera = new Flog.RayTracer.Camera(
michael@0 314 new Flog.RayTracer.Vector(0,0,-5),
michael@0 315 new Flog.RayTracer.Vector(0,0,1),
michael@0 316 new Flog.RayTracer.Vector(0,1,0)
michael@0 317 );
michael@0 318 this.shapes = new Array();
michael@0 319 this.lights = new Array();
michael@0 320 this.background = new Flog.RayTracer.Background(new Flog.RayTracer.Color(0,0,0.5), 0.2);
michael@0 321 }
michael@0 322 }
michael@0 323 /* Fake a Flog.* namespace */
michael@0 324 if(typeof(Flog) == 'undefined') var Flog = {};
michael@0 325 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
michael@0 326 if(typeof(Flog.RayTracer.Material) == 'undefined') Flog.RayTracer.Material = {};
michael@0 327
michael@0 328 Flog.RayTracer.Material.BaseMaterial = Class.create();
michael@0 329
michael@0 330 Flog.RayTracer.Material.BaseMaterial.prototype = {
michael@0 331
michael@0 332 gloss: 2.0, // [0...infinity] 0 = matt
michael@0 333 transparency: 0.0, // 0=opaque
michael@0 334 reflection: 0.0, // [0...infinity] 0 = no reflection
michael@0 335 refraction: 0.50,
michael@0 336 hasTexture: false,
michael@0 337
michael@0 338 initialize : function() {
michael@0 339
michael@0 340 },
michael@0 341
michael@0 342 getColor: function(u, v){
michael@0 343
michael@0 344 },
michael@0 345
michael@0 346 wrapUp: function(t){
michael@0 347 t = t % 2.0;
michael@0 348 if(t < -1) t += 2.0;
michael@0 349 if(t >= 1) t -= 2.0;
michael@0 350 return t;
michael@0 351 },
michael@0 352
michael@0 353 toString : function () {
michael@0 354 return 'Material [gloss=' + this.gloss + ', transparency=' + this.transparency + ', hasTexture=' + this.hasTexture +']';
michael@0 355 }
michael@0 356 }
michael@0 357 /* Fake a Flog.* namespace */
michael@0 358 if(typeof(Flog) == 'undefined') var Flog = {};
michael@0 359 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
michael@0 360
michael@0 361 Flog.RayTracer.Material.Solid = Class.create();
michael@0 362
michael@0 363 Flog.RayTracer.Material.Solid.prototype = Object.extend(
michael@0 364 new Flog.RayTracer.Material.BaseMaterial(), {
michael@0 365 initialize : function(color, reflection, refraction, transparency, gloss) {
michael@0 366 this.color = color;
michael@0 367 this.reflection = reflection;
michael@0 368 this.transparency = transparency;
michael@0 369 this.gloss = gloss;
michael@0 370 this.hasTexture = false;
michael@0 371 },
michael@0 372
michael@0 373 getColor: function(u, v){
michael@0 374 return this.color;
michael@0 375 },
michael@0 376
michael@0 377 toString : function () {
michael@0 378 return 'SolidMaterial [gloss=' + this.gloss + ', transparency=' + this.transparency + ', hasTexture=' + this.hasTexture +']';
michael@0 379 }
michael@0 380 }
michael@0 381 );
michael@0 382 /* Fake a Flog.* namespace */
michael@0 383 if(typeof(Flog) == 'undefined') var Flog = {};
michael@0 384 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
michael@0 385
michael@0 386 Flog.RayTracer.Material.Chessboard = Class.create();
michael@0 387
michael@0 388 Flog.RayTracer.Material.Chessboard.prototype = Object.extend(
michael@0 389 new Flog.RayTracer.Material.BaseMaterial(), {
michael@0 390 colorEven: null,
michael@0 391 colorOdd: null,
michael@0 392 density: 0.5,
michael@0 393
michael@0 394 initialize : function(colorEven, colorOdd, reflection, transparency, gloss, density) {
michael@0 395 this.colorEven = colorEven;
michael@0 396 this.colorOdd = colorOdd;
michael@0 397 this.reflection = reflection;
michael@0 398 this.transparency = transparency;
michael@0 399 this.gloss = gloss;
michael@0 400 this.density = density;
michael@0 401 this.hasTexture = true;
michael@0 402 },
michael@0 403
michael@0 404 getColor: function(u, v){
michael@0 405 var t = this.wrapUp(u * this.density) * this.wrapUp(v * this.density);
michael@0 406
michael@0 407 if(t < 0.0)
michael@0 408 return this.colorEven;
michael@0 409 else
michael@0 410 return this.colorOdd;
michael@0 411 },
michael@0 412
michael@0 413 toString : function () {
michael@0 414 return 'ChessMaterial [gloss=' + this.gloss + ', transparency=' + this.transparency + ', hasTexture=' + this.hasTexture +']';
michael@0 415 }
michael@0 416 }
michael@0 417 );
michael@0 418 /* Fake a Flog.* namespace */
michael@0 419 if(typeof(Flog) == 'undefined') var Flog = {};
michael@0 420 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
michael@0 421 if(typeof(Flog.RayTracer.Shape) == 'undefined') Flog.RayTracer.Shape = {};
michael@0 422
michael@0 423 Flog.RayTracer.Shape.BaseShape = Class.create();
michael@0 424
michael@0 425 Flog.RayTracer.Shape.BaseShape.prototype = {
michael@0 426 position: null,
michael@0 427 material: null,
michael@0 428
michael@0 429 initialize : function() {
michael@0 430 this.position = new Vector(0,0,0);
michael@0 431 this.material = new Flog.RayTracer.Material.SolidMaterial(
michael@0 432 new Flog.RayTracer.Color(1,0,1),
michael@0 433 0,
michael@0 434 0,
michael@0 435 0
michael@0 436 );
michael@0 437 },
michael@0 438
michael@0 439 toString : function () {
michael@0 440 return 'Material [gloss=' + this.gloss + ', transparency=' + this.transparency + ', hasTexture=' + this.hasTexture +']';
michael@0 441 }
michael@0 442 }
michael@0 443 /* Fake a Flog.* namespace */
michael@0 444 if(typeof(Flog) == 'undefined') var Flog = {};
michael@0 445 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
michael@0 446 if(typeof(Flog.RayTracer.Shape) == 'undefined') Flog.RayTracer.Shape = {};
michael@0 447
michael@0 448 Flog.RayTracer.Shape.Sphere = Class.create();
michael@0 449
michael@0 450 Flog.RayTracer.Shape.Sphere.prototype = {
michael@0 451 initialize : function(pos, radius, material) {
michael@0 452 this.radius = radius;
michael@0 453 this.position = pos;
michael@0 454 this.material = material;
michael@0 455 },
michael@0 456
michael@0 457 intersect: function(ray){
michael@0 458 var info = new Flog.RayTracer.IntersectionInfo();
michael@0 459 info.shape = this;
michael@0 460
michael@0 461 var dst = Flog.RayTracer.Vector.prototype.subtract(ray.position, this.position);
michael@0 462
michael@0 463 var B = dst.dot(ray.direction);
michael@0 464 var C = dst.dot(dst) - (this.radius * this.radius);
michael@0 465 var D = (B * B) - C;
michael@0 466
michael@0 467 if(D > 0){ // intersection!
michael@0 468 info.isHit = true;
michael@0 469 info.distance = (-B) - Math.sqrt(D);
michael@0 470 info.position = Flog.RayTracer.Vector.prototype.add(
michael@0 471 ray.position,
michael@0 472 Flog.RayTracer.Vector.prototype.multiplyScalar(
michael@0 473 ray.direction,
michael@0 474 info.distance
michael@0 475 )
michael@0 476 );
michael@0 477 info.normal = Flog.RayTracer.Vector.prototype.subtract(
michael@0 478 info.position,
michael@0 479 this.position
michael@0 480 ).normalize();
michael@0 481
michael@0 482 info.color = this.material.getColor(0,0);
michael@0 483 } else {
michael@0 484 info.isHit = false;
michael@0 485 }
michael@0 486 return info;
michael@0 487 },
michael@0 488
michael@0 489 toString : function () {
michael@0 490 return 'Sphere [position=' + this.position + ', radius=' + this.radius + ']';
michael@0 491 }
michael@0 492 }
michael@0 493 /* Fake a Flog.* namespace */
michael@0 494 if(typeof(Flog) == 'undefined') var Flog = {};
michael@0 495 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
michael@0 496 if(typeof(Flog.RayTracer.Shape) == 'undefined') Flog.RayTracer.Shape = {};
michael@0 497
michael@0 498 Flog.RayTracer.Shape.Plane = Class.create();
michael@0 499
michael@0 500 Flog.RayTracer.Shape.Plane.prototype = {
michael@0 501 d: 0.0,
michael@0 502
michael@0 503 initialize : function(pos, d, material) {
michael@0 504 this.position = pos;
michael@0 505 this.d = d;
michael@0 506 this.material = material;
michael@0 507 },
michael@0 508
michael@0 509 intersect: function(ray){
michael@0 510 var info = new Flog.RayTracer.IntersectionInfo();
michael@0 511
michael@0 512 var Vd = this.position.dot(ray.direction);
michael@0 513 if(Vd == 0) return info; // no intersection
michael@0 514
michael@0 515 var t = -(this.position.dot(ray.position) + this.d) / Vd;
michael@0 516 if(t <= 0) return info;
michael@0 517
michael@0 518 info.shape = this;
michael@0 519 info.isHit = true;
michael@0 520 info.position = Flog.RayTracer.Vector.prototype.add(
michael@0 521 ray.position,
michael@0 522 Flog.RayTracer.Vector.prototype.multiplyScalar(
michael@0 523 ray.direction,
michael@0 524 t
michael@0 525 )
michael@0 526 );
michael@0 527 info.normal = this.position;
michael@0 528 info.distance = t;
michael@0 529
michael@0 530 if(this.material.hasTexture){
michael@0 531 var vU = new Flog.RayTracer.Vector(this.position.y, this.position.z, -this.position.x);
michael@0 532 var vV = vU.cross(this.position);
michael@0 533 var u = info.position.dot(vU);
michael@0 534 var v = info.position.dot(vV);
michael@0 535 info.color = this.material.getColor(u,v);
michael@0 536 } else {
michael@0 537 info.color = this.material.getColor(0,0);
michael@0 538 }
michael@0 539
michael@0 540 return info;
michael@0 541 },
michael@0 542
michael@0 543 toString : function () {
michael@0 544 return 'Plane [' + this.position + ', d=' + this.d + ']';
michael@0 545 }
michael@0 546 }
michael@0 547 /* Fake a Flog.* namespace */
michael@0 548 if(typeof(Flog) == 'undefined') var Flog = {};
michael@0 549 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
michael@0 550
michael@0 551 Flog.RayTracer.IntersectionInfo = Class.create();
michael@0 552
michael@0 553 Flog.RayTracer.IntersectionInfo.prototype = {
michael@0 554 isHit: false,
michael@0 555 hitCount: 0,
michael@0 556 shape: null,
michael@0 557 position: null,
michael@0 558 normal: null,
michael@0 559 color: null,
michael@0 560 distance: null,
michael@0 561
michael@0 562 initialize : function() {
michael@0 563 this.color = new Flog.RayTracer.Color(0,0,0);
michael@0 564 },
michael@0 565
michael@0 566 toString : function () {
michael@0 567 return 'Intersection [' + this.position + ']';
michael@0 568 }
michael@0 569 }
michael@0 570 /* Fake a Flog.* namespace */
michael@0 571 if(typeof(Flog) == 'undefined') var Flog = {};
michael@0 572 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
michael@0 573
michael@0 574 Flog.RayTracer.Camera = Class.create();
michael@0 575
michael@0 576 Flog.RayTracer.Camera.prototype = {
michael@0 577 position: null,
michael@0 578 lookAt: null,
michael@0 579 equator: null,
michael@0 580 up: null,
michael@0 581 screen: null,
michael@0 582
michael@0 583 initialize : function(pos, lookAt, up) {
michael@0 584 this.position = pos;
michael@0 585 this.lookAt = lookAt;
michael@0 586 this.up = up;
michael@0 587 this.equator = lookAt.normalize().cross(this.up);
michael@0 588 this.screen = Flog.RayTracer.Vector.prototype.add(this.position, this.lookAt);
michael@0 589 },
michael@0 590
michael@0 591 getRay: function(vx, vy){
michael@0 592 var pos = Flog.RayTracer.Vector.prototype.subtract(
michael@0 593 this.screen,
michael@0 594 Flog.RayTracer.Vector.prototype.subtract(
michael@0 595 Flog.RayTracer.Vector.prototype.multiplyScalar(this.equator, vx),
michael@0 596 Flog.RayTracer.Vector.prototype.multiplyScalar(this.up, vy)
michael@0 597 )
michael@0 598 );
michael@0 599 pos.y = pos.y * -1;
michael@0 600 var dir = Flog.RayTracer.Vector.prototype.subtract(
michael@0 601 pos,
michael@0 602 this.position
michael@0 603 );
michael@0 604
michael@0 605 var ray = new Flog.RayTracer.Ray(pos, dir.normalize());
michael@0 606
michael@0 607 return ray;
michael@0 608 },
michael@0 609
michael@0 610 toString : function () {
michael@0 611 return 'Ray []';
michael@0 612 }
michael@0 613 }
michael@0 614 /* Fake a Flog.* namespace */
michael@0 615 if(typeof(Flog) == 'undefined') var Flog = {};
michael@0 616 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
michael@0 617
michael@0 618 Flog.RayTracer.Background = Class.create();
michael@0 619
michael@0 620 Flog.RayTracer.Background.prototype = {
michael@0 621 color : null,
michael@0 622 ambience : 0.0,
michael@0 623
michael@0 624 initialize : function(color, ambience) {
michael@0 625 this.color = color;
michael@0 626 this.ambience = ambience;
michael@0 627 }
michael@0 628 }
michael@0 629 /* Fake a Flog.* namespace */
michael@0 630 if(typeof(Flog) == 'undefined') var Flog = {};
michael@0 631 if(typeof(Flog.RayTracer) == 'undefined') Flog.RayTracer = {};
michael@0 632
michael@0 633 Flog.RayTracer.Engine = Class.create();
michael@0 634
michael@0 635 Flog.RayTracer.Engine.prototype = {
michael@0 636 canvas: null, /* 2d context we can render to */
michael@0 637
michael@0 638 initialize: function(options){
michael@0 639 this.options = Object.extend({
michael@0 640 canvasHeight: 100,
michael@0 641 canvasWidth: 100,
michael@0 642 pixelWidth: 2,
michael@0 643 pixelHeight: 2,
michael@0 644 renderDiffuse: false,
michael@0 645 renderShadows: false,
michael@0 646 renderHighlights: false,
michael@0 647 renderReflections: false,
michael@0 648 rayDepth: 2
michael@0 649 }, options || {});
michael@0 650
michael@0 651 this.options.canvasHeight /= this.options.pixelHeight;
michael@0 652 this.options.canvasWidth /= this.options.pixelWidth;
michael@0 653
michael@0 654 /* TODO: dynamically include other scripts */
michael@0 655 },
michael@0 656
michael@0 657 setPixel: function(x, y, color){
michael@0 658 var pxW, pxH;
michael@0 659 pxW = this.options.pixelWidth;
michael@0 660 pxH = this.options.pixelHeight;
michael@0 661
michael@0 662 if (this.canvas) {
michael@0 663 this.canvas.fillStyle = color.toString();
michael@0 664 this.canvas.fillRect (x * pxW, y * pxH, pxW, pxH);
michael@0 665 } else {
michael@0 666 if (x === y) {
michael@0 667 checkNumber += color.brightness();
michael@0 668 }
michael@0 669 // print(x * pxW, y * pxH, pxW, pxH);
michael@0 670 }
michael@0 671 },
michael@0 672
michael@0 673 renderScene: function(scene, canvas){
michael@0 674 checkNumber = 0;
michael@0 675 /* Get canvas */
michael@0 676 if (canvas) {
michael@0 677 this.canvas = canvas.getContext("2d");
michael@0 678 } else {
michael@0 679 this.canvas = null;
michael@0 680 }
michael@0 681
michael@0 682 var canvasHeight = this.options.canvasHeight;
michael@0 683 var canvasWidth = this.options.canvasWidth;
michael@0 684
michael@0 685 for(var y=0; y < canvasHeight; y++){
michael@0 686 for(var x=0; x < canvasWidth; x++){
michael@0 687 var yp = y * 1.0 / canvasHeight * 2 - 1;
michael@0 688 var xp = x * 1.0 / canvasWidth * 2 - 1;
michael@0 689
michael@0 690 var ray = scene.camera.getRay(xp, yp);
michael@0 691
michael@0 692 var color = this.getPixelColor(ray, scene);
michael@0 693
michael@0 694 this.setPixel(x, y, color);
michael@0 695 }
michael@0 696 }
michael@0 697 assertEq(checkNumber, 2321);
michael@0 698 },
michael@0 699
michael@0 700 getPixelColor: function(ray, scene){
michael@0 701 var info = this.testIntersection(ray, scene, null);
michael@0 702 if(info.isHit){
michael@0 703 var color = this.rayTrace(info, ray, scene, 0);
michael@0 704 return color;
michael@0 705 }
michael@0 706 return scene.background.color;
michael@0 707 },
michael@0 708
michael@0 709 testIntersection: function(ray, scene, exclude){
michael@0 710 var hits = 0;
michael@0 711 var best = new Flog.RayTracer.IntersectionInfo();
michael@0 712 best.distance = 2000;
michael@0 713
michael@0 714 for(var i=0; i<scene.shapes.length; i++){
michael@0 715 var shape = scene.shapes[i];
michael@0 716
michael@0 717 if(shape != exclude){
michael@0 718 var info = shape.intersect(ray);
michael@0 719 if(info.isHit && info.distance >= 0 && info.distance < best.distance){
michael@0 720 best = info;
michael@0 721 hits++;
michael@0 722 }
michael@0 723 }
michael@0 724 }
michael@0 725 best.hitCount = hits;
michael@0 726 return best;
michael@0 727 },
michael@0 728
michael@0 729 getReflectionRay: function(P,N,V){
michael@0 730 var c1 = -N.dot(V);
michael@0 731 var R1 = Flog.RayTracer.Vector.prototype.add(
michael@0 732 Flog.RayTracer.Vector.prototype.multiplyScalar(N, 2*c1),
michael@0 733 V
michael@0 734 );
michael@0 735 return new Flog.RayTracer.Ray(P, R1);
michael@0 736 },
michael@0 737
michael@0 738 rayTrace: function(info, ray, scene, depth){
michael@0 739 // Calc ambient
michael@0 740 var color = Flog.RayTracer.Color.prototype.multiplyScalar(info.color, scene.background.ambience);
michael@0 741 var oldColor = color;
michael@0 742 var shininess = Math.pow(10, info.shape.material.gloss + 1);
michael@0 743
michael@0 744 for(var i=0; i<scene.lights.length; i++){
michael@0 745 var light = scene.lights[i];
michael@0 746
michael@0 747 // Calc diffuse lighting
michael@0 748 var v = Flog.RayTracer.Vector.prototype.subtract(
michael@0 749 light.position,
michael@0 750 info.position
michael@0 751 ).normalize();
michael@0 752
michael@0 753 if(this.options.renderDiffuse){
michael@0 754 var L = v.dot(info.normal);
michael@0 755 if(L > 0.0){
michael@0 756 color = Flog.RayTracer.Color.prototype.add(
michael@0 757 color,
michael@0 758 Flog.RayTracer.Color.prototype.multiply(
michael@0 759 info.color,
michael@0 760 Flog.RayTracer.Color.prototype.multiplyScalar(
michael@0 761 light.color,
michael@0 762 L
michael@0 763 )
michael@0 764 )
michael@0 765 );
michael@0 766 }
michael@0 767 }
michael@0 768
michael@0 769 // The greater the depth the more accurate the colours, but
michael@0 770 // this is exponentially (!) expensive
michael@0 771 if(depth <= this.options.rayDepth){
michael@0 772 // calculate reflection ray
michael@0 773 if(this.options.renderReflections && info.shape.material.reflection > 0)
michael@0 774 {
michael@0 775 var reflectionRay = this.getReflectionRay(info.position, info.normal, ray.direction);
michael@0 776 var refl = this.testIntersection(reflectionRay, scene, info.shape);
michael@0 777
michael@0 778 if (refl.isHit && refl.distance > 0){
michael@0 779 refl.color = this.rayTrace(refl, reflectionRay, scene, depth + 1);
michael@0 780 } else {
michael@0 781 refl.color = scene.background.color;
michael@0 782 }
michael@0 783
michael@0 784 color = Flog.RayTracer.Color.prototype.blend(
michael@0 785 color,
michael@0 786 refl.color,
michael@0 787 info.shape.material.reflection
michael@0 788 );
michael@0 789 }
michael@0 790
michael@0 791 // Refraction
michael@0 792 /* TODO */
michael@0 793 }
michael@0 794
michael@0 795 /* Render shadows and highlights */
michael@0 796
michael@0 797 var shadowInfo = new Flog.RayTracer.IntersectionInfo();
michael@0 798
michael@0 799 if(this.options.renderShadows){
michael@0 800 var shadowRay = new Flog.RayTracer.Ray(info.position, v);
michael@0 801
michael@0 802 shadowInfo = this.testIntersection(shadowRay, scene, info.shape);
michael@0 803 if(shadowInfo.isHit && shadowInfo.shape != info.shape /*&& shadowInfo.shape.type != 'PLANE'*/){
michael@0 804 var vA = Flog.RayTracer.Color.prototype.multiplyScalar(color, 0.5);
michael@0 805 var dB = (0.5 * Math.pow(shadowInfo.shape.material.transparency, 0.5));
michael@0 806 color = Flog.RayTracer.Color.prototype.addScalar(vA,dB);
michael@0 807 }
michael@0 808 }
michael@0 809
michael@0 810 // Phong specular highlights
michael@0 811 if(this.options.renderHighlights && !shadowInfo.isHit && info.shape.material.gloss > 0){
michael@0 812 var Lv = Flog.RayTracer.Vector.prototype.subtract(
michael@0 813 info.shape.position,
michael@0 814 light.position
michael@0 815 ).normalize();
michael@0 816
michael@0 817 var E = Flog.RayTracer.Vector.prototype.subtract(
michael@0 818 scene.camera.position,
michael@0 819 info.shape.position
michael@0 820 ).normalize();
michael@0 821
michael@0 822 var H = Flog.RayTracer.Vector.prototype.subtract(
michael@0 823 E,
michael@0 824 Lv
michael@0 825 ).normalize();
michael@0 826
michael@0 827 var glossWeight = Math.pow(Math.max(info.normal.dot(H), 0), shininess);
michael@0 828 color = Flog.RayTracer.Color.prototype.add(
michael@0 829 Flog.RayTracer.Color.prototype.multiplyScalar(light.color, glossWeight),
michael@0 830 color
michael@0 831 );
michael@0 832 }
michael@0 833 }
michael@0 834 color.limit();
michael@0 835 return color;
michael@0 836 }
michael@0 837 };
michael@0 838
michael@0 839
michael@0 840 function renderScene(){
michael@0 841 var scene = new Flog.RayTracer.Scene();
michael@0 842
michael@0 843 scene.camera = new Flog.RayTracer.Camera(
michael@0 844 new Flog.RayTracer.Vector(0, 0, -15),
michael@0 845 new Flog.RayTracer.Vector(-0.2, 0, 5),
michael@0 846 new Flog.RayTracer.Vector(0, 1, 0)
michael@0 847 );
michael@0 848
michael@0 849 scene.background = new Flog.RayTracer.Background(
michael@0 850 new Flog.RayTracer.Color(0.5, 0.5, 0.5),
michael@0 851 0.4
michael@0 852 );
michael@0 853
michael@0 854 var sphere = new Flog.RayTracer.Shape.Sphere(
michael@0 855 new Flog.RayTracer.Vector(-1.5, 1.5, 2),
michael@0 856 1.5,
michael@0 857 new Flog.RayTracer.Material.Solid(
michael@0 858 new Flog.RayTracer.Color(0,0.5,0.5),
michael@0 859 0.3,
michael@0 860 0.0,
michael@0 861 0.0,
michael@0 862 2.0
michael@0 863 )
michael@0 864 );
michael@0 865
michael@0 866 var sphere1 = new Flog.RayTracer.Shape.Sphere(
michael@0 867 new Flog.RayTracer.Vector(1, 0.25, 1),
michael@0 868 0.5,
michael@0 869 new Flog.RayTracer.Material.Solid(
michael@0 870 new Flog.RayTracer.Color(0.9,0.9,0.9),
michael@0 871 0.1,
michael@0 872 0.0,
michael@0 873 0.0,
michael@0 874 1.5
michael@0 875 )
michael@0 876 );
michael@0 877
michael@0 878 var plane = new Flog.RayTracer.Shape.Plane(
michael@0 879 new Flog.RayTracer.Vector(0.1, 0.9, -0.5).normalize(),
michael@0 880 1.2,
michael@0 881 new Flog.RayTracer.Material.Chessboard(
michael@0 882 new Flog.RayTracer.Color(1,1,1),
michael@0 883 new Flog.RayTracer.Color(0,0,0),
michael@0 884 0.2,
michael@0 885 0.0,
michael@0 886 1.0,
michael@0 887 0.7
michael@0 888 )
michael@0 889 );
michael@0 890
michael@0 891 scene.shapes.push(plane);
michael@0 892 scene.shapes.push(sphere);
michael@0 893 scene.shapes.push(sphere1);
michael@0 894
michael@0 895 var light = new Flog.RayTracer.Light(
michael@0 896 new Flog.RayTracer.Vector(5, 10, -1),
michael@0 897 new Flog.RayTracer.Color(0.8, 0.8, 0.8)
michael@0 898 );
michael@0 899
michael@0 900 var light1 = new Flog.RayTracer.Light(
michael@0 901 new Flog.RayTracer.Vector(-3, 5, -15),
michael@0 902 new Flog.RayTracer.Color(0.8, 0.8, 0.8),
michael@0 903 100
michael@0 904 );
michael@0 905
michael@0 906 scene.lights.push(light);
michael@0 907 scene.lights.push(light1);
michael@0 908
michael@0 909 var imageWidth = 100; // $F('imageWidth');
michael@0 910 var imageHeight = 100; // $F('imageHeight');
michael@0 911 var pixelSize = "5,5".split(','); // $F('pixelSize').split(',');
michael@0 912 var renderDiffuse = true; // $F('renderDiffuse');
michael@0 913 var renderShadows = true; // $F('renderShadows');
michael@0 914 var renderHighlights = true; // $F('renderHighlights');
michael@0 915 var renderReflections = true; // $F('renderReflections');
michael@0 916 var rayDepth = 2;//$F('rayDepth');
michael@0 917
michael@0 918 var raytracer = new Flog.RayTracer.Engine(
michael@0 919 {
michael@0 920 canvasWidth: imageWidth,
michael@0 921 canvasHeight: imageHeight,
michael@0 922 pixelWidth: pixelSize[0],
michael@0 923 pixelHeight: pixelSize[1],
michael@0 924 "renderDiffuse": renderDiffuse,
michael@0 925 "renderHighlights": renderHighlights,
michael@0 926 "renderShadows": renderShadows,
michael@0 927 "renderReflections": renderReflections,
michael@0 928 "rayDepth": rayDepth
michael@0 929 }
michael@0 930 );
michael@0 931
michael@0 932 raytracer.renderScene(scene, null, 0);
michael@0 933 }
michael@0 934
michael@0 935 renderScene();

mercurial