Saltar al contenido

Los nodos de utilidad integrados

El catálogo de ruido, patrones, mapeos de UV, ajustes de color y modos de mezcla que Three.js ya trae, con sus firmas reales.

Ruido

Three.js trae la biblioteca de ruido de MaterialX, que es de calidad de producción y está probada. Los nombres siguen la convención del estándar:

JS
import {  mx_noise_float, mx_noise_vec3, mx_noise_vec4,  mx_fractal_noise_float, mx_fractal_noise_vec2, mx_fractal_noise_vec3, mx_fractal_noise_vec4,  mx_worley_noise_float, mx_worley_noise_vec2, mx_worley_noise_vec3,  mx_cell_noise_float} from 'three/tsl';

Las firmas que importan:

JS
mx_noise_float( texcoord = uv(), amplitude = 1, pivot = 0 )mx_fractal_noise_vec3( position = uv(), octaves = 3, lacunarity = 2, diminish = 0.5, amplitude = 1 )

El ruido fractal es el que se usa para casi todo lo orgánico: el número de octavas controla el detalle, la lacunaridad cuánto sube la frecuencia entre octavas, y el factor de disminución cuánto baja la amplitud.

JS
import { mx_fractal_noise_float, positionLocal, mix, color } from 'three/tsl';const veta = mx_fractal_noise_float( positionLocal.mul( 3 ), 5, 2, 0.55 )  .mul( 0.5 ).add( 0.5 )  .toVar( 'veta' );material.colorNode = mix( color( 0xe8e2d6 ), color( 0x6b5f4b ), veta );

El ruido de Worley, también llamado celular, da patrones de celdas y sirve para escamas, piedra, burbujas y craquelado. mx_cell_noise_float da un valor constante por celda, útil para variación aleatoria discreta.

Un aviso: mx_noise_vec2 no existe. Está comentado en el código fuente. Las variantes disponibles de mx_noise son float, vec3 y vec4; las de mx_fractal_noise sí incluyen vec2.

Y hay tres nodos de ruido más ligeros para casos simples:

JS
import { rand, hash, triNoise3D, checker } from 'three/tsl';const aleatorio = rand( uv() );          // pseudoaleatorio determinista desde un vec2const tablero  = checker( uv().mul( 8 ) ); // patron de damas

checker( coord = uv() ) es un damero clásico y es sorprendentemente útil como textura de depuración: aplicado a un modelo, muestra de un vistazo si sus UV están bien distribuidas.

Mapeos de coordenadas

Triplanar. Aplicar una textura a una geometría sin UV, proyectándola desde los tres ejes y mezclando según la normal. Es la solución estándar para terrenos, rocas y geometría procedural.

JS
import { triplanarTexture, texture, float } from 'three/tsl';material.colorNode = triplanarTexture( texture( miTextura ), null, null, float( 0.5 ) );

La firma completa, del código fuente:

JS
triplanarTextures( textureXNode, textureYNode = null, textureZNode = null,                   scaleNode = float( 1 ), positionNode = positionLocal, normalNode = normalLocal )

triplanarTexture es un alias que delega en triplanarTextures. Si solo das la primera textura, se usa para los tres ejes; si das las tres, cada eje usa la suya, que es lo que permite tener por ejemplo hierba arriba y roca en los laterales.

Matcap. Las coordenadas para un material de captura de material se obtienen de un nodo ya evaluado:

JS
import { matcapUV, texture } from 'three/tsl';material.colorNode = texture( miMatcap, matcapUV );

Ojo: matcapUV es un valor, no una función. No lleva paréntesis.

Equirectangular. Para muestrear un panorama esférico a partir de una dirección:

JS
import { equirectUV, texture, positionWorldDirection } from 'three/tsl';material.colorNode = texture( miPanorama, equirectUV( positionWorldDirection ) );

Su parámetro tiene por defecto positionWorldDirection, así que equirectUV() sin argumentos ya hace lo habitual.

Rotación. rotate( position, rotation ) gira un vector, con dos argumentos.

Y hay más en el mismo territorio: spritesheetUV para animación por hojas de sprites, pointUV para las coordenadas dentro de un punto, rotateUV para girar coordenadas de textura.

Color: ajustes y mezcla

JS
import { saturation, vibrance, hue, luminance, grayscale, posterize } from 'three/tsl';

Las tres primeras comparten firma: ( color, adjustment = float( 1 ) ), donde uno significa sin cambio.

JS
import { output, saturation, vec4 } from 'three/tsl';// Baja la saturacion a la mitad, conservando el resto del calculo.material.outputNode = vec4( saturation( output.rgb, 0.5 ), output.a );

luminance es distinta: es una función normal de JavaScript con argumentos posicionales, luminance( color, coeficientes ), y sus coeficientes por defecto salen del sistema de gestión de color de Three.js, así que respetan el espacio de trabajo activo. Usarla es preferible a escribir a mano el producto escalar con los coeficientes de siempre.

Modos de mezcla

Los cinco modos clásicos de composición, todos con firma ( base, blend ):

JS
import { blendBurn, blendDodge, blendScreen, blendOverlay, blendColor } from 'three/tsl';material.colorNode = blendOverlay( texturaBase, texturaDetalle );

Los cuatro primeros trabajan con vec3; blendColor trabaja con vec4 y respeta el alfa, que lo hace el adecuado para superponer una capa con transparencia.

Pantalla, tiempo y osciladores

Nodo Qué da
screenUV coordenada normalizada de pantalla, de 0 a 1
screenCoordinate coordenada en píxeles
screenSize tamaño del framebuffer en píxeles
screenDPR la densidad de píxeles
viewportUV, viewportSize, viewportCoordinate equivalentes referidos al viewport
time segundos transcurridos
deltaTime segundos del último frame
frameId número de frame, tipo entero sin signo

Y los cuatro osciladores, todos con la misma firma ( t = time ), que devuelven valores en el rango de cero a uno con periodo uno:

JS
import { oscSine, oscSquare, oscTriangle, oscSawtooth } from 'three/tsl';material.emissiveNode = color( 0x33ffcc ).mul( oscSine() );material.emissiveNode = color( 0xff2244 ).mul( oscSquare( time.mul( 4 ) ) );

Remapeo y rangos

JS
import { remap, remapClamp, range } from 'three/tsl';// De un rango a otro.const v = remap( ruido, -1, 1, 0.2, 0.8 );// Igual, pero recortando fuera del rango de entrada.const w = remapClamp( altura, 0, 10, 0, 1 );

range( min, max ) es distinto y muy útil con instancias: genera un valor aleatorio pero estable por instancia dentro del rango dado, lo que permite variar color, tamaño o velocidad entre miles de copias sin ningún atributo adicional.

JS
import { range, color, mix } from 'three/tsl';// Cada instancia recibe su propio tono.material.colorNode = mix( color( 0x2244ff ), color( 0xffaa22 ), range( 0, 1 ) );