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