# Threejs Textures > Texturas en Three.js: tipos de textura, mapeo UV, mapas de entorno y ajustes. Úsalo al trabajar con imágenes, coordenadas UV, cubemaps, entornos HDR u optimización de texturas. Fuente: https://skillsagentes.com/skills/calesthio/openmontage/threejs-textures Markdown: https://skillsagentes.com/skills/calesthio/openmontage/threejs-textures.md Repositorio: https://github.com/calesthio/OpenMontage Autor: calesthio Licencia: AGPL-3.0 Actualizado: hace 4 meses Coste de contexto: 45 tok instalada, 3.4k tok al activarse, 3.4k tok con todos los archivos del bundle Bundle: 1 archivo, 13 KB Permisos que pide: ninguno declarado ## Instalación Un skill son archivos markdown: los mismos archivos valen para cualquier agente y lo único que cambia es el directorio de destino, es decir la bandera `--agent`. Añade `-g` para instalarlo en todos los proyectos de la máquina. ```bash # Claude Code npx -y skills add calesthio/OpenMontage --skill threejs-textures --agent claude-code # Cursor npx -y skills add calesthio/OpenMontage --skill threejs-textures --agent cursor # Codex npx -y skills add calesthio/OpenMontage --skill threejs-textures --agent codex # Gemini CLI npx -y skills add calesthio/OpenMontage --skill threejs-textures --agent gemini # Windsurf npx -y skills add calesthio/OpenMontage --skill threejs-textures --agent windsurf # Cline npx -y skills add calesthio/OpenMontage --skill threejs-textures --agent cline ``` ## Qué hace - Cubre la carga y configuración de texturas en Three.js, y los distintos tipos de textura - Trata cube textures, texturas HDR, render targets y `CubeCamera` - Explica el mapeo UV y los atlas de textura - Repasa los mapas de textura de material y las texturas procedurales - Documenta la gestión de memoria de texturas y consejos de rendimiento ## Cuándo usarla - Trabajar con imágenes como textura - Manejar coordenadas UV - Usar cubemaps o entornos HDR - Optimizar el uso de texturas ## Qué la activa - "Aplica esta textura al objeto" - "Monta un cubemap de entorno" - "Ajusta las coordenadas UV de esta malla" - "Las texturas ocupan mucha memoria, ¿cómo lo optimizo?" ## Archivos - SKILL.md — 13 KB ## SKILL.md Reproducido tal cual desde calesthio/OpenMontage bajo AGPL-3.0. Esta sección es el documento original y está en inglés. # Three.js Textures ## Quick Start ```javascript import * as THREE from "three"; // Load texture const loader = new THREE.TextureLoader(); const texture = loader.load("texture.jpg"); // Apply to material const material = new THREE.MeshStandardMaterial({ map: texture, }); ``` ## Texture Loading ### Basic Loading ```javascript const loader = new THREE.TextureLoader(); // Async with callbacks loader.load( "texture.jpg", (texture) => console.log("Loaded"), (progress) => console.log("Progress"), (error) => console.error("Error"), ); // Synchronous style (loads async internally) const texture = loader.load("texture.jpg"); material.map = texture; ``` ### Promise Wrapper ```javascript function loadTexture(url) { return new Promise((resolve, reject) => { new THREE.TextureLoader().load(url, resolve, undefined, reject); }); } // Usage const [colorMap, normalMap, roughnessMap] = await Promise.all([ loadTexture("color.jpg"), loadTexture("normal.jpg"), loadTexture("roughness.jpg"), ]); ``` ## Texture Configuration ### Color Space Critical for accurate color reproduction. ```javascript // Color/albedo textures - use sRGB colorTexture.colorSpace = THREE.SRGBColorSpace; // Data textures (normal, roughness, metalness, AO) - leave as default // Do NOT set colorSpace for data textures (NoColorSpace is default) ``` ### Wrapping Modes ```javascript texture.wrapS = THREE.RepeatWrapping; // Horizontal texture.wrapT = THREE.RepeatWrapping; // Vertical // Options: // THREE.ClampToEdgeWrapping - Stretches edge pixels (default) // THREE.RepeatWrapping - Tiles the texture // THREE.MirroredRepeatWrapping - Tiles with mirror flip ``` ### Repeat, Offset, Rotation ```javascript // Tile texture 4x4 texture.repeat.set(4, 4); texture.wrapS = THREE.RepeatWrapping; texture.wrapT = THREE.RepeatWrapping; // Offset (0-1 range) texture.offset.set(0.5, 0.5); // Rotation (radians, around center) texture.rotation = Math.PI / 4; texture.center.set(0.5, 0.5); // Rotation pivot ``` ### Filtering ```javascript // Minification (texture larger than screen pixels) texture.minFilter = THREE.LinearMipmapLinearFilter; // Default, smooth texture.minFilter = THREE.NearestFilter; // Pixelated texture.minFilter = THREE.LinearFilter; // Smooth, no mipmaps // Magnification (texture smaller than screen pixels) texture.magFilter = THREE.LinearFilter; // Smooth (default) texture.magFilter = THREE.NearestFilter; // Pixelated (retro games) // Anisotropic filtering (sharper at angles) texture.anisotropy = renderer.capabilities.getMaxAnisotropy(); ``` ### Generate Mipmaps ```javascript // Usually true by default texture.generateMipmaps = true; // Disable for non-power-of-2 textures or data textures texture.generateMipmaps = false; texture.minFilter = THREE.LinearFilter; ``` ## Texture Types ### Regular Texture ```javascript const texture = new THREE.Texture(image); texture.needsUpdate = true; ``` ### Data Texture Create texture from raw data. ```javascript // Create gradient texture const size = 256; const data = new Uint8Array(size * size * 4); for (let i = 0; i < size; i++) { for (let j = 0; j < size; j++) { const index = (i * size + j) * 4; data[index] = i; // R data[index + 1] = j; // G data[index + 2] = 128; // B data[index + 3] = 255; // A } } const texture = new THREE.DataTexture(data, size, size); texture.needsUpdate = true; ``` ### Canvas Texture ```javascript const canvas = document.createElement("canvas"); canvas.width = 256; canvas.height = 256; const ctx = canvas.getContext("2d"); // Draw on canvas ctx.fillStyle = "red"; ctx.fillRect(0, 0, 256, 256); ctx.fillStyle = "white"; ctx.font = "48px Arial"; ctx.fillText("Hello", 50, 150); const texture = new THREE.CanvasTexture(canvas); // Update when canvas changes texture.needsUpdate = true; ``` ### Video Texture ```javascript const video = document.createElement("video"); video.src = "video.mp4"; video.loop = true; video.muted = true; video.play(); const texture = new THREE.VideoTexture(video); texture.colorSpace = THREE.SRGBColorSpace; // No need to set needsUpdate - auto-updates ``` ### Compressed Textures ```javascript import { KTX2Loader } from "three/examples/jsm/loaders/KTX2Loader.js"; const ktx2Loader = new KTX2Loader(); ktx2Loader.setTranscoderPath("path/to/basis/"); ktx2Loader.detectSupport(renderer); ktx2Loader.load("texture.ktx2", (texture) => { material.map = texture; }); ``` ## Cube Textures For environment maps and skyboxes. ### CubeTextureLoader ```javascript const loader = new THREE.CubeTextureLoader(); const cubeTexture = loader.load([ "px.jpg", "nx.jpg", // +X, -X "py.jpg", "ny.jpg", // +Y, -Y "pz.jpg", "nz.jpg", // +Z, -Z ]); // As background scene.background = cubeTexture; // As environment map scene.environment = cubeTexture; material.envMap = cubeTexture; ``` ### Equirectangular to Cubemap ```javascript import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js"; const pmremGenerator = new THREE.PMREMGenerator(renderer); pmremGenerator.compileEquirectangularShader(); new RGBELoader().load("environment.hdr", (texture) => { const envMap = pmremGenerator.fromEquirectangular(texture).texture; scene.environment = envMap; scene.background = envMap; texture.dispose(); pmremGenerator.dispose(); }); ``` ## HDR Textures ### RGBELoader ```javascript import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js"; const loader = new RGBELoader(); loader.load("environment.hdr", (texture) => { texture.mapping = THREE.EquirectangularReflectionMapping; scene.environment = texture; scene.background = texture; }); ``` ### EXRLoader ```javascript import { EXRLoader } from "three/examples/jsm/loaders/EXRLoader.js"; const loader = new EXRLoader(); loader.load("environment.exr", (texture) => { texture.mapping = THREE.EquirectangularReflectionMapping; scene.environment = texture; }); ``` ### Background Options ```javascript scene.background = texture; scene.backgroundBlurriness = 0.5; // 0-1, blur background scene.backgroundIntensity = 1.0; // Brightness scene.backgroundRotation.y = Math.PI; // Rotate background ``` ## Render Targets Render to texture for effects. ```javascript // Create render target const renderTarget = new THREE.WebGLRenderTarget(512, 512, { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBAFormat, }); // Render scene to target renderer.setRenderTarget(renderTarget); renderer.render(scene, camera); renderer.setRenderTarget(null); // Back to screen // Use as texture material.map = renderTarget.texture; ``` ### Depth Texture ```javascript const renderTarget = new THREE.WebGLRenderTarget(512, 512); renderTarget.depthTexture = new THREE.DepthTexture( 512, 512, THREE.UnsignedShortType, ); // Access depth const depthTexture = renderTarget.depthTexture; ``` ### Multi-Sample Render Target ```javascript const renderTarget = new THREE.WebGLRenderTarget(512, 512, { samples: 4, // MSAA }); ``` ## CubeCamera Dynamic environment maps for reflections. ```javascript const cubeRenderTarget = new THREE.WebGLCubeRenderTarget(256, { generateMipmaps: true, minFilter: THREE.LinearMipmapLinearFilter, }); const cubeCamera = new THREE.CubeCamera(0.1, 1000, cubeRenderTarget); scene.add(cubeCamera); // Apply to reflective material reflectiveMaterial.envMap = cubeRenderTarget.texture; // Update in animation loop (expensive!) function animate() { // Hide reflective object, update env map, show again reflectiveObject.visible = false; cubeCamera.position.copy(reflectiveObject.position); cubeCamera.update(renderer, scene); reflectiveObject.visible = true; } ``` ## UV Mapping ### Accessing UVs ```javascript const uvs = geometry.attributes.uv; // Read UV const u = uvs.getX(vertexIndex); const v = uvs.getY(vertexIndex); // Modify UV uvs.setXY(vertexIndex, newU, newV); uvs.needsUpdate = true; ``` ### Second UV Channel (for AO maps) ```javascript // Required for aoMap geometry.setAttribute("uv2", geometry.attributes.uv); // Or create custom second UV const uv2 = new Float32Array(vertexCount * 2); // ... fill uv2 data geometry.setAttribute("uv2", new THREE.BufferAttribute(uv2, 2)); ``` ### UV Transform in Shader ```javascript const material = new THREE.ShaderMaterial({ uniforms: { map: { value: texture }, uvOffset: { value: new THREE.Vector2(0, 0) }, uvScale: { value: new THREE.Vector2(1, 1) }, }, vertexShader: ` varying vec2 vUv; uniform vec2 uvOffset; uniform vec2 uvScale; void main() { vUv = uv * uvScale + uvOffset; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); } `, fragmentShader: ` varying vec2 vUv; uniform sampler2D map; void main() { gl_FragColor = texture2D(map, vUv); } `, }); ``` ## Texture Atlas Multiple images in one texture. ```javascript // Atlas with 4 sprites (2x2 grid) const atlas = loader.load("atlas.png"); atlas.wrapS = THREE.ClampToEdgeWrapping; atlas.wrapT = THREE.ClampToEdgeWrapping; // Select sprite by UV offset/scale function selectSprite(row, col, gridSize = 2) { atlas.offset.set(col / gridSize, 1 - (row + 1) / gridSize); atlas.repeat.set(1 / gridSize, 1 / gridSize); } // Select top-left sprite selectSprite(0, 0); ``` ## Material Texture Maps ### PBR Texture Set ```javascript const material = new THREE.MeshStandardMaterial({ // Base color (sRGB) map: colorTexture, // Surface detail (Linear) normalMap: normalTexture, normalScale: new THREE.Vector2(1, 1), // Roughness (Linear, grayscale) roughnessMap: roughnessTexture, roughness: 1, // Multiplier // Metalness (Linear, grayscale) metalnessMap: metalnessTexture, metalness: 1, // Multiplier // Ambient occlusion (Linear, uses uv2) aoMap: aoTexture, aoMapIntensity: 1, // Self-illumination (sRGB) emissiveMap: emissiveTexture, emissive: 0xffffff, emissiveIntensity: 1, // Vertex displacement (Linear) displacementMap: displacementTexture, displacementScale: 0.1, displacementBias: 0, // Alpha (Linear) alphaMap: alphaTexture, transparent: true, }); // Don't forget UV2 for AO geometry.setAttribute("uv2", geometry.attributes.uv); ``` ### Normal Map Types ```javascript // OpenGL style normals (default) material.normalMapType = THREE.TangentSpaceNormalMap; // Object space normals material.normalMapType = THREE.ObjectSpaceNormalMap; ``` ## Procedural Textures ### Noise Texture ```javascript function generateNoiseTexture(size = 256) { const data = new Uint8Array(size * size * 4); for (let i = 0; i < size * size; i++) { const value = Math.random() * 255; data[i * 4] = value; data[i * 4 + 1] = value; data[i * 4 + 2] = value; data[i * 4 + 3] = 255; } const texture = new THREE.DataTexture(data, size, size); texture.needsUpdate = true; return texture; } ``` ### Gradient Texture ```javascript function generateGradientTexture(color1, color2, size = 256) { const canvas = document.createElement("canvas"); canvas.width = size; canvas.height = 1; const ctx = canvas.getContext("2d"); const gradient = ctx.createLinearGradient(0, 0, size, 0); gradient.addColorStop(0, color1); gradient.addColorStop(1, color2); ctx.fillStyle = gradient; ctx.fillRect(0, 0, size, 1); return new THREE.CanvasTexture(canvas); } ``` ## Texture Memory Management ### Dispose Textures ```javascript // Single texture texture.dispose(); // Material textures function disposeMaterial(material) { const maps = [ "map", "normalMap", "roughnessMap", "metalnessMap", "aoMap", "emissiveMap", "displacementMap", "alphaMap", "envMap", "lightMap", "bumpMap", "specularMap", ]; maps.forEach((mapName) => { if (material[mapName]) { material[mapName].dispose(); } }); material.dispose(); } ``` ### Texture Pooling ```javascript class TexturePool { constructor() { this.textures = new Map(); this.loader = new THREE.TextureLoader(); } async get(url) { if (this.textures.has(url)) { return this.textures.get(url); } const texture = await new Promise((resolve, reject) => { this.loader.load(url, resolve, undefined, reject); }); this.textures.set(url, texture); return texture; } dispose(url) { const texture = this.textures.get(url); if (texture) { texture.dispose(); this.textures.delete(url); } } disposeAll() { this.textures.forEach((t) => t.dispose()); this.textures.clear(); } } ``` ## Performance Tips 1. **Use power-of-2 dimensions**: 256, 512, 1024, 2048 2. **Compress textures**: KTX2/Basis for web delivery 3. **Use texture atlases**: Reduce texture switches 4. **Enable mipmaps**: For distant objects 5. **Limit texture size**: 2048 usually sufficient for web 6. **Reuse textures**: Same texture = better batching ```javascript // Check texture memory console.log(renderer.info.memory.textures); // Optimize for mobile const maxSize = renderer.capabilities.maxTextureSize; const isMobile = /iPhone|iPad|Android/i.test(navigator.userAgent); const textureSize = isMobile ? 1024 : 2048; ``` ## See Also - `threejs-materials` - Applying textures to materials - `threejs-loaders` - Loading texture files - `threejs-shaders` - Custom texture sampling ## Dónde encaja - Categoría: [Diseño y UI](https://skillsagentes.com/categorias/diseno-ui.md) — Sistemas de diseño, trabajo con componentes y acabado visual. - Creador: [calesthio](https://skillsagentes.com/creators/calesthio.md) — 0 skills en el directorio - [Todas las skills](https://skillsagentes.com/skills.md) - [Ranking de instalaciones](https://skillsagentes.com/ranking.md) ## Otras skills del mismo repositorio - [Seedance 2 5](https://skillsagentes.com/skills/calesthio/openmontage/seedance-2-5.md): Genera vídeo cinematográfico de 4-30 s con ByteDance Seedance 2.5 por fal.ai, Volcengine Ark, Runway o ComfyUI. Cubre el contrato de prompt 2.5, cortes duros, locks de continuidad y voz. - [Comfyui](https://skillsagentes.com/skills/calesthio/openmontage/comfyui.md): Úsalo al trabajar con workflows de ComfyUI en OpenMontage: comfyui_image/video/music, workflows propios, selección de output_node, modelos que faltan, LoRAs, poca VRAM e importación de workflows de la comunidad. - [Fish Audio Tts](https://skillsagentes.com/skills/calesthio/openmontage/fish-audio-tts.md): Genera narración expresiva y multilingüe con fish.audio (modelos S1 / S2) y reutiliza voces clonadas mediante reference_id. - [Minimax H3](https://skillsagentes.com/skills/calesthio/openmontage/minimax-h3.md): Genera vídeo con MiniMax H3 (Hailuo 3.0) por la API oficial v2, fal.ai, Runway, nodos partner de ComfyUI o pesos abiertos locales. Clips de 4-15s a 2K con animación de primer/último fotograma. - [Gemini Omni](https://skillsagentes.com/skills/calesthio/openmontage/gemini-omni.md): Genera y edita conversacionalmente vídeos cortos con Google Gemini Omni Flash: itera con ediciones en lenguaje natural, clips de 3-10s a 720p con audio y texto en pantalla, e imágenes de referencia por etiquetas. ## Skills relacionadas - [Threejs Geometry](https://skillsagentes.com/skills/calesthio/openmontage/threejs-geometry.md): Creación de geometría en Three.js: formas integradas, BufferGeometry, geometría a medida e instancing. Úsalo al crear formas 3D, trabajar con vértices o optimizar con renderizado instanciado. - [Design Taste Frontend](https://skillsagentes.com/skills/leonxlnx/taste-skill/design-taste-frontend.md): Skill anti-slop para frontend: landing pages, portafolios y rediseños. El agente lee el brief, infiere la dirección de diseño correcta y evita interfaces que parezcan plantillas genéricas. - [Gpt Taste](https://skillsagentes.com/skills/leonxlnx/taste-skill/gpt-taste.md): Ingeniero de UX/UI y motion GSAP de élite: impone aleatoriedad real tipo Python, estructura AIDA estricta, tipografía editorial ancha, bento grids sin huecos, ScrollTriggers avanzados y espaciado masivo entre secciones. - [Imagegen Frontend Mobile](https://skillsagentes.com/skills/leonxlnx/taste-skill/imagegen-frontend-mobile.md): Skill de generación de imágenes para conceptos premium de pantallas de apps móviles (iOS, Android, cross-platform), con mockups de teléfono, jerarquía limpia y consistencia multi-pantalla. Solo genera imágenes, no código.' - [Brandkit](https://skillsagentes.com/skills/leonxlnx/taste-skill/brandkit.md): Skill de generación de imágenes premium para brand-kits: boards de guías de marca, sistemas de logo, decks de identidad y presentaciones de mundo visual de alta gama. --- Skills Agentes · [Índice de páginas en markdown](https://skillsagentes.com/sitemap.md) · [Inicio](https://skillsagentes.com/index.md)