RaytracingWorkerRenderer.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. /**
  2. * The way to use RaytracingWorkerRenderer is similar to RaytracingRenderer
  3. * except that it is simply a coordinator for workers. The workers compute
  4. * the pixel values and this renderer simply paints it to the Canvas. As such,
  5. * it is simply a renderer.
  6. *
  7. * TODO
  8. * - serialize scene and hand it to workers
  9. * - pass worker path as option
  10. *
  11. * @author zz85 / http://github.com/zz85
  12. */
  13. THREE.RaytracingWorkerRenderer = function ( parameters ) {
  14. console.log( 'THREE.RaytracingWorkerRenderer', THREE.REVISION );
  15. parameters = parameters || {};
  16. var scope = this;
  17. var pool = [];
  18. var canvas = document.createElement( 'canvas' );
  19. var context = canvas.getContext( '2d', {
  20. alpha: parameters.alpha === true
  21. } );
  22. var maxRecursionDepth = 3;
  23. var canvasWidth, canvasHeight;
  24. var canvasWidthHalf, canvasHeightHalf;
  25. var clearColor = new THREE.Color( 0x000000 );
  26. this.domElement = canvas;
  27. this.autoClear = true;
  28. var workers = parameters.workers || navigator.hardwareConcurrency || 4;
  29. var blockSize = parameters.blockSize || 64;
  30. console.log('%cSpinning off ' + workers + ' Workers ', 'font-size: 20px; background: black; color: white; font-family: monospace;');
  31. for (var i = 0; i < workers; i++) {
  32. var worker = new Worker('js/renderers/RaytracingWorker.js');
  33. worker.onmessage = function(e) {
  34. var data = e.data;
  35. if (!data) return;
  36. if (data.blockSize) {
  37. var d = data.data;
  38. var imagedata = new ImageData(new Uint8ClampedArray(d), data.blockSize, data.blockSize);
  39. context.putImageData( imagedata, data.blockX, data.blockY );
  40. } else if (data.type == 'complete') {
  41. // TODO can terminate workers after all is done?
  42. console.log('Worker ' + data.worker, data.time / 1000, (Date.now() - reallyThen) / 1000 + ' s');
  43. renderNext(this);
  44. }
  45. }
  46. worker.color = new THREE.Color().setHSL(i / workers, 0.8, 0.8).getHexString();
  47. pool.push(worker);
  48. }
  49. this.setClearColor = function ( color, alpha ) {
  50. clearColor.set( color );
  51. };
  52. this.setPixelRatio = function () {};
  53. this.setSize = function ( width, height ) {
  54. canvas.width = width;
  55. canvas.height = height;
  56. canvasWidth = canvas.width;
  57. canvasHeight = canvas.height;
  58. canvasWidthHalf = Math.floor( canvasWidth / 2 );
  59. canvasHeightHalf = Math.floor( canvasHeight / 2 );
  60. context.fillStyle = 'white';
  61. pool.forEach( function( p, i ) {
  62. p.postMessage({
  63. init: [ width, height ],
  64. worker: i,
  65. workers: pool.length,
  66. blockSize: blockSize,
  67. initScene: initScene.toString()
  68. });
  69. });
  70. };
  71. this.setSize( canvas.width, canvas.height );
  72. this.clear = function () {
  73. };
  74. //
  75. var nextBlock, totalBlocks, xblocks, yblocks;
  76. function renderNext(worker) {
  77. var current = nextBlock++;
  78. if (nextBlock > totalBlocks) {
  79. return scope.dispatchEvent( { type: "complete" } );
  80. }
  81. var blockX = (current % xblocks) * blockSize;
  82. var blockY = (current / xblocks | 0) * blockSize;
  83. worker.postMessage({
  84. render: true,
  85. x: blockX,
  86. y: blockY
  87. });
  88. context.fillStyle = '#' + worker.color;
  89. context.fillRect( blockX, blockY, blockSize, blockSize );
  90. }
  91. this.render = function ( scene, camera ) {
  92. var sceneJSON = scene.toJSON();
  93. var cameraJSON = camera.toJSON();
  94. pool.forEach(function(worker) {
  95. worker.postMessage({
  96. scene: sceneJSON,
  97. camera: cameraJSON
  98. });
  99. });
  100. context.clearRect( 0, 0, canvasWidth, canvasHeight );
  101. reallyThen = Date.now();
  102. xblocks = Math.ceil(canvasWidth / blockSize);
  103. yblocks = Math.ceil(canvasHeight / blockSize);
  104. nextBlock = 0;
  105. totalBlocks = xblocks * yblocks;
  106. pool.forEach(renderNext);
  107. };
  108. };
  109. THREE.EventDispatcher.prototype.apply( THREE.RaytracingWorkerRenderer.prototype );