Muestra los sombreadores de fragmentos GLSL como fondo del sitio web. Admite ShaderToy Shaders, Multipass-Buffers fuera de pantalla Ping-pong, bucles de retroalimentación, texturas de punto flotante. Ya sea con WebGL 1 o 2, intentará ejecutar donde sea técnicamente posible.
Sitio web/demostración : ? https://xemantic.github.io/shader-web-background?
❔ ??? Para hacer preguntas, vaya al servidor Xemantic Discord ☕ ???
Diseñé esta biblioteca para usar sombreadores de fragmentos complejos como parte de mi diseño de diseño y desarrollo web. Esta es la herramienta que finalmente me permite adoptar el navegador web como un entorno de codificación creativa. Si está familiarizado con GLSL, entonces podría ayudarlo a publicar su trabajo en la web también. Si viene de un fondo de desarrollo web, es posible que desee aprender un poco más sobre los sombreadores primero, por ejemplo del Libro de los Shaders. Espero que los ejemplos presentados en esta documentación se expliquen por sí mismos. Si lo encuentra útil, entonces
❤️ Patrocorador Xemantic en Github o https://www.buymeacoffee.com/kazik
Kazik (Morisil) Pogoda
https://xemantic.com/
Tabla de contenido
texture ?Tl; dr:
<!DOCTYPE html >
< html lang =" en " >
< head >
< meta charset =" utf-8 " >
< title > Minimal shader </ title >
< meta name =" viewport " content =" width=device-width, initial-scale=1 " >
< meta http-equiv =" X-UA-Compatible " content =" IE=edge " >
< script src =" https://xemantic.github.io/shader-web-background/dist/shader-web-background.min.js " > </ script >
< script type =" x-shader/x-fragment " id =" image " >
precision highp float ;
uniform float iTime ;
void main ( ) {
gl_FragColor = vec4 (
mod ( gl_FragCoord . x / 256. , 1. ) ,
mod ( ( gl_FragCoord . x + gl_FragCoord . y - iTime * 40. ) / 256. , 1. ) ,
mod ( gl_FragCoord . y / 256. , 1. ) ,
1.
) ;
}
</ script >
< script >
shaderWebBackground . shade ( {
shaders : {
image : {
uniforms : {
iTime : ( gl , loc ) => gl . uniform1f ( loc , performance . now ( ) / 1000 )
}
}
}
} ) ;
</ script >
< style >
.shader-web-background-fallback {
background: url("https://placekitten.com/666/666");
background-position: center;
background-size: cover;
background-attachment: fixed;
}
</ style >
</ head >
< body >
< h1 > shader-web-background minimal example </ h1 >
</ body >
</ html >Si prefiere aprender con el ejemplo, aquí está la lista de demostraciones que se muestran con su código fuente resaltado:
https://xemantic.github.io/shader-web-background/#demo
Hay varias formas de ajustar esta biblioteca a sus necesidades:
Si desea que sus sombreadores comiencen a renderizar antes de que se carguen otros recursos, busque este método. Solo toma el contenido de:
https://xemantic.github.io/shader-web-background/dist/shader-web-background.min.js
y colóquelo como <script> en el <head> de su archivo HTML.
Ver demostración mínima para referencia (versión en vivo).
Agregue este código a la <head> de su HTML:
< script src =" https://xemantic.github.io/shader-web-background/dist/shader-web-background.min.js " > </ script > En el futuro publicaré shader-web-background a NPM. Por ahora, puede descargar la última distribución minificada junto con el mapa de origen y las fuentes.
Necesitará al menos un sombreador de fragmentos definido así:
< script type =" x-shader/x-fragment " id =" image " >
precision highp float ;
void main ( ) {
// ...
}
</ script > Póngalo en la <head> de su HTML. El type debe ser x-shader/x-fragment y el atributo id es arbitrario.
id única a cada uno de sus sombreadores si está definiendo más de ellos.
< script >
shaderWebBackground.shade( {
shaders : {
image : { }
}
} );
</ script >image del nombre del sombreador debe coincidir con la definida como el atributo id de origen del sombreador.
Este paso no es necesario, sin embargo, agregarlo mejorará la experiencia para la pequeña cantidad de usuarios que aún no pueden ejecutar sombreadores en sus dispositivos.
Definir estilo CSS alternativo, por ejemplo, una captura de pantalla estática de su marco de sombreador:
< style >
.shader-web-background-fallback {
background: url("https://placekitten.com/666/666");
background-position: center;
background-size: cover;
background-attachment: fixed;
}
</ style > La clase CSS shader-web-background-fallback se aplica a la raíz de documento HTML y al lienzo.
shader-web-background-fallback , sin embargo, podría no funcionar en algunos navegadores. El controlador de errores personalizado podría ser necesario para la compatibilidad cruzada.
Consulte la sección Errores de manejo para más detalles.
Vea la API completa de sombreador-web-background
El objeto de configuración pasado a la llamada shaderwebbackground.shade (config) en el ejemplo anterior dará como resultado una tubería de representación mínima que consiste en un sombreador de fragmento llamado image . Un nuevo elemento estático <canvas id="shader-web-background"> El elemento que cubre toda la ventana gráfica se agregará a la página con z-index: -9999 , que se mostrará detrás de otros elementos de la página.
Nota: El elemento predeterminado <canvas> se adjuntará al documento <body> solo cuando se construya todo el árbol DOM. Además, la representación real de los marcos de sombreador no ocurrirá hasta que la página esté completamente cargada, a pesar de que los sombreadores se compilan de inmediato.
Los uniformes proporcionan a los sombreadores la entrada del mundo fuera de GPU. Describir este mecanismo está fuera del alcance de esta documentación. Decidí no construir abstracción en esta parte de WebGL, porque ya es bastante conciso. Consulte WebGlrenderingContext.NUniform Documentation.
Supongamos que desea proporcionar a su sombreador un valor de tiempo medido en segundos desde el momento en que se cargó la página. Primero defina un uniforme en el sombreador image :
uniform float iTime; El nombre iTime es arbitrario, pero debe coincidir con lo que especifica en la configuración:
shaderWebBackground . shade ( {
shaders : {
image : {
uniforms : {
iTime : ( gl , loc ) => gl . uniform1f ( loc , performance . now ( ) / 1000 )
}
}
}
} ) ; La función (gl, loc) => gl.uniform1f(loc, performance.now() / 1000) se invocará antes de representar cada marco de sombreador. Si no está familiarizado con las funciones de JavaScript Arrow, es un equivalente de:
function ( gl , loc ) {
gl . uniform1f ( loc , performance . now ( ) / 1000 )
} Verifique la documentación de la función estándar de JavaScript Performance.now () que devuelve el número de milisegundos desde que se cargó la página. Dividirlo por 1000 dará como resultado un valor de punto flotante medido en segundos.
Resumen: puede usar este mecanismo para adaptar cualquier API como una entrada de sus sombreadores. Verifique las demostraciones del proyecto para ver ejemplos sobre cómo integrar la entrada como:
La declaración de uniforme de "textura" usa el tipo sampler2D :
uniform sampler2D iWebCam; El nombre uniforme es arbitrario. Por ejemplo, Shadertoy es texturas vinculantes bajo el nombre de iChannel0 , iChannel1 , etc. y esta es la convención utilizada principalmente en esta documentación.
Tal uniforme se puede configurar con:
shaderWebBackground . shade ( {
onInit : ( ctx ) => {
ctx . iWebCam = initializeTexture ( ctx . gl ) ;
} ,
shaders : {
image : {
uniforms : {
iWebCam : ( gl , loc , ctx ) => ctx . texture ( loc , ctx . iWebCam ) ;
}
}
}
} ) ;La textura pasada como un segundo argumento a CTX.Texture puede ser una instancia de WebGlTexture o una referencia al búfer de otro sombreador en la tubería. Verifique la sección de ejemplo de configuración compleja y la API - contexto: buffers.
Consulte la sección Agregar texturas para obtener detalles sobre cómo cargar una textura de una imagen.
Todos los sombreadores, excepto el último en la tubería, tendrán texturas asociadas para renderizar. Por defecto, estas texturas se inicializan como punto flotante RGBA HALF_FLOAT (16 bits) con interpolación lineal y se sujetan al borde. La inicialización de la textura se puede personalizar. Ver API - Shader: Documentación de textura para más detalles.
Aquí hay un ejemplo completo de un objeto de configuración con comentarios. Está utilizando las convenciones de Shadertoy para nombrar amortiguadores y uniformes, pero tenga en cuenta que el nombramiento es arbitrario y podría ajustarse a las necesidades de su proyecto.
// mouse coordinates taken from from the mousemove event expressed in "CSS pixels"
var mouseX ;
var mouseY ;
document . addEventListener ( "mousemove" , ( event ) => {
mouseX = event . clientX ;
mouseY = event . clientY ;
} ) ;
shaderWebBackground . shade ( {
// supplied canvas to use for shading
canvas : document . getElementById ( "my-canvas" ) ,
// called only once before the first run
onInit : ( ctx ) => {
// we can center the mouse even before any "mousemove" event occurs
// note, we are
mouseX = ctx . cssWidth / 2 ;
mouseY = ctx . cssHeight / 2 ;
// for convenience you can store your attributes on context
ctx . iFrame = 0 ;
} ,
onResize : ( width , height , ctx ) => {
ctx . iMinDimension = Math . min ( width , height ) ;
} ,
onBeforeFrame : ( ctx ) => {
ctx . shaderMouseX = ctx . toShaderX ( mouseX ) ;
ctx . shaderMouseY = ctx . toShaderY ( mouseY ) ;
} ,
shaders : {
// the first buffer to be rendered in the pipeline
BufferA : {
// uniform setters, attribute names should match with those defined in the shader
uniforms : {
// uniform value calculated in place
iTime : ( gl , loc ) => gl . uniform1f ( loc , performance . now ( ) / 1000 ) ,
// uniform values taken from context
iFrame : ( gl , loc ) => gl . uniform1i ( loc , ctx . iFrame ) ,
iMinDimension : ( gl , loc , ctx ) => gl . uniform1f ( loc , ctx . iMinDimension ) ,
iResolution : ( gl , loc , ctx ) => gl . uniform2f ( loc , ctx . width , ctx . height ) ,
iMouse : ( gl , loc , ctx ) => gl . uniform2f ( loc , ctx . shaderMouseX , ctx . shaderMouseY ) ,
// inputing the previous output of itself - feedback loop
iChannel0 : ( gl , loc , ctx ) => ctx . texture ( loc , ctx . buffers . BufferA )
// ... more uniforms
}
} ,
// ... more shaders
BufferD : {
// optional custom initializer of buffer's texture
texture : ( gl , ctx ) => {
// initializing floating-point texture in custom way for WebGL 1 and 2
ctx . initHalfFloatRGBATexture ( ctx . width , ctx . height ) ;
// standard WebGL texture parameters
gl . texParameteri ( gl . TEXTURE_2D , gl . TEXTURE_MIN_FILTER , gl . NEAREST ) ;
gl . texParameteri ( gl . TEXTURE_2D , gl . TEXTURE_MAG_FILTER , gl . NEAREST ) ;
gl . texParameteri ( gl . TEXTURE_2D , gl . TEXTURE_WRAP_S , gl . REPEAT ) ;
gl . texParameteri ( gl . TEXTURE_2D , gl . TEXTURE_WRAP_T , gl . REPEAT ) ;
} ,
uniforms : {
iChanel0 : ( gl , loc , ctx ) => ctx . texture ( loc , ctx . buffers . BufferA )
// ... more uniforms
}
} ,
// the last shader will render to screen
Image : {
uniforms : {
iChanel0 : ( gl , loc , ctx ) => ctx . texture ( loc , ctx . buffers . BufferD )
// ... more uniforms
}
}
} ,
onAfterFrame : ( ctx ) => {
ctx . iFrame ++ ;
} ,
// custom error handler
onError : ( error , canvas ) => {
canvas . remove ( ) ;
console . error ( error ) ;
document . documentElement . classList . add ( "my-fallback" ) ;
}
} ) ; La API está destinada a ser autoexplicativa. Verifique la especificación API para obtener más detalles. Hay varios sombreadores definidos en el ejemplo anterior. Se procesarán en secuencia llamada Multipass en la nomenclatura de Shadertoy. El último sombreadores definidos se convertirá en pantalla. La salida de sombreadores anteriores, incluido el circuito de retroalimentación del marco anterior representado por el mismo sombreador, se puede pasar fácilmente a uniformes.
Se están realizando varias validaciones en la configuración suministrada para evitar problemas comunes que generalmente son difíciles de depurar lo contrario. La carpeta SRC/Test/HTML/Errors/Contiene todos los casos de prueba de error que también se pueden verificar en la demostración en vivo del manejo de errores.
Todos los errores y advertencias serán visibles en la consola.
Ver:
// mouse coordinates taken from from the mousemove event
var mouseX ;
var mouseY ;
document . addEventListener ( "mousemove" , ( event ) => {
mouseX = event . clientX ;
mouseY = event . clientY ;
} ) ;
// mouse coordinates relative to the shader, you can also store them on the context
var shaderMouseX ;
var shaderMouseY ;
shaderWebBackground . shade ( {
onInit : ( ctx ) => {
// screen center
mouseX = ctx . cssWidth / 2 ;
mouseY = ctx . cssHeight / 2 ;
} ,
onBeforeFrame : ( ctx ) => {
shaderMouseX = ctx . toShaderX ( mouseX ) ;
shaderMouseY = ctx . toShaderY ( mouseY ) ;
} ,
shaders : {
image : {
uniforms : {
iMouse : ( gl , loc ) => gl . uniform2f ( loc , shaderMouseX , shaderMouseY )
}
}
}
} ) ; Nota: Las coordenadas iniciales del mouse se proporcionan en la función onInit porque el primer evento mousemove puede ocurrir mucho después de que se inicia el sombreador. Las coordenadas del sombreador comienzan en la esquina inferior izquierda del lienzo y están alineadas con la mitad del píxel - (0.5, 0.5) .
Referencia de API:
Población:
python -m http.server 8000 si no funciona en su último Ubuntu que ejecutar sudo apt install python-is-python3 primero.
Ver textura: demostración de mármol azul a mapeo de tierra plana
Las texturas se pueden establecer de la misma manera que los búferes se establecen como uniformes, pero primero debemos cargarlas. Por ejemplo, definiendo la promesa personalizada que se puede reutilizar:
const loadImage = ( src ) => new Promise ( ( resolve , reject ) => {
let img = new Image ( ) ;
img . onload = ( ) => resolve ( img ) ;
img . onerror = ( ) => {
reject ( new Error ( "Failed to load image from: " + src ) ) ;
}
img . src = src ;
} ) ; La función onInit es un lugar bastante conveniente para llamar loadPicture :
shaderWebBackground . shade ( {
onInit : ( ctx ) => {
loadImage ( "texture.jpg" )
. then ( image => {
const gl = ctx . gl ;
const texture = gl . createTexture ( ) ;
gl . bindTexture ( gl . TEXTURE_2D , texture ) ;
gl . texParameteri ( gl . TEXTURE_2D , gl . TEXTURE_WRAP_S , gl . CLAMP_TO_EDGE ) ;
gl . texParameteri ( gl . TEXTURE_2D , gl . TEXTURE_WRAP_T , gl . CLAMP_TO_EDGE ) ;
gl . texParameteri ( gl . TEXTURE_2D , gl . TEXTURE_MIN_FILTER , gl . LINEAR ) ;
gl . texParameteri ( gl . TEXTURE_2D , gl . TEXTURE_MAG_FILTER , gl . LINEAR ) ;
gl . texImage2D ( gl . TEXTURE_2D , 0 , gl . RGBA , gl . RGBA , gl . UNSIGNED_BYTE , image ) ;
gl . bindTexture ( gl . TEXTURE_2D , null ) ;
ctx . iTexture = texture ;
} ) ;
} ,
shaders : {
image : {
uniforms : {
iTexture : ( gl , loc , ctx ) => ctx . texture ( loc , ctx . iTexture )
}
}
}
} ) ; Esta biblioteca puede utilizar el código ShaderToy con un esfuerzo mínimo: una envoltura de sombreador simple:
< script type =" x-shader/x-fragment " id =" Image " >
precision highp float ;
uniform vec2 iResolution ;
uniform float iTime ;
// ... other needed uniforms
// -- Paste your Shadertoy code here:
// ...
// -- End of Shadertoy code
void main ( ) {
mainImage ( gl_FragColor , gl_FragCoord . xy ) ;
}
</ script > El atributo id del <script> está configurado para reflejar la pestaña ShaderToy llamada Image . La mayoría de los sombreadores usarán al menos estos 2 uniformes, y es fácil proporcionar sus valores en la configuración:
shaderWebBackground . shade ( {
shaders : {
Image : {
uniforms : {
iResolution : ( gl , loc , ctx ) => gl . uniform2f ( loc , ctx . width , ctx . height ) ,
iTime : ( gl , loc ) => gl . uniform1f ( loc , performance . now ( ) / 1000 ) ,
}
}
}
} ) ;Demoss de Shadertoy:
No hay una solución automatizada para eso. Tendrá que copiar la parte Common directamente en sus sombreadores, justo encima del otro código de Shadertoy.
texture ? En ShaderToy se accede a las texturas con la función texture mientras que en WebGL 1 es texture2D . Aquí hay una solución simple que se agregará antes del código original:
#define texture texture2D En ShaderToy, cada enlace de "canal", una textura puede tener parámetros de muestras separados como interpolación o envoltura. Esta funcionalidad no se puede transferir fácilmente a WebGL 1, pero la mayoría de los sombreadores que se transmiten en estas características se pueden ajustar con soluciones basadas en código. Por ejemplo, si se supone que la textura se repite, entonces algo como esto podría ser un reemplazo funcional de la función texture en un sombreador determinado:
vec4 repeatedTexture( in sampler2D channel, in vec2 uv) {
return texture2D (channel, mod (uv, 1 .));
}Ver también API - Shader: Textura.
Puede nombrar a sus sombreadores según los nombres de buffer de Shadertoy:
BufferABufferBBufferCBufferDImageY luego cílalos:
<!DOCTYPE html >
< html lang =" en " >
< head >
< title > Multipass Shadertoy shader </ title >
< script type =" x-shader/x-fragment " id =" BufferA " >
precision highp float ;
uniform sampler2D iChannel0 ;
// ... the code of BufferA tab with the uniforms and wrapping as above
</ script >
< script type =" x-shader/x-fragment " id =" Image " >
precision highp float ;
uniform sampler2D iChannel0 ;
// ... the code of Image tab with the uniforms and wrapping as above
</ script >
< script >
// ... your prefer method of loading shader-web-background as described above
</ script >
< script >
shaderWebBackground . shade ( {
shaders : {
BufferA : {
uniforms : {
iChannel0 : ( gl , loc , ctx ) => ctx . texture ( loc , ctx . buffers . BufferA )
}
} ,
Image : {
uniforms : {
iChannel0 : ( gl , loc , ctx ) => ctx . texture ( loc , ctx . buffers . BufferA )
}
}
}
} ) ;
</ script >
</ head >
< body >
</ body >
</ html > Es posible alterar el sombreador de vértice predeterminado para cada sombreador de fragmentos proporcionando el siguiente script en <head> :
< script type = "x-shader/x-vertex" id = "shaderIdVertex" >
attribute vec2 V;
varying vec2 uv;
void main() {
gl_Position = vec4 ( V , 0 , 1 ) ;
}
</ script >
< script type = "x-shader/x-fragment" id = "shaderId" >
// ...
varying vec2 uv ;
// ...
< / script > Nota: El type de script está configurado en x-shader/x-vertex y el atributo id se prefiere con el sufijo Vertex . El atributo de vértice debe llamarse V .
NOTA: Se puede especificar que se comparta varying vec2 uv entre vértice y sombreadores de fragmentos (no agregados por defecto).
git clone https://github.com/xemantic/shader-web-background.git
cd shader-web-background
./gradlew compileJsActivará el compilador de cierre de Google, que verificará las fuentes utilizando la información de tipo y las transferirá a archivos minificados de JavaScript:
Este proyecto se ha desarrollado utilizando Idea IntelliJ con el complemento Google-Java-format habilitado. El elemento más notable de este estilo son 2 espacios en lugar de 4 para representar pestañas.
Cualquiera:
<section id="projects-using-shader-web-background">O envíeme un enlace con la descripción.