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 };
 |