WebGPUGeometries.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. import { Uint32BufferAttribute, Uint16BufferAttribute } from 'three';
  2. function arrayNeedsUint32( array ) {
  3. // assumes larger values usually on last
  4. for ( let i = array.length - 1; i >= 0; -- i ) {
  5. if ( array[ i ] >= 65535 ) return true; // account for PRIMITIVE_RESTART_FIXED_INDEX, #24565
  6. }
  7. return false;
  8. }
  9. function getWireframeVersion( geometry ) {
  10. return ( geometry.index !== null ) ? geometry.index.version : geometry.attributes.position.version;
  11. }
  12. function getWireframeIndex( geometry ) {
  13. const indices = [];
  14. const geometryIndex = geometry.index;
  15. const geometryPosition = geometry.attributes.position;
  16. if ( geometryIndex !== null ) {
  17. const array = geometryIndex.array;
  18. for ( let i = 0, l = array.length; i < l; i += 3 ) {
  19. const a = array[ i + 0 ];
  20. const b = array[ i + 1 ];
  21. const c = array[ i + 2 ];
  22. indices.push( a, b, b, c, c, a );
  23. }
  24. } else {
  25. const array = geometryPosition.array;
  26. for ( let i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) {
  27. const a = i + 0;
  28. const b = i + 1;
  29. const c = i + 2;
  30. indices.push( a, b, b, c, c, a );
  31. }
  32. }
  33. const attribute = new ( arrayNeedsUint32( indices ) ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 );
  34. attribute.version = getWireframeVersion( geometry );
  35. return attribute;
  36. }
  37. class WebGPUGeometries {
  38. constructor( attributes, properties, info ) {
  39. this.attributes = attributes;
  40. this.properties = properties;
  41. this.info = info;
  42. this.wireframes = new WeakMap();
  43. this.geometryFrame = new WeakMap();
  44. }
  45. has( renderObject ) {
  46. const geometry = renderObject.geometry;
  47. return this.properties.has( geometry ) && this.properties.get( geometry ).initialized === true;
  48. }
  49. update( renderObject ) {
  50. if ( this.has( renderObject ) === false ) this.initGeometry( renderObject );
  51. this.updateFrameAttributes( renderObject );
  52. }
  53. initGeometry( renderObject ) {
  54. const geometry = renderObject.geometry;
  55. const geometryProperties = this.properties.get( geometry );
  56. geometryProperties.initialized = true;
  57. const dispose = () => {
  58. this.info.memory.geometries --;
  59. const index = geometry.index;
  60. const geometryAttributes = geometry.attributes;
  61. if ( index !== null ) {
  62. this.attributes.remove( index );
  63. }
  64. for ( const name in geometryAttributes ) {
  65. this.attributes.remove( geometryAttributes[ name ] );
  66. }
  67. const wireframeAttribute = this.wireframes.get( geometry );
  68. if ( wireframeAttribute !== undefined ) {
  69. this.attributes.remove( wireframeAttribute );
  70. }
  71. geometry.removeEventListener( 'dispose', dispose );
  72. };
  73. this.info.memory.geometries ++;
  74. geometry.addEventListener( 'dispose', dispose );
  75. }
  76. updateFrameAttributes( renderObject ) {
  77. const frame = this.info.render.frame;
  78. const geometry = renderObject.geometry;
  79. if ( this.geometryFrame.get( geometry ) !== frame ) {
  80. this.updateAttributes( renderObject );
  81. this.geometryFrame.set( geometry, frame );
  82. }
  83. }
  84. updateAttributes( renderObject ) {
  85. const geometry = renderObject.geometry;
  86. const geometryAttributes = geometry.attributes;
  87. for ( const name in geometryAttributes ) {
  88. this.attributes.update( geometryAttributes[ name ] );
  89. }
  90. const index = this.getIndex( renderObject );
  91. if ( index !== null ) {
  92. this.attributes.update( index, true );
  93. }
  94. }
  95. getIndex( renderObject ) {
  96. const { geometry, material } = renderObject;
  97. let index = geometry.index;
  98. if ( material.wireframe === true ) {
  99. const wireframes = this.wireframes;
  100. let wireframeAttribute = wireframes.get( geometry );
  101. if ( wireframeAttribute === undefined ) {
  102. wireframeAttribute = getWireframeIndex( geometry );
  103. wireframes.set( geometry, wireframeAttribute );
  104. } else if ( wireframeAttribute.version !== getWireframeVersion( geometry ) ) {
  105. this.attributes.remove( wireframeAttribute );
  106. wireframeAttribute = getWireframeIndex( geometry );
  107. wireframes.set( geometry, wireframeAttribute );
  108. }
  109. index = wireframeAttribute;
  110. }
  111. return index;
  112. }
  113. }
  114. export default WebGPUGeometries;