238 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			238 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 
								 | 
							
								import {
							 | 
						||
| 
								 | 
							
									BoxGeometry,
							 | 
						||
| 
								 | 
							
									BufferAttribute,
							 | 
						||
| 
								 | 
							
									DoubleSide,
							 | 
						||
| 
								 | 
							
									Mesh,
							 | 
						||
| 
								 | 
							
									PlaneGeometry,
							 | 
						||
| 
								 | 
							
									ShaderMaterial,
							 | 
						||
| 
								 | 
							
									Vector3,
							 | 
						||
| 
								 | 
							
								} from 'three';
							 | 
						||
| 
								 | 
							
								import { mergeGeometries } from '../utils/BufferGeometryUtils.js';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class TextureHelper extends Mesh {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									constructor( texture, width = 1, height = 1, depth = 1 ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const material = new ShaderMaterial( {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											type: 'TextureHelperMaterial',
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											side: DoubleSide,
							 | 
						||
| 
								 | 
							
											transparent: true,
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											uniforms: {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												map: { value: texture },
							 | 
						||
| 
								 | 
							
												alpha: { value: getAlpha( texture ) },
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											},
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											vertexShader: [
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												'attribute vec3 uvw;',
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												'varying vec3 vUvw;',
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												'void main() {',
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												'	vUvw = uvw;',
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												'	gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );',
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												'}',
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											].join( '\n' ),
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											fragmentShader: [
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												'precision highp float;',
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												'precision highp sampler2DArray;',
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												'precision highp sampler3D;',
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												'uniform {samplerType} map;',
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												'uniform float alpha;',
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												'varying vec3 vUvw;',
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												'vec4 textureHelper( in sampler2D map ) { return texture( map, vUvw.xy ); }',
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												'vec4 textureHelper( in sampler2DArray map ) { return texture( map, vUvw ); }',
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												'vec4 textureHelper( in sampler3D map ) { return texture( map, vUvw ); }',
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												'vec4 textureHelper( in samplerCube map ) { return texture( map, vUvw ); }',
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												'void main() {',
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												'	gl_FragColor = linearToOutputTexel( vec4( textureHelper( map ).xyz, alpha ) );',
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												'}'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											].join( '\n' ).replace( '{samplerType}', getSamplerType( texture ) )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										} );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const geometry = texture.isCubeTexture
							 | 
						||
| 
								 | 
							
											? createCubeGeometry( width, height, depth )
							 | 
						||
| 
								 | 
							
											: createSliceGeometry( texture, width, height, depth );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										super( geometry, material );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.texture = texture;
							 | 
						||
| 
								 | 
							
										this.type = 'TextureHelper';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									dispose() {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.geometry.dispose();
							 | 
						||
| 
								 | 
							
										this.material.dispose();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function getSamplerType( texture ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if ( texture.isCubeTexture ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return 'samplerCube';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									} else if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return 'sampler2DArray';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									} else if ( texture.isData3DTexture || texture.isCompressed3DTexture ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return 'sampler3D';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									} else {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return 'sampler2D';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function getImageCount( texture ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if ( texture.isCubeTexture ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return 6;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									} else if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return texture.image.depth;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									} else if ( texture.isData3DTexture || texture.isCompressed3DTexture ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return texture.image.depth;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									} else {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function getAlpha( texture ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if ( texture.isCubeTexture ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									} else if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return Math.max( 1 / texture.image.depth, 0.25 );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									} else if ( texture.isData3DTexture || texture.isCompressed3DTexture ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return Math.max( 1 / texture.image.depth, 0.25 );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									} else {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function createCubeGeometry( width, height, depth ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									const geometry = new BoxGeometry( width, height, depth );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									const position = geometry.attributes.position;
							 | 
						||
| 
								 | 
							
									const uv = geometry.attributes.uv;
							 | 
						||
| 
								 | 
							
									const uvw = new BufferAttribute( new Float32Array( uv.count * 3 ), 3 );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									const _direction = new Vector3();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									for ( let j = 0, jl = uv.count; j < jl; ++ j ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										_direction.fromBufferAttribute( position, j ).normalize();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const u = _direction.x;
							 | 
						||
| 
								 | 
							
										const v = _direction.y;
							 | 
						||
| 
								 | 
							
										const w = _direction.z;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										uvw.setXYZ( j, u, v, w );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									geometry.deleteAttribute( 'uv' );
							 | 
						||
| 
								 | 
							
									geometry.setAttribute( 'uvw', uvw );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return geometry;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function createSliceGeometry( texture, width, height, depth ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									const sliceCount = getImageCount( texture );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									const geometries = [];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									for ( let i = 0; i < sliceCount; ++ i ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const geometry = new PlaneGeometry( width, height );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if ( sliceCount > 1 ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											geometry.translate( 0, 0, depth * ( i / ( sliceCount - 1 ) - 0.5 ) );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const uv = geometry.attributes.uv;
							 | 
						||
| 
								 | 
							
										const uvw = new BufferAttribute( new Float32Array( uv.count * 3 ), 3 );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for ( let j = 0, jl = uv.count; j < jl; ++ j ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											const u = uv.getX( j );
							 | 
						||
| 
								 | 
							
											const v = texture.flipY ? uv.getY( j ) : 1 - uv.getY( j );
							 | 
						||
| 
								 | 
							
											const w = sliceCount === 1
							 | 
						||
| 
								 | 
							
												? 1
							 | 
						||
| 
								 | 
							
												: texture.isDataArrayTexture || texture.isCompressedArrayTexture
							 | 
						||
| 
								 | 
							
													? i
							 | 
						||
| 
								 | 
							
													: i / ( sliceCount - 1 );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											uvw.setXYZ( j, u, v, w );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										geometry.deleteAttribute( 'uv' );
							 | 
						||
| 
								 | 
							
										geometry.setAttribute( 'uvw', uvw );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										geometries.push( geometry );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return mergeGeometries( geometries );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export { TextureHelper };
							 |