Materiales de textura procedural
Fuente: room-at-dawn (MIT), de src/core/tex.js, rng.js, src/scene/materials.js y las funciones de material de cada pieza en parts/.
El dormitorio del proyecto original no contiene ningún archivo de imagen; todas las texturas se generan proceduralmente al cargar.
Ideas clave:
- Diseñar con unidades físicas. La altura se mide en milímetros, se especifica cuántos metros representa un mosaico de textura y la UV también está en metros. De esta forma,
repeat = 1 / tileMetros, y cambiar la resolución no altera la apariencia. - La mayor parte del "realismo" está en la rugosidad, no en el color. Las huellas dactilares, las marcas de limpieza y el polvo son casi invisibles en el color; se manifiestan cuando la luz especular los recorre.
- Siempre repetible y reproducible. El ruido tiene períodos fijos y los números aleatorios siempre usan
RNG(seed). El mismo seed produce siempre el mismo resultado (esencial para horneado de iluminación y pruebas de regresión de capturas de pantalla).
Archivos
| Ruta | Contenido |
|---|---|
scripts/tex.js | Base: RNG, pnoise/pfbm (períodos diferentes por eje), worley, vn (ruido rápido con tabla de consulta), field, normalBytes (en milímetros), dataTex/canvasTex/packTex/colorTex, avgColor, once (caché), rep (compartir imagen, solo cambiar repeat), seamScore, texData |
scripts/surfaces.js | wallNormal + wallPatch (papel pintado de viruta de madera con variaciones de yeso y pintura a escala 3.2 m), lacquerNormal, smudgeRough, dustRough, floorMaps, woodMaps, oakVeneer |
scripts/textiles.js | weaveNormal, waffleNormal, terryNormal, ribNormal, knitNormal, feltNormal, ropeNormal, fabricMaterial (sheen más transmisión de luz a contraluz) |
scripts/wear.js | wornMaps (una superficie usada: dos imágenes de color y rugosidad), speckleTexture, scuffTexture, y pinceles básicos softBlob, strand, fingerprint, noiseTile, overlay |
scripts/print.js | word/phrase (texto falso a partir de sílabas), PAL, packer, fitText, paperGrain, makeBook + bookAtlas + bookGeometry, pagesTexture, topoPoster, photoPrints |
example/ | Una esquina de la habitación, cada superficie utiliza un material de la biblioteca. ?cam= (room, desk, glint, fabric, floor, wall, books); ?flat=1 cambia a color plano de control |
example/preview.jpg | Captura de pantalla de ejemplo |
references/recipes.md | Método, dimensiones, parámetros de cada material y cómo añadir nuevos |
references/verify-engines.md | Métodos de verificación, problemas encontrados, rendimiento y migración a Godot/Unreal |
Ejecutar ejemplo
cd <carpeta_del_skill> && python3 -m http.server 5422 --bind 127.0.0.1
# Abrir http://127.0.0.1:5422/example/ (window.__tex tiene el tiempo de generación, puntuación de costura y albedo promedio de cada textura)
(<carpeta_del_skill> es el directorio base que se muestra al cargar este skill; cuando está instalado como plugin, se encuentra en ~/.claude/plugins/cache/)
Uso
import { rep } from './scripts/tex.js';
import { floorMaps, wallNormal, wallPatch, lacquerNormal } from './scripts/surfaces.js';
import { knitNormal, fabricMaterial } from './scripts/textiles.js';
import { wornMaps } from './scripts/wear.js';
const fl = floorMaps(); // UV en metros; repeat ya está configurado
floor.material = new THREE.MeshStandardMaterial({ map: fl.map, normalMap: fl.normalMap, roughnessMap: fl.roughnessMap, roughness: 1 });
wall.material = wallPatch(new THREE.MeshStandardMaterial({ color: 0xebebe6, roughness: 0.93, normalMap: wallNormal() }));
door.material = new THREE.MeshStandardMaterial({ color: 0xdddddd, roughness: 0.6, normalMap: rep(lacquerNormal(), 9), normalScale: new THREE.Vector2(0.18, 0.18) });
sweater.material = fabricMaterial(0x6f7f6a, { normal: knitNormal(), tileM: 0.1 });
const w = wornMaps({ sizeM: [1.2, 0.6], hands: [[0.55, 0.5]], rings: [[0.9, 0.4, 0.032, 0.6]], prints: 6 });
deskTop.material = new THREE.MeshStandardMaterial({ map: w.map, roughnessMap: w.roughnessMap, roughness: 1 });
- En los materiales con
roughnessMap,roughnessdebe ser 1. three.js multiplica ambos valores. - La rugosidad en
packTexywornMapsestá en el canal G. También se puede usar un canvas en escala de grises directamente. - Cada material devuelve
avg(color lineal promedio) parathreejs-baked-gicomo albedo de la luz reflejada.
Reglas a seguir obligatoriamente
- No usar
Math.random(). Cada textura debe tener una semilla fija. - El período del ruido debe ser un número entero y alineado con la cuadrícula de la textura (por ejemplo,
pfbm(u*6, v*6, oct, seed, 6)). Si no está alineado, aparecen costuras. UsarseamScorepara verificar. - La altura se mide en milímetros, usar
normalBytes(H, w, h, milimetrosPorCuadro). Al cambiar la resolución, la intensidad de las protuberancias no cambia; algunos materiales no tienen cuadrícula cuadrada (suelo de 1.1 × 1.9 mm), por lo que hay que proporcionar valores separados por eje. - La rugosidad se dibuja junto con el color. Cada trazo de
wornMapsse dibuja simultáneamente en dos canvases usando el mismonew RNG(i), para que las formas de ambos queden alineadas. - En superficies oscuras, reducir la cantidad de partículas y puntos brillantes (en el ejemplo, la mesa oscura pasó de 9000 a 2500), de lo contrario parecerá granito.
- Todo el texto e imágenes dibujados en Canvas deben ser generados por el código (
word(), formas geométricas). No incluir nombres de libros, marcas o logotipos reales. - La textura más grande (2048²) tarda entre 0.1 y 0.35 segundos en crearse. Usar
oncepara cachear la misma textura yrep()para compartirla. No generar una copia para cada objeto.
Rendimiento medido (RTX 4090, Chrome headless, ejemplo completo 1.1 s)
| Textura | Tamaño | Tiempo | Puntuación de costura (x/y) |
|---|---|---|---|
floorMaps | 2048² × 3 imágenes | 0.32 s | Color 0.96/1.10, Normal 1.00/1.02, Rugosidad 0.89/1.05 |
woodMaps | 1024² × 3 | 0.20–0.23 s | Color 0.93/1.12, Normal 1.30/1.06 |
wornMaps (1.2 × 0.6 m, 3400 px/m) | 4080×2040 + rugosidad a la mitad | 0.13 s | No repetible |
oakVeneer | 1024² × 3 | 0.10 s | 0.98–1.06 |
wallNormal | 1024² | 0.04 s | 1.00/1.07 |
lacquerNormal, smudgeRough | 512² | 0.02–0.04 s | 0.98–1.04 |
| 7 tipos de tela | 128²–512² | 1–19 ms | 0.94–1.10 (la y de la cuerda de algodón es 2.03, es una ranura intencional; ver verify-engines.md) |
bookAtlas (12 libros) | 2048×1536 | 0.05–0.08 s | — |
Una puntuación de costura cercana a 1 indica que no se ven costuras; si es mayor de 2, hay que revisarla. Al calcular, se suma 1 nivel de color al numerador y al denominador para evitar que en direcciones con poca variación (como madera con veta recta) el ruido inferior a 1 nivel de color genere una relación muy grande.