Cartel editorial: una esfera cuyo grano se concentra en el borde, sobre la retícula de partículas en espacio de pantalla.
Gráficos

Esfera de grano

estudio de shaders

EstadoEn vivo
RolGráficos
Año2025
Stack
glslthree.jsreact three fiber

Resumen

Un shader GLSL que genera grano animado sobre una geometría esférica, con capas de ruido que se desplazan a distinta velocidad para simular película.

La idea

El grano de película no pertenece a lo que se está filmando. Pertenece al soporte. Por eso, cuando la cámara se mueve, el grano no se mueve con la escena: se queda donde está, y la imagen pasa por detrás.

Casi todos los shaders de grano hacen justo lo contrario —ruido sobre las coordenadas de la superficie, que viaja pegado al objeto— y por eso se ven como una textura y no como película.

El grano vive en la pantalla, no en el objeto

La decisión que define todo lo demás es una línea: el ruido se evalúa sobre gl_FragCoord, la coordenada del píxel, y no sobre las UV ni sobre la normal.

glsl
float g = hash12(gl_FragCoord.xy);
float on = step(g, uParticleDensity);

Qué píxeles son partícula queda decidido de una vez y no cambia nunca. La esfera gira, respira y se desplaza por debajo de una piel que está quieta.

Esto tiene una consecuencia que no había previsto y que terminó siendo el motivo de conservarlo: la esfera y el campo de partículas del fondo comparten la misma piel. Son dos objetos distintos, con geometrías distintas, evaluando la misma función sobre la misma coordenada de pantalla. Donde se solapan, el grano coincide exactamente.

El hash es el de Dave Hoskins, sin sin(). La versión con seno es la que todo el mundo copia y produce artefactos de rejilla en cuanto la resolución sube, porque su periodicidad se alinea con la del píxel.

Figura pendiente/media/projects/grain-sphere-shader/01-screen-space.webp

La onda atraviesa el cuerpo

Si todos los píxeles encendidos brillaran igual, esto sería estática. Lo que le da forma es una onda plana que viaja a través del volumen:

glsl
float w1 = 0.5 + 0.5 * sin(
  dot(vWorldPos, normalize(vec3(0.8, 0.45, 0.35))) * uWaveFreq
    - uTime * uWaveSpeed);

El producto punto entre la posición en el mundo y una dirección fija convierte el espacio en una sola cifra: la distancia a lo largo de esa dirección. Los frentes de onda son planos que barren la esfera, así que la banda iluminada envuelve el cuerpo mientras avanza en vez de deslizarse por su superficie. Una segunda onda, mucho más débil y en otra dirección, rompe la regularidad de la primera.

Figura pendiente/media/projects/grain-sphere-shader/02-wavefront.webp

El borde

Falta el volumen. Sin él la esfera es un disco: una silueta redonda rellena de grano, sin ninguna señal de que hay una cara mirando a la cámara.

glsl
float ndv = clamp(dot(normalize(vNormal), viewDir), 0.0, 1.0);
float volume = 0.25 + 0.75 * smoothstep(0.0, 0.9, ndv);
float W = pow(wave, 1.8) * volume;

Lo que mira a la cámara se enciende; lo que se va de canto se deshace hasta un 25%, no hasta cero — un borde que llega a cero se recorta contra el fondo y vuelve a leerse como un disco, esta vez con un contorno duro.

El pow(wave, 1.8) es lo que separa la onda del fondo. Sin él, el mínimo de una sinusoide sigue siendo luz, y el cuerpo entero queda tenuemente encendido todo el tiempo.

Respirar

La geometría hace una sola cosa, en el vertex shader: la esfera entera se hincha y se asienta, multiplicando la posición por un factor que oscila. No es una deformación por vértice, es una sola masa cambiando de tamaño.

Es el único movimiento del que la esfera es dueña. Todo lo demás —las poses de ruta, la escala al navegar— lo escribe GSAP desde fuera, y esa separación es justamente la regla que el resto del sitio también sigue: un solo escritor por propiedad.

Más proyectos



SESSION_ELAPSED00:00:00
LOCALE: ESENV: PROD