A Texture is an image plus sampling and upload settings. Like every scene object it is plain data; the renderer uploads it to the GPU the first time it is used as a uniform.
image can be an HTMLImageElement, HTMLVideoElement,
HTMLCanvasElement, ImageData or ImageBitmap. Texture.fromImageUrl(url)
loads an image with crossOrigin = 'anonymous' (so images from other origins
work when the server allows it) and resolves with a texture once decoded.
Texture.fromBlob(blob) decodes a Blob with createImageBitmap instead -
the way to go from raw bytes (an embedded image in a binary file format, a
fetch response) to an uploadable image without ever creating a DOM
element.
For a video or a canvas that changes, set texture.needsUpdate = true after
the change; the renderer re-uploads the current frame on the next draw and
clears the flag. Nothing is re-uploaded otherwise, so a static image costs one
upload.
magFilter says what to do when a texel covers more than one pixel
(zoomed in): 'nearest' picks the closest texel and looks blocky, which is
what pixel art wants; 'linear' blends the four nearest and looks smooth.
minFilter says what to do when many texels fall into one pixel (zoomed
out). Picking one texel here makes the texture shimmer as it moves, because
which texel wins changes every frame. The fix is mipmaps: a chain of
pre-shrunk copies, each half the size of the previous, and a filter that
samples from the copy whose texels match the pixel size. The four
'...-mipmap-...' values of Filter choose how to pick between
levels and within a level; 'linear-mipmap-linear' (trilinear) is the
smooth default in most engines. The renderer calls generateMipmap after
uploading when the minification filter uses mipmaps.
The default in magic-pixels is 'nearest' for both, the cheapest and
sharpest option; pass minFilter and magFilter in the options to change
it.
wrapS and wrapT say what happens for texture coordinates outside 0..1
along U and V: 'clamp-to-edge' (the default) stretches the border pixel,
'repeat' tiles the image, 'mirrored-repeat' tiles with every other copy
flipped. Repeat modes let a small tile cover a large floor with UVs from 0
to 10.
colorSpace tells the GPU what the bytes in the image mean: 'linear'
(the default) uploads them unchanged, 'srgb' uploads with an sRGB internal
format so the GPU converts sRGB-encoded values to linear ones when a shader
samples the texture. Anything meant to be looked at as a picture (a photo, a
hand-painted color texture) is sRGB; anything that is really just numbers
stored as an image (a normal map, a roughness map) is linear. See
linear and sRGB color for why
this matters and texture extensions for how
the renderer applies it.
WebGL uploads the image's first row of pixels at texture coordinate
v = 0, and by convention v = 0 is the bottom of the texture. Image
files store their first row at the top. flipY (default false) tells
the renderer to flip the image vertically during upload so v = 0 lines up
with the top of the picture; the default keeps the old behaviour, where a
texture appears upside down unless the shader flips the V coordinate itself
(1.0 - vUv.y) or the UVs are authored the other way round.
The first time a texture is bound the renderer creates a GL texture,
uploads the image as 8-bit RGBA (or sRGB-encoded RGBA, see above), sets the
four sampling parameters and the flip flag, and, if needed, generates
mipmaps. The GL texture is cached in a map keyed by the Texture
object; the same texture in ten materials is uploaded once.
renderer.dispose(texture) frees it, and it is re-created if still used.
Textures are bound to units per draw in the order they appear in the material's uniforms, starting from 0, so a shader with three samplers uses units 0 to 2. WebGL2 guarantees at least 16 units in the fragment shader.
crossOrigin = 'anonymous' is needed and what the server has to send.