Diseño Procedural de Telas (Sin Simulación)
Fuente: room-at-dawn (MIT), src/scene/parts/bed.js (mantas, alfombras, almohadas).
Aquí se desglosa en una biblioteca reutilizable, acompañada de un ejemplo que puede visualizarse por etapas.
Idea central: la tela no se "simula", se "diseña".
Sobre coordenadas planas se define "cuánto más alto está cada punto de la tela respecto al soporte", y luego se envuelve ese plano sobre el soporte.
La ventaja es que cada paso es controlable y reproducible (mismo seed → mismo resultado), se construye en menos de 0.5 segundos,
y otros objetos (libros, teléfonos, otra manta) pueden consultar directamente la misma función de altura, asegurando que queden sobre la tela.
El costo es que la tela es estática: no es empujada por personajes (para interactividad, ver references/engines.md).
Archivos
| Ruta | Contenido |
|---|---|
scripts/cloth.js | Biblioteca (módulo ES, solo depende de three): RNG/ruido, Field, lóbulos, familias de pliegues, arrugas, drapeado sobre soporte, doblado de esquinas, malla, relajación UV, textura de arrugas, estampado, material de algodón, exportableMesh (conversión antes de exportar GLB) |
example/index.html + main.js | Una manta sin tender sobre una cama, ?stage=1..5 añade efectos progresivamente |
scripts/curtain.js | Cortinas: curtainPanel (integración de sección transversal sin estiramiento), auditPanel, linenTextures (lino tejido plano), curtainMaterial (costuras, puntadas, pliegues de almacenamiento, translucidez contraluz, micro-ondulación), curtainRing |
example/curtain.html | Un par de cortinas colgadas frente a una ventana, ?cam= (front, angle, top, hem, stitch, above), ?tied=1, ?fullness=, ?loops=, ?tex=checker |
example/preview-*.jpg | Imágenes de ejemplo terminadas y por etapas (preview-curtain.jpg es la cortina) |
references/shape.md | Diseño del campo de alturas: lóbulos, pliegues largos, crestas suavizadas, arrugas, zonas planas |
references/drape-curl.md | Soportes, inclinación, deformación del plano, doblado de esquinas, costuras, colocar objetos sobre la tela, superponer una segunda capa |
references/uv-material.md | Relajación UV, normal map de arrugas finas + cavidad, estampado, material |
references/verification.md | Qué datos revisar, qué tomas de cámara, tabla de síntomas comunes |
references/curtain.md | Cortinas: integración de sección transversal y resolución de ancho, composición de θ(s), material, parámetros, verificación, problemas encontrados |
references/engines.md | Migración a Godot/Unreal: exportación GLB, reescritura en GDScript/C++, cómo integrar telas interactivas |
Ejecutar el ejemplo
cd <carpeta_del_skill> && python3 -m http.server 5420 --bind 127.0.0.1
# Abrir http://127.0.0.1:5420/example/
(<carpeta_del_skill> es el directorio base que se muestra al cargar este skill; como plugin está en ~/.claude/plugins/cache/)
Parámetros URL:
stage=1..5: lóbulos, añadir pliegues largos, crestas suavizadas, arrugas, doblado de esquinas e inclinación.cam=wide|close|top|side|left|foot: cámaras predefinidas.tex=checker: cambia a cuadrícula de 10 cm para comprobar estiramiento UV.relax=0: desactiva la relajación UV, para comparar.ui=0: oculta el panel de datos, útil para capturas.
Al finalizar, window.__cloth contiene los datos de verificación, y body[data-ready="1"] indica que ya se puede capturar.
El botón "Descargar GLB" permite exportar la tela para otros motores.
Flujo de trabajo
| Paso | Qué se hace | Por qué | Biblioteca |
|---|---|---|---|
| 1 | Definir el contorno (cuatro esquinas) y la "distancia al borde" en coordenadas planas | Se necesita para costuras, desvanecimiento de arrugas, doblado de esquinas | quadEdge |
| 2 | Lóbulos: colocar manualmente 5–10 elipses, cada una con altura y ángulo, unidas con smooth-max | La forma grande define "en qué estado está la manta"; el ruido no logra esto | makeLobes lobesAt |
| 3 | Pliegues largos: 2–3 grupos de ruido billow con dirección, cambiando de orientación según la zona | Los pliegues de una manta siguen la dirección de la fuerza que los genera | foldFamily |
| 4 | Ondas longitudinales en las partes colgantes; domain warp global; soft cap para limitar altura | La tela que cuelga no es plana; evitar líneas rectas de regla; que el lóbulo más alto no sea exagerado | softCap |
| 5 | Crestas suavizadas: cada punto no supera ~1.2 cm por encima de su entorno (difuminado dos veces), los valles se mantienen afilados | Las telas con relleno no tienen picos; este paso las transforma de "montañas" a "mantas" | Field.erodePeaks |
| 6 | Dibujar arrugas una a una: desde puntos de sujeción en abanico, y dispersas en el resto siguiendo el campo de tensión, atenuadas cerca de zonas planas y bordes | Las arrugas con ruido parecen mármol; se necesitan segmentos con perfil de tienda de campaña | CreaseSet crease |
| 7 | Costuras: banda plana, ranura de puntada, fruncido | El borde debe ser geometría real para que se vea creíble de cerca | Ejemplo hemElev |
| 8 | Envolver sobre el soporte: zona plana + esquinas redondeadas + caída vertical | Un solo plano puede representar tanto la parte sobre la cama como la que cuelga | boxSupport |
| 9 | Inclinar los pliegues altos hacia un lado: la distancia de inclinación depende de la altura en cada punto | Los bultos se vuelven asimétricos: un lado empinado, otro suave, no como panes simétricos | Ejemplo place |
| 10 | Doblar esquinas: la parte que cruza la línea de pliegue primero se enrosca en un cilindro y luego se tumba sobre la manta; la zona presionada se marca como plana | Añade un detalle narrativo | curl |
| 11 | Relajar UV sobre la superficie 3D (malla múltiple, restricción de longitud de borde) | Los estampados en pliegues pronunciados no se alargan | relaxUV uvStretch |
| 12 | Material: normal map de arrugas finas repetible (alpha guarda cavidad) + estampado + sheen | La geometría maneja centímetros, las texturas manejan milímetros | wrinkleTexture sprigPrintTexture cottonMaterial |
Reglas obligatorias
- El azar siempre va por
RNG(seed)/pn(...,seed), no usesMath.random(). Depende de ello la reproducibilidad de capturas, horneado de iluminación y sincronización multijugador. - Las formas grandes se muestrean con interpolación cúbica (
Field.cubic), las arrugas con bilineal (Field.bil). Si las formas grandes usan bilineal, se ven facetas de 5 mm en la malla. - No hagas arrugas con ruido. El ruido produce manchas; las arrugas reales son líneas con dirección y extremos que se estrechan.
- Primero suaviza crestas, luego añade arrugas. Si se invierte el orden, las líneas de los pliegues también se aplanan.
- La zona plana bajo la esquina doblada debe cubrir todo el rango del pliegue (el ejemplo usa
QMAXpara calcularlo automáticamente). Si no se cubre, la parte doblada se superpone sobre lóbulos altos y el estampado se alarga en franjas (problema real, verreferences/verification.md). - La relajación UV usa la forma "sin doblar" U; el estiramiento de la parte doblada se revisa aparte.
relaxUVrequiere que el número de celdas sea múltiplo de 8. - La tela que cuelga no debe chocar con objetos debajo: el ejemplo hace el armazón de la cama más estrecho que el colchón. Las colisiones fuera del soporte no están dentro del alcance de este método.
- Cuando dos bordes adyacentes cuelgan a la vez, la esquina necesita una forma cónica o una pieza triangular;
boxSupportno lo maneja. Deja solo dos lados opuestos colgando.
Valores de partida (medidos en el ejemplo)
- Grosor de la manta extendida: 5 cm; altura de lóbulos ×
LOBE_SCALE(0.3 es normal después de dormir, 1 es apilado), soft cap máximo 23 cm. - Separación entre pliegues largos: ~12 cm, longitud ~60 cm, amplitud 3–4 cm; radio de suavizado de crestas: 5 celdas (2.5 cm), límite 1.2 cm.
- Ancho de arrugas: 2.4–4 cm, altura ~0.16–0.3 veces el ancho, 30% son surcos; cada punto de sujeción genera 4–7 líneas, otras 200 dispersas.
- Malla: ~7 mm (288×192), ~130 000 triángulos, modelado ~0.45 s (de los cuales relajación UV ~0.15 s), sin penetraciones, estiramiento UV p5/p95 ~0.92/1.08.
Cortinas (tela colgante)
El método de la manta era "campo de alturas envuelto sobre un soporte"; para cortinas no funciona. En su lugar: cada sección horizontal es una línea de longitud fija,
dibujada integrando el ángulo de avance θ(s) a lo largo de la tela, y usando bisección para ajustar el múltiplo de θ de modo que esa fila tenga exactamente el ancho deseado a esa altura.
La tela no se estira, por lo que la UV se mide en metros directamente y la textura no se deforma. Detalles en references/curtain.md.
import { curtainPanel, auditPanel, linenTextures, curtainMaterial, curtainRing, CU } from './scripts/curtain.js';
const p = curtainPanel({ x0t: 0.27, x1t: 0.95, x0h: 0.25, x1h: 0.97, zc: 0.12, yTop: 2.29, yHem: 0.02, loops: 7, seed: 4101 });
const lin = linenTextures();
scene.add(new THREE.Mesh(p.geo, curtainMaterial({ map: lin.map, normalMap: lin.normalMap, yTop: 2.29 })));
console.log(auditPanel(p)); // crossings debe ser 0; stretchP95Pct debe ser menor que 1
- Medido en el ejemplo: un panel ~100 000 triángulos, ~0.2 s de construcción, estiramiento p95 0.4–0.7 %, cruces 0.
- Problema conocido: si
depthse ajusta demasiado, la tela pierde 5–15 % de ancho. Si falta espacio, reducefullness, no comprimas la profundidad. - Problema conocido: si el dobladillo inferior es demasiado estrecho, los pliegues pueden cruzarse entre sí; el umbral depende del seed (en el ejemplo, el panel derecho aún tiene cruces en ~0.67×, y pasa solo en ~0.79×). Revisa
crossingsy cambia el seed si es necesario. - La profundidad por defecto
depth[-0.11, 0.16] no acorta la tela, pero la barra debe estar a unos 12 cm de la pared.