|
@@ -0,0 +1,237 @@
|
|
|
|
+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 };
|