Documentación · referencia

Lo que el motor le da a un shader

Cada nombre que puede leer un material o un efecto de pantalla, en sprites, modelos y la pantalla entera, con las dos tarjetas gráficas.

Un material es una función pequeña que escribes tú: el motor la ejecuta en cada píxel (y, en un modelo, en cada esquina) y le da lo que sabe de ese sitio. Esta página lo lista todo. Los nombres son una promesa: un shader escrito con ellos sigue funcionando en versiones futuras, así que ninguno se renombra nunca. Las pruebas del motor comprueban que cada nombre de esta página existe en las dos tarjetas gráficas.

Para ver cada entrada trabajando, cada una dibujando algo que se ve, abre el ejemplo Lo que recibe un shader.

Las funciones se escriben en WGSL para WebGPU (fragment, vertex) y en GLSL para WebGL2 (fragmentGlsl, vertexGlsl). Los nombres son los mismos en los dos; solo los tipos se escriben a la manera de GLSL (vec4 por vec4<f32>). Si construyes el material con el compositor de shaders, él escribe los dos por ti.

En todos los shaders: mu

Los parámetros de un material llegan en mu. Primero van los del motor, siempre en el mismo orden, y después los tuyos, con el nombre que les diste: uniforms: { charge: 0 } se lee como mu.charge.

NombreTipoQué es
mu.timef32Segundos de juego. timeScale lo acelera o lo frena, y la pausa lo para.
mu.resolutionvec2<f32>El tamaño de aquello en lo que se dibuja, en píxeles.
mu.progressf32Solo en efectos de pantalla: cuánto lleva de su mitad un cambio de escena, de 0 a 1.
mu.phasef32Solo en efectos de pantalla: 0 mientras el cambio de escena tapa la pantalla, 1 mientras la destapa.

Fuera de un cambio de escena, progress y phase valen 0. Esos cuatro nombres están ocupados: un parámetro tuyo no puede llamarse así.

Un parámetro es de uno de cuatro tipos: f32, vec2<f32>, vec3<f32> o vec4<f32>. El bloque entero cabe en 64 números, contando los del motor. Un vec3 o un vec4 empieza en un múltiplo de cuatro, así que un número suelto justo antes deja un hueco pequeño. Un material que declara más de lo que cabe se dibuja con el aspecto de serie, y la consola dice por qué.

Sprites, textos y capas de mapa

Un material con shader: 'sprite2d' (el de serie) tiene una función:

fn effect(color: vec4<f32>, uv: vec2<f32>) -> vec4<f32> {
    return color;
}

El mismo material funciona en una capa de mapa sin cambiar una palabra.

Modelos

Un material con shader: 'mesh3d' tiene dos funciones. Las dos son opcionales: la que no escribas hace lo que hace el motor.

fn vertex(pos: vec3<f32>, ctx: VertContext) -> vec3<f32> {
    return pos;
}
 
fn effect(surface: vec4<f32>, ctx: FragContext) -> vec4<f32> {
    return vec4<f32>(surface.rgb * ctx.light + ctx.shine + ctx.emissive, surface.a);
}

Ese effect es el del motor, palabra por palabra: un buen punto de partida.

Lo que recibe la función de la esquina:

VertContextTipoQué es
normalvec3<f32>Hacia dónde mira la esquina, en el espacio del modelo.
uvvec2<f32>El sitio en la imagen.
colorvec4<f32>El color pintado en la esquina; blanco si no hay.
tangent, bitangentvec3<f32>Hacia dónde corre la imagen a lo ancho y hacia abajo, en el espacio del modelo.
uv2vec2<f32>Una segunda coordenada de imagen: la del fichero, o uv otra vez.

Lo que recibe la función del color:

FragContextTipoQué es
uvvec2<f32>El sitio en la imagen, ya estirado si el material es affine.
normalvec3<f32>Hacia dónde mira la superficie, en el mundo.
worldPosvec3<f32>Dónde está el píxel, en el mundo.
lightvec3<f32>La luz que cae aquí, sombras y luz ambiente incluidas.
shinevec3<f32>El brillo.
emissivevec3<f32>La luz propia del material, a través de su imagen de brillo.
viewDirvec3<f32>De la superficie hacia la cámara.
colorvec4<f32>El color pintado, solo. Ya va dentro de surface.
screenvec2<f32>Dónde está en la pantalla, en píxeles del juego, con (0, 0) arriba a la izquierda.
tangent, bitangentvec3<f32>Hacia dónde corre la imagen a lo ancho y hacia abajo, en el mundo.
uv2vec2<f32>La segunda coordenada de imagen.
frontFacingboolFalso solo en la cara de atrás de un material con cull: 'front' o 'none'.
carryvec4<f32>Lo que vertex escribió en carry, mezclado a lo largo del triángulo. Cero si no escribió nada.

light y shine se calculan en las esquinas y se mezclan a lo largo del triángulo; no se vuelven a calcular en cada píxel. Así iluminaban un modelo las consolas de la época, y es el aspecto que busca el motor.

Ayudantes que puede llamar el shader de un modelo:

Efectos de pantalla

Un efecto sobre la pantalla entera (usePostProcess({ fragment })) tiene la misma función que un sprite. color es el fotograma ya leído en uv.

AyudanteQué lee
sampleTexture(uv)El fotograma, píxel a píxel.
sampleTextureSmooth(uv)El fotograma, mezclado entre píxeles: para desenfoques, deformaciones y pasadas más pequeñas.
sampleInput(uv)El fotograma que recibió el efecto. Solo es distinto de sampleTexture en un efecto con passes.
sampleHistory(uv)Lo que mostró el efecto el fotograma anterior: negro al principio, blanco si el efecto no lo pidió.
paletteSize(), paletteColor(i)La paleta que recibe el efecto: cuántos colores tiene, y el color i.
lutSize(), lutTexel(x, y, slice, size), lutColor(rgb)La tabla de color que recibe. lutColor pasa un color por ella.

Un efecto lee una sola imagen de datos: una paleta o una tabla de color, nunca las dos.