InstancedVolume.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. import { InstancedMesh, BoxGeometry, Matrix4, Vector3, Quaternion } from 'three';
  2. import { VolumeStandardMaterial } from './VolumeStandardMaterial.js';
  3. import { VolumeGenerator } from './VolumeGenerator.js';
  4. export class InstancedVolume extends InstancedMesh {
  5. constructor( count, params = {} ) {
  6. const geometry = new BoxGeometry( 1, 1, 1 );
  7. const material = new VolumeStandardMaterial( {
  8. roughness: params.roughness !== undefined ? params.roughness : 1.0,
  9. metalness: params.metalness !== undefined ? params.metalness : 1.0
  10. } );
  11. super( geometry, material, count );
  12. this.resolution = params.resolution !== undefined ? params.resolution : 100;
  13. this.margin = params.margin !== undefined ? params.margin : 0.05;
  14. this.surface = params.surface !== undefined ? params.surface : 0.0;
  15. this.sdfTexture = null;
  16. this.inverseBoundsMatrix = new Matrix4();
  17. }
  18. async generate( sourceMesh ) {
  19. // Dispose of the existing SDF texture
  20. if ( this.sdfTexture ) {
  21. this.sdfTexture.dispose();
  22. }
  23. // Generate the SDF using the shared generator
  24. const result = await VolumeGenerator.generateSDF( sourceMesh, this.resolution, this.margin );
  25. this.sdfTexture = result.sdfTexture;
  26. this.inverseBoundsMatrix = result.inverseBoundsMatrix;
  27. // Copy textures from source mesh material if available
  28. if ( sourceMesh.material ) {
  29. const mat = sourceMesh.material;
  30. if ( mat.map ) this.material.map = mat.map;
  31. if ( mat.normalMap ) this.material.normalMap = mat.normalMap;
  32. if ( mat.metalnessMap ) this.material.metalnessMap = mat.metalnessMap;
  33. if ( mat.roughnessMap ) this.material.roughnessMap = mat.roughnessMap;
  34. if ( mat.aoMap ) this.material.aoMap = mat.aoMap;
  35. if ( mat.envMap ) this.material.envMap = mat.envMap;
  36. this.material.needsUpdate = true;
  37. }
  38. // Set the mesh's scale to match SDF bounds
  39. const sdfBoundsMatrix = this.inverseBoundsMatrix.clone().invert();
  40. const boundsCenter = new Vector3();
  41. const boundsQuat = new Quaternion();
  42. const boundsScale = new Vector3();
  43. sdfBoundsMatrix.decompose( boundsCenter, boundsQuat, boundsScale );
  44. // For instanced mesh, we set the base scale
  45. // Individual instances can be positioned using setMatrixAt
  46. this.scale.copy( boundsScale );
  47. this.position.copy( boundsCenter );
  48. this.updateMatrix();
  49. }
  50. onBeforeRender( renderer, scene, camera ) {
  51. if ( ! this.sdfTexture ) return;
  52. // Update matrices
  53. camera.updateMatrixWorld();
  54. this.updateMatrixWorld();
  55. const depth = 1 / this.resolution;
  56. // Update custom uniforms
  57. this.material.uniforms.sdfTex.value = this.sdfTexture;
  58. this.material.uniforms.normalStep.value.set( depth, depth, depth );
  59. this.material.uniforms.surface.value = this.surface;
  60. // Automatically use scene.environment if available
  61. if ( scene.environment && ! this.material.envMap ) {
  62. this.material.envMap = scene.environment;
  63. this.material.needsUpdate = true;
  64. }
  65. }
  66. dispose() {
  67. if ( this.sdfTexture ) {
  68. this.sdfTexture.dispose();
  69. this.sdfTexture = null;
  70. }
  71. this.geometry.dispose();
  72. this.material.dispose();
  73. }
  74. }
粤ICP备19079148号