Viewport.Pathtracer.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  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. ProceduralEquirectTexture,
  8. } from 'three-gpu-pathtracer';
  9. function buildColorTexture( color ) {
  10. const texture = new ProceduralEquirectTexture( 4, 4 );
  11. texture.generationCallback = ( polar, uv, coord, target ) => {
  12. target.copy( color );
  13. };
  14. texture.update();
  15. return texture;
  16. }
  17. function ViewportPathtracer( renderer ) {
  18. let generator = null;
  19. let pathtracer = null;
  20. let quad = null;
  21. let hdr = null;
  22. function init( scene, camera ) {
  23. if ( pathtracer === null ) {
  24. generator = new PathTracingSceneGenerator();
  25. pathtracer = new PathTracingRenderer( renderer );
  26. pathtracer.setSize( renderer.domElement.offsetWidth, renderer.domElement.offsetHeight );
  27. pathtracer.alpha = true;
  28. pathtracer.camera = camera;
  29. pathtracer.material = new PhysicalPathTracingMaterial();
  30. pathtracer.tiles.set( 3, 4 );
  31. quad = new FullScreenQuad( new THREE.MeshBasicMaterial( {
  32. map: pathtracer.target.texture,
  33. blending: THREE.CustomBlending
  34. } ) );
  35. }
  36. pathtracer.reset();
  37. const { bvh, textures, materials, lights } = generator.generate( scene );
  38. const ptGeometry = bvh.geometry;
  39. const ptMaterial = pathtracer.material;
  40. ptMaterial.bvh.updateFrom( bvh );
  41. ptMaterial.attributesArray.updateFrom(
  42. ptGeometry.attributes.normal,
  43. ptGeometry.attributes.tangent,
  44. ptGeometry.attributes.uv,
  45. ptGeometry.attributes.color,
  46. );
  47. ptMaterial.materialIndexAttribute.updateFrom( ptGeometry.attributes.materialIndex );
  48. ptMaterial.textures.setTextures( renderer, 2048, 2048, textures );
  49. ptMaterial.materials.updateFrom( materials, textures );
  50. ptMaterial.lights.updateFrom( lights );
  51. ptMaterial.filterGlossyFactor = 0.5;
  52. //
  53. setBackground( scene.background, scene.backgroundBlurriness );
  54. setEnvironment( scene.environment );
  55. }
  56. function setSize( width, height ) {
  57. if ( pathtracer === null ) return;
  58. pathtracer.setSize( width, height );
  59. pathtracer.reset();
  60. }
  61. function setBackground( background, blurriness ) {
  62. if ( pathtracer === null ) return;
  63. const ptMaterial = pathtracer.material;
  64. if ( background ) {
  65. if ( background.isTexture ) {
  66. ptMaterial.backgroundMap = background;
  67. ptMaterial.backgroundBlur = blurriness;
  68. } else if ( background.isColor ) {
  69. ptMaterial.backgroundMap = buildColorTexture( background );
  70. ptMaterial.backgroundBlur = 0;
  71. }
  72. } else {
  73. ptMaterial.backgroundMap = buildColorTexture( new THREE.Color( 0 ) );
  74. ptMaterial.backgroundBlur = 0;
  75. }
  76. pathtracer.reset();
  77. }
  78. function setEnvironment( environment ) {
  79. if ( pathtracer === null ) return;
  80. const ptMaterial = pathtracer.material;
  81. if ( environment && environment.isDataTexture === true ) {
  82. // Avoid calling envMapInfo() with the same hdr
  83. if ( environment !== hdr ) {
  84. ptMaterial.envMapInfo.updateFrom( environment );
  85. hdr = environment;
  86. }
  87. } else {
  88. ptMaterial.envMapInfo.updateFrom( buildColorTexture( new THREE.Color( 0 ) ) );
  89. }
  90. pathtracer.reset();
  91. }
  92. function update() {
  93. if ( pathtracer === null ) return;
  94. pathtracer.update();
  95. if ( pathtracer.samples >= 1 ) {
  96. renderer.autoClear = false;
  97. quad.render( renderer );
  98. renderer.autoClear = true;
  99. }
  100. }
  101. function reset() {
  102. if ( pathtracer === null ) return;
  103. pathtracer.reset();
  104. }
  105. return {
  106. init: init,
  107. setSize: setSize,
  108. setBackground: setBackground,
  109. setEnvironment: setEnvironment,
  110. update: update,
  111. reset: reset
  112. };
  113. }
  114. export { ViewportPathtracer };