Viewport.Pathtracer.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. import * as THREE from 'three';
  2. import { FullScreenQuad } from 'three/examples/jsm/postprocessing/Pass.js';
  3. import {
  4. PathTracingSceneGenerator,
  5. PathTracingRenderer,
  6. PhysicalPathTracingMaterial
  7. } from 'three-gpu-pathtracer';
  8. function buildColorTexture( color ) {
  9. const data = new Uint8Array( [ color.r * 255, color.g * 255, color.b * 255, 255 ] );
  10. const texture = new THREE.DataTexture( data, 1, 1, THREE.RGBAFormat );
  11. texture.needsUpdate = true;
  12. return texture;
  13. }
  14. function ViewportPathtracer( renderer ) {
  15. let generator = null;
  16. let pathtracer = null;
  17. let quad = null;
  18. let hdr = null;
  19. function init( scene, camera ) {
  20. if ( pathtracer === null ) {
  21. generator = new PathTracingSceneGenerator();
  22. pathtracer = new PathTracingRenderer( renderer );
  23. pathtracer.setSize( renderer.domElement.offsetWidth, renderer.domElement.offsetHeight );
  24. pathtracer.alpha = true;
  25. pathtracer.camera = camera;
  26. pathtracer.material = new PhysicalPathTracingMaterial();
  27. pathtracer.tiles.set( 3, 4 );
  28. quad = new FullScreenQuad( new THREE.MeshBasicMaterial( {
  29. map: pathtracer.target.texture,
  30. blending: THREE.CustomBlending
  31. } ) );
  32. }
  33. pathtracer.material.backgroundBlur = scene.backgroundBlurriness;
  34. pathtracer.reset();
  35. // TOFIX: If the scene is empty the generator crashes so we render a tiny cube (:
  36. if ( scene.children.length === 0 ) {
  37. scene = new THREE.Mesh( new THREE.BoxGeometry( 0.0001, 0.0001, 0.0001 ) );
  38. }
  39. const { bvh, textures, materials, lights } = generator.generate( scene );
  40. const ptGeometry = bvh.geometry;
  41. const ptMaterial = pathtracer.material;
  42. ptMaterial.bvh.updateFrom( bvh );
  43. ptMaterial.attributesArray.updateFrom(
  44. ptGeometry.attributes.normal,
  45. ptGeometry.attributes.tangent,
  46. ptGeometry.attributes.uv,
  47. ptGeometry.attributes.color,
  48. );
  49. ptMaterial.materialIndexAttribute.updateFrom( ptGeometry.attributes.materialIndex );
  50. ptMaterial.textures.setTextures( renderer, 2048, 2048, textures );
  51. ptMaterial.materials.updateFrom( materials, textures );
  52. ptMaterial.lights.updateFrom( lights );
  53. //
  54. const background = scene.background;
  55. if ( background ) {
  56. if ( background.isTexture ) {
  57. ptMaterial.backgroundMap = background;
  58. } else if ( background.isColor ) {
  59. ptMaterial.backgroundMap = buildColorTexture( background );
  60. }
  61. } else {
  62. ptMaterial.backgroundMap = buildColorTexture( new THREE.Color( 0x000000 ) );
  63. }
  64. //
  65. const environment = scene.environment;
  66. if ( environment && environment.isTexture === true ) {
  67. // Avoid calling envMapInfo() with the same hdr
  68. if ( scene.environment !== hdr ) {
  69. ptMaterial.envMapInfo.updateFrom( scene.environment );
  70. hdr = scene.environment;
  71. }
  72. } else {
  73. ptMaterial.envMapInfo.updateFrom( buildColorTexture( new THREE.Color( 0xffffff ) ) );
  74. }
  75. }
  76. function setSize( width, height ) {
  77. if ( pathtracer === null ) return;
  78. pathtracer.setSize( width, height );
  79. pathtracer.reset();
  80. }
  81. function update() {
  82. if ( pathtracer === null ) return;
  83. pathtracer.update();
  84. renderer.autoClear = false;
  85. quad.render( renderer );
  86. renderer.autoClear = true;
  87. }
  88. function reset() {
  89. if ( pathtracer === null ) return;
  90. pathtracer.reset();
  91. }
  92. return {
  93. init: init,
  94. setSize: setSize,
  95. update: update,
  96. reset: reset
  97. };
  98. }
  99. export { ViewportPathtracer };