TextureHelper.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. import {
  2. BoxGeometry,
  3. BufferAttribute,
  4. DoubleSide,
  5. Mesh,
  6. PlaneGeometry,
  7. ShaderMaterial,
  8. Vector3,
  9. } from 'three';
  10. import { mergeGeometries } from '../utils/BufferGeometryUtils.js';
  11. class TextureHelper extends Mesh {
  12. constructor( texture, width = 1, height = 1, depth = 1 ) {
  13. const material = new ShaderMaterial( {
  14. type: 'TextureHelperMaterial',
  15. side: DoubleSide,
  16. transparent: true,
  17. uniforms: {
  18. map: { value: texture },
  19. alpha: { value: getAlpha( texture ) },
  20. },
  21. vertexShader: [
  22. 'attribute vec3 uvw;',
  23. 'varying vec3 vUvw;',
  24. 'void main() {',
  25. ' vUvw = uvw;',
  26. ' gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );',
  27. '}',
  28. ].join( '\n' ),
  29. fragmentShader: [
  30. 'precision highp float;',
  31. 'precision highp sampler2DArray;',
  32. 'precision highp sampler3D;',
  33. 'uniform {samplerType} map;',
  34. 'uniform float alpha;',
  35. 'varying vec3 vUvw;',
  36. 'vec4 textureHelper( in sampler2D map ) { return texture( map, vUvw.xy ); }',
  37. 'vec4 textureHelper( in sampler2DArray map ) { return texture( map, vUvw ); }',
  38. 'vec4 textureHelper( in sampler3D map ) { return texture( map, vUvw ); }',
  39. 'vec4 textureHelper( in samplerCube map ) { return texture( map, vUvw ); }',
  40. 'void main() {',
  41. ' gl_FragColor = linearToOutputTexel( vec4( textureHelper( map ).xyz, alpha ) );',
  42. '}'
  43. ].join( '\n' ).replace( '{samplerType}', getSamplerType( texture ) )
  44. } );
  45. const geometry = texture.isCubeTexture
  46. ? createCubeGeometry( width, height, depth )
  47. : createSliceGeometry( texture, width, height, depth );
  48. super( geometry, material );
  49. this.texture = texture;
  50. this.type = 'TextureHelper';
  51. }
  52. dispose() {
  53. this.geometry.dispose();
  54. this.material.dispose();
  55. }
  56. }
  57. function getSamplerType( texture ) {
  58. if ( texture.isCubeTexture ) {
  59. return 'samplerCube';
  60. } else if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) {
  61. return 'sampler2DArray';
  62. } else if ( texture.isData3DTexture || texture.isCompressed3DTexture ) {
  63. return 'sampler3D';
  64. } else {
  65. return 'sampler2D';
  66. }
  67. }
  68. function getImageCount( texture ) {
  69. if ( texture.isCubeTexture ) {
  70. return 6;
  71. } else if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) {
  72. return texture.image.depth;
  73. } else if ( texture.isData3DTexture || texture.isCompressed3DTexture ) {
  74. return texture.image.depth;
  75. } else {
  76. return 1;
  77. }
  78. }
  79. function getAlpha( texture ) {
  80. if ( texture.isCubeTexture ) {
  81. return 1;
  82. } else if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) {
  83. return Math.max( 1 / texture.image.depth, 0.25 );
  84. } else if ( texture.isData3DTexture || texture.isCompressed3DTexture ) {
  85. return Math.max( 1 / texture.image.depth, 0.25 );
  86. } else {
  87. return 1;
  88. }
  89. }
  90. function createCubeGeometry( width, height, depth ) {
  91. const geometry = new BoxGeometry( width, height, depth );
  92. const position = geometry.attributes.position;
  93. const uv = geometry.attributes.uv;
  94. const uvw = new BufferAttribute( new Float32Array( uv.count * 3 ), 3 );
  95. const _direction = new Vector3();
  96. for ( let j = 0, jl = uv.count; j < jl; ++ j ) {
  97. _direction.fromBufferAttribute( position, j ).normalize();
  98. const u = _direction.x;
  99. const v = _direction.y;
  100. const w = _direction.z;
  101. uvw.setXYZ( j, u, v, w );
  102. }
  103. geometry.deleteAttribute( 'uv' );
  104. geometry.setAttribute( 'uvw', uvw );
  105. return geometry;
  106. }
  107. function createSliceGeometry( texture, width, height, depth ) {
  108. const sliceCount = getImageCount( texture );
  109. const geometries = [];
  110. for ( let i = 0; i < sliceCount; ++ i ) {
  111. const geometry = new PlaneGeometry( width, height );
  112. if ( sliceCount > 1 ) {
  113. geometry.translate( 0, 0, depth * ( i / ( sliceCount - 1 ) - 0.5 ) );
  114. }
  115. const uv = geometry.attributes.uv;
  116. const uvw = new BufferAttribute( new Float32Array( uv.count * 3 ), 3 );
  117. for ( let j = 0, jl = uv.count; j < jl; ++ j ) {
  118. const u = uv.getX( j );
  119. const v = texture.flipY ? uv.getY( j ) : 1 - uv.getY( j );
  120. const w = sliceCount === 1
  121. ? 1
  122. : texture.isDataArrayTexture || texture.isCompressedArrayTexture
  123. ? i
  124. : i / ( sliceCount - 1 );
  125. uvw.setXYZ( j, u, v, w );
  126. }
  127. geometry.deleteAttribute( 'uv' );
  128. geometry.setAttribute( 'uvw', uvw );
  129. geometries.push( geometry );
  130. }
  131. return mergeGeometries( geometries );
  132. }
  133. export { TextureHelper };