Browse Source

Add TextureHelper (#27151)

Don McCurdy 1 năm trước cách đây
mục cha
commit
ec09a960a1
2 tập tin đã thay đổi với 238 bổ sung0 xóa
  1. 1 0
      examples/jsm/Addons.js
  2. 237 0
      examples/jsm/helpers/TextureHelper.js

+ 1 - 0
examples/jsm/Addons.js

@@ -60,6 +60,7 @@ export * from './helpers/LightProbeHelper.js';
 export * from './helpers/OctreeHelper.js';
 export * from './helpers/PositionalAudioHelper.js';
 export * from './helpers/RectAreaLightHelper.js';
+export * from './helpers/TextureHelper.js';
 export * from './helpers/VertexNormalsHelper.js';
 export * from './helpers/VertexTangentsHelper.js';
 export * from './helpers/ViewHelper.js';

+ 237 - 0
examples/jsm/helpers/TextureHelper.js

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