Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add TextureHelper #27151

Merged
merged 1 commit into from
Nov 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/jsm/Addons.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
237 changes: 237 additions & 0 deletions examples/jsm/helpers/TextureHelper.js
Original file line number Diff line number Diff line change
@@ -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 };