| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683 |
- import { EventDispatcher } from '../core/EventDispatcher.js';
- import {
- MirroredRepeatWrapping,
- ClampToEdgeWrapping,
- RepeatWrapping,
- UnsignedByteType,
- RGBAFormat,
- LinearMipmapLinearFilter,
- LinearFilter,
- UVMapping,
- NoColorSpace,
- } from '../constants.js';
- import { generateUUID } from '../math/MathUtils.js';
- import { Vector2 } from '../math/Vector2.js';
- import { Matrix3 } from '../math/Matrix3.js';
- import { Source } from './Source.js';
- let _textureId = 0;
- /**
- * Base class for all textures.
- *
- * Note: After the initial use of a texture, its dimensions, format, and type
- * cannot be changed. Instead, call {@link Texture#dispose} on the texture and instantiate a new one.
- *
- * @augments EventDispatcher
- */
- class Texture extends EventDispatcher {
- /**
- * Constructs a new texture.
- *
- * @param {Object} [image=Texture.DEFAULT_IMAGE] - The image holding the texture data.
- * @param {number} [mapping=Texture.DEFAULT_MAPPING] - The texture mapping.
- * @param {number} [wrapS=ClampToEdgeWrapping] - The wrapS value.
- * @param {number} [wrapT=ClampToEdgeWrapping] - The wrapT value.
- * @param {number} [magFilter=LinearFilter] - The mag filter value.
- * @param {number} [minFilter=LinearFilter] - The min filter value.
- * @param {number} [format=RGABFormat] - The min filter value.
- * @param {number} [type=UnsignedByteType] - The min filter value.
- * @param {number} [anisotropy=Texture.DEFAULT_ANISOTROPY] - The min filter value.
- * @param {string} [colorSpace=NoColorSpace] - The min filter value.
- */
- constructor( image = Texture.DEFAULT_IMAGE, mapping = Texture.DEFAULT_MAPPING, wrapS = ClampToEdgeWrapping, wrapT = ClampToEdgeWrapping, magFilter = LinearFilter, minFilter = LinearMipmapLinearFilter, format = RGBAFormat, type = UnsignedByteType, anisotropy = Texture.DEFAULT_ANISOTROPY, colorSpace = NoColorSpace ) {
- super();
- /**
- * This flag can be used for type testing.
- *
- * @type {boolean}
- * @readonly
- * @default true
- */
- this.isTexture = true;
- /**
- * The ID of the texture.
- *
- * @name Texture#id
- * @type {number}
- * @readonly
- */
- Object.defineProperty( this, 'id', { value: _textureId ++ } );
- /**
- * The UUID of the material.
- *
- * @type {string}
- * @readonly
- */
- this.uuid = generateUUID();
- /**
- * The name of the material.
- *
- * @type {string}
- */
- this.name = '';
- /**
- * The data definition of a texture. A reference to the data source can be
- * shared across textures. This is often useful in context of spritesheets
- * where multiple textures render the same data but with different texture
- * transformations.
- *
- * @type {Source}
- */
- this.source = new Source( image );
- /**
- * An array holding user-defined mipmaps.
- *
- * @type {Array<Object>}
- */
- this.mipmaps = [];
- /**
- * How the texture is applied to the object. The value `UVMapping`
- * is the default, where texture or uv coordinates are used to apply the map.
- *
- * @type {(UVMapping|CubeReflectionMapping|CubeRefractionMapping|EquirectangularReflectionMapping|EquirectangularRefractionMapping|CubeUVReflectionMapping)}
- * @default UVMapping
- */
- this.mapping = mapping;
- /**
- * Lets you select the uv attribute to map the texture to. `0` for `uv`,
- * `1` for `uv1`, `2` for `uv2` and `3` for `uv3`.
- *
- * @type {number}
- * @default 0
- */
- this.channel = 0;
- /**
- * This defines how the texture is wrapped horizontally and corresponds to
- * *U* in UV mapping.
- *
- * @type {(RepeatWrapping|ClampToEdgeWrapping|MirroredRepeatWrapping)}
- * @default ClampToEdgeWrapping
- */
- this.wrapS = wrapS;
- /**
- * This defines how the texture is wrapped horizontally and corresponds to
- * *V* in UV mapping.
- *
- * @type {(RepeatWrapping|ClampToEdgeWrapping|MirroredRepeatWrapping)}
- * @default ClampToEdgeWrapping
- */
- this.wrapT = wrapT;
- /**
- * How the texture is sampled when a texel covers more than one pixel.
- *
- * @type {(NearestFilter|NearestMipmapNearestFilter|NearestMipmapLinearFilter|LinearFilter|LinearMipmapNearestFilter|LinearMipmapLinearFilter)}
- * @default LinearFilter
- */
- this.magFilter = magFilter;
- /**
- * How the texture is sampled when a texel covers less than one pixel.
- *
- * @type {(NearestFilter|NearestMipmapNearestFilter|NearestMipmapLinearFilter|LinearFilter|LinearMipmapNearestFilter|LinearMipmapLinearFilter)}
- * @default LinearMipmapLinearFilter
- */
- this.minFilter = minFilter;
- /**
- * The number of samples taken along the axis through the pixel that has the
- * highest density of texels. By default, this value is `1`. A higher value
- * gives a less blurry result than a basic mipmap, at the cost of more
- * texture samples being used.
- *
- * @type {number}
- * @default 0
- */
- this.anisotropy = anisotropy;
- /**
- * The format of the texture.
- *
- * @type {number}
- * @default RGBAFormat
- */
- this.format = format;
- /**
- * The default internal format is derived from {@link Texture#format} and {@link Texture#type} and
- * defines how the texture data is going to be stored on the GPU.
- *
- * This property allows to overwrite the default format.
- *
- * @type {?string}
- * @default null
- */
- this.internalFormat = null;
- /**
- * The data type of the texture.
- *
- * @type {number}
- * @default UnsignedByteType
- */
- this.type = type;
- /**
- * How much a single repetition of the texture is offset from the beginning,
- * in each direction U and V. Typical range is `0.0` to `1.0`.
- *
- * @type {Vector2}
- * @default (0,0)
- */
- this.offset = new Vector2( 0, 0 );
- /**
- * How many times the texture is repeated across the surface, in each
- * direction U and V. If repeat is set greater than `1` in either direction,
- * the corresponding wrap parameter should also be set to `RepeatWrapping`
- * or `MirroredRepeatWrapping` to achieve the desired tiling effect.
- *
- * @type {Vector2}
- * @default (1,1)
- */
- this.repeat = new Vector2( 1, 1 );
- /**
- * The point around which rotation occurs. A value of `(0.5, 0.5)` corresponds
- * to the center of the texture. Default is `(0, 0)`, the lower left.
- *
- * @type {Vector2}
- * @default (0,0)
- */
- this.center = new Vector2( 0, 0 );
- /**
- * How much the texture is rotated around the center point, in radians.
- * Positive values are counter-clockwise.
- *
- * @type {number}
- * @default 0
- */
- this.rotation = 0;
- /**
- * Whether to update the texture's uv-transformation {@link Texture#matrix}
- * from the properties {@link Texture#offset}, {@link Texture#repeat},
- * {@link Texture#rotation}, and {@link Texture#center}.
- *
- * Set this to `false` if you are specifying the uv-transform matrix directly.
- *
- * @type {boolean}
- * @default true
- */
- this.matrixAutoUpdate = true;
- /**
- * The uv-transformation matrix of the texture.
- *
- * @type {Matrix3}
- */
- this.matrix = new Matrix3();
- /**
- * Whether to generate mipmaps (if possible) for a texture.
- *
- * Set this to `false` if you are creating mipmaps manually.
- *
- * @type {boolean}
- * @default true
- */
- this.generateMipmaps = true;
- /**
- * If set to `true`, the alpha channel, if present, is multiplied into the
- * color channels when the texture is uploaded to the GPU.
- *
- * Note that this property has no effect when using `ImageBitmap`. You need to
- * configure premultiply alpha on bitmap creation instead.
- *
- * @type {boolean}
- * @default false
- */
- this.premultiplyAlpha = false;
- /**
- * If set to `true`, the texture is flipped along the vertical axis when
- * uploaded to the GPU.
- *
- * Note that this property has no effect when using `ImageBitmap`. You need to
- * configure the flip on bitmap creation instead.
- *
- * @type {boolean}
- * @default true
- */
- this.flipY = true;
- /**
- * Specifies the alignment requirements for the start of each pixel row in memory.
- * The allowable values are `1` (byte-alignment), `2` (rows aligned to even-numbered bytes),
- * `4` (word-alignment), and `8` (rows start on double-word boundaries).
- *
- * @type {number}
- * @default 4
- */
- this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml)
- /**
- * Textures containing color data should be annotated with `SRGBColorSpace` or `LinearSRGBColorSpace`.
- *
- * @type {string}
- * @default NoColorSpace
- */
- this.colorSpace = colorSpace;
- /**
- * An object that can be used to store custom data about the texture. It
- * should not hold references to functions as these will not be cloned.
- *
- * @type {Object}
- */
- this.userData = {};
- /**
- * This starts at `0` and counts how many times {@link Texture#needsUpdate} is set to `true`.
- *
- * @type {number}
- * @readonly
- * @default 0
- */
- this.version = 0;
- /**
- * A callback function, called when the texture is updated (e.g., when
- * {@link Texture#needsUpdate} has been set to true and then the texture is used).
- *
- * @type {?Function}
- * @default null
- */
- this.onUpdate = null;
- /**
- * An optional back reference to the textures render target.
- *
- * @type {?(RenderTarget|WebGLRenderTarget)}
- * @default null
- */
- this.renderTarget = null;
- /**
- * Indicates whether a texture belongs to a render target or not.
- *
- * @type {boolean}
- * @readonly
- * @default false
- */
- this.isRenderTargetTexture = false;
- /**
- * Indicates whether this texture should be processed by `PMREMGenerator` or not
- * (only relevant for render target textures).
- *
- * @type {number}
- * @readonly
- * @default 0
- */
- this.pmremVersion = 0;
- }
- /**
- * The image object holding the texture data.
- *
- * @type {Object}
- */
- get image() {
- return this.source.data;
- }
- set image( value = null ) {
- this.source.data = value;
- }
- /**
- * Updates the texture transformation matrix from the from the properties {@link Texture#offset},
- * {@link Texture#repeat}, {@link Texture#rotation}, and {@link Texture#center}.
- */
- updateMatrix() {
- this.matrix.setUvTransform( this.offset.x, this.offset.y, this.repeat.x, this.repeat.y, this.rotation, this.center.x, this.center.y );
- }
- /**
- * Returns a new texture with copied values from this instance.
- *
- * @return {Texture} A clone of this instance.
- */
- clone() {
- return new this.constructor().copy( this );
- }
- /**
- * Copies the values of the given texture to this instance.
- *
- * @param {Texture} source - The texture to copy.
- * @return {Texture} A reference to this instance.
- */
- copy( source ) {
- this.name = source.name;
- this.source = source.source;
- this.mipmaps = source.mipmaps.slice( 0 );
- this.mapping = source.mapping;
- this.channel = source.channel;
- this.wrapS = source.wrapS;
- this.wrapT = source.wrapT;
- this.magFilter = source.magFilter;
- this.minFilter = source.minFilter;
- this.anisotropy = source.anisotropy;
- this.format = source.format;
- this.internalFormat = source.internalFormat;
- this.type = source.type;
- this.offset.copy( source.offset );
- this.repeat.copy( source.repeat );
- this.center.copy( source.center );
- this.rotation = source.rotation;
- this.matrixAutoUpdate = source.matrixAutoUpdate;
- this.matrix.copy( source.matrix );
- this.generateMipmaps = source.generateMipmaps;
- this.premultiplyAlpha = source.premultiplyAlpha;
- this.flipY = source.flipY;
- this.unpackAlignment = source.unpackAlignment;
- this.colorSpace = source.colorSpace;
- this.renderTarget = source.renderTarget;
- this.isRenderTargetTexture = source.isRenderTargetTexture;
- this.userData = JSON.parse( JSON.stringify( source.userData ) );
- this.needsUpdate = true;
- return this;
- }
- /**
- * Serializes the texture into JSON.
- *
- * @param {?(Object|string)} meta - An optional value holding meta information about the serialization.
- * @return {Object} A JSON object representing the serialized texture.
- * @see {@link ObjectLoader#parse}
- */
- toJSON( meta ) {
- const isRootObject = ( meta === undefined || typeof meta === 'string' );
- if ( ! isRootObject && meta.textures[ this.uuid ] !== undefined ) {
- return meta.textures[ this.uuid ];
- }
- const output = {
- metadata: {
- version: 4.6,
- type: 'Texture',
- generator: 'Texture.toJSON'
- },
- uuid: this.uuid,
- name: this.name,
- image: this.source.toJSON( meta ).uuid,
- mapping: this.mapping,
- channel: this.channel,
- repeat: [ this.repeat.x, this.repeat.y ],
- offset: [ this.offset.x, this.offset.y ],
- center: [ this.center.x, this.center.y ],
- rotation: this.rotation,
- wrap: [ this.wrapS, this.wrapT ],
- format: this.format,
- internalFormat: this.internalFormat,
- type: this.type,
- colorSpace: this.colorSpace,
- minFilter: this.minFilter,
- magFilter: this.magFilter,
- anisotropy: this.anisotropy,
- flipY: this.flipY,
- generateMipmaps: this.generateMipmaps,
- premultiplyAlpha: this.premultiplyAlpha,
- unpackAlignment: this.unpackAlignment
- };
- if ( Object.keys( this.userData ).length > 0 ) output.userData = this.userData;
- if ( ! isRootObject ) {
- meta.textures[ this.uuid ] = output;
- }
- return output;
- }
- /**
- * Frees the GPU-related resources allocated by this instance. Call this
- * method whenever this instance is no longer used in your app.
- *
- * @fires Texture#dispose
- */
- dispose() {
- /**
- * Fires when the texture has been disposed of.
- *
- * @event Texture#dispose
- * @type {Object}
- */
- this.dispatchEvent( { type: 'dispose' } );
- }
- /**
- * Transforms the given uv vector with the textures uv transformation matrix.
- *
- * @param {Vector2} uv - The uv vector.
- * @return {Vector2} The transformed uv vector.
- */
- transformUv( uv ) {
- if ( this.mapping !== UVMapping ) return uv;
- uv.applyMatrix3( this.matrix );
- if ( uv.x < 0 || uv.x > 1 ) {
- switch ( this.wrapS ) {
- case RepeatWrapping:
- uv.x = uv.x - Math.floor( uv.x );
- break;
- case ClampToEdgeWrapping:
- uv.x = uv.x < 0 ? 0 : 1;
- break;
- case MirroredRepeatWrapping:
- if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) {
- uv.x = Math.ceil( uv.x ) - uv.x;
- } else {
- uv.x = uv.x - Math.floor( uv.x );
- }
- break;
- }
- }
- if ( uv.y < 0 || uv.y > 1 ) {
- switch ( this.wrapT ) {
- case RepeatWrapping:
- uv.y = uv.y - Math.floor( uv.y );
- break;
- case ClampToEdgeWrapping:
- uv.y = uv.y < 0 ? 0 : 1;
- break;
- case MirroredRepeatWrapping:
- if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) {
- uv.y = Math.ceil( uv.y ) - uv.y;
- } else {
- uv.y = uv.y - Math.floor( uv.y );
- }
- break;
- }
- }
- if ( this.flipY ) {
- uv.y = 1 - uv.y;
- }
- return uv;
- }
- /**
- * Setting this property to `true` indicates the engine the texture
- * must be updated in the next render. This triggers a texture upload
- * to the GPU and ensures correct texture parameter configuration.
- *
- * @type {boolean}
- * @default false
- * @param {boolean} value
- */
- set needsUpdate( value ) {
- if ( value === true ) {
- this.version ++;
- this.source.needsUpdate = true;
- }
- }
- /**
- * Setting this property to `true` indicates the engine the PMREM
- * must be regenerated.
- *
- * @type {boolean}
- * @default false
- * @param {boolean} value
- */
- set needsPMREMUpdate( value ) {
- if ( value === true ) {
- this.pmremVersion ++;
- }
- }
- }
- /**
- * The default image for all textures.
- *
- * @static
- * @type {?Image}
- * @default null
- */
- Texture.DEFAULT_IMAGE = null;
- /**
- * The default mapping for all textures.
- *
- * @static
- * @type {number}
- * @default UVMapping
- */
- Texture.DEFAULT_MAPPING = UVMapping;
- /**
- * The default anisotropy value for all textures.
- *
- * @static
- * @type {number}
- * @default 1
- */
- Texture.DEFAULT_ANISOTROPY = 1;
- export { Texture };
|