Zeigt GLSL -Fragment -Shader als Website -Hintergrund an. Unterstützt Shadertoy Shader, Multipass-Ping-Pong-Offscreen-Puffer, Feedback-Schleifen, schwimmende Punktetexturen. Entweder mit WebGL 1 oder 2 wird versucht, überall dort zu laufen, wo es technisch möglich ist.
Website/Demo:? https://xemantic.github.io/shader-web-background?
❔ ??? Um Fragen zu stellen, gehen Sie zu Xemantic Discord Server ☕ ???
Ich habe diese Bibliothek so gestaltet, dass sie komplexe Fragment -Shader als Teil meines Webdesign- und Entwicklungsprozesses verwenden. Dies ist das Tool, mit dem ich den Webbrowser schließlich als kreative Codierungsumgebung annehmen kann. Wenn Sie mit GLSL vertraut sind, können Sie auch Ihre Arbeiten im Web veröffentlichen. Wenn Sie aus einem Webentwicklungshintergrund stammen, möchten Sie vielleicht zuerst ein bisschen mehr über Shaders lernen, zum Beispiel aus dem Buch der Shaders. Ich hoffe, dass Beispiele, die in dieser Dokumentation vorgestellt werden, selbsterklärend sind. Wenn Sie es nützlich finden, dann
❤️ Sponsor Xemantic auf Github oder https://www.buymaacoffee.com/kazik
Kazik (Morisil) Pogoda
https://xemantic.com/
Inhaltsverzeichnis
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 >Wenn Sie es lieber mit Beispiel lernen, finden Sie hier die Liste der Demos, die mit ihrem hervorgehobenen Quellcode angezeigt werden:
https://xemantic.github.io/shader-web-background/#demo
Es gibt verschiedene Möglichkeiten, diese Bibliothek an Ihre Bedürfnisse anzupassen:
Wenn Sie möchten, dass Ihre Shader mit dem Rendern beginnen, bevor andere Ressourcen geladen werden, entscheiden Sie sich für diese Methode. Nehmen Sie einfach den Inhalt von:
https://xemantic.github.io/shader-web-background/dist/shader-web-background.min.js
und setzen Sie es als <script> in die <head> Ihrer HTML -Datei ein.
Siehe minimale Demo als Referenz (Live -Version).
Fügen Sie diesen Code dem <head> Ihres HTML hinzu:
< script src =" https://xemantic.github.io/shader-web-background/dist/shader-web-background.min.js " > </ script > In Zukunft werde ich shader-web-background auf NPM veröffentlichen. Im Moment können Sie einfach die neueste Minimified Distribution zusammen mit Quellkarte und Quellen herunterladen.
Sie benötigen mindestens einen Fragment -Shader, der so definiert ist:
< script type =" x-shader/x-fragment " id =" image " >
precision highp float ;
void main ( ) {
// ...
}
</ script > Legen Sie es in die <head> Ihres HTML. Der type sollte x-shader/x-fragment sein und das id Attribut ist willkürlich.
id zu geben, wenn Sie mehr von ihnen definieren.
< script >
shaderWebBackground.shade( {
shaders : {
image : { }
}
} );
</ script >image sollte mit dem als Shader Source id -Attribut definierten Quell -ID -Attribut übereinstimmen.
Dieser Schritt ist nicht erforderlich. Hinzufügen wird jedoch die Erfahrung für die geringe Anzahl von Benutzern verbessern, die immer noch keine Shader auf ihren Geräten ausführen können.
Definieren Sie den Fallback -CSS -Stil, zum Beispiel einen statischen Screenshot Ihres Shader -Rahmens:
< style >
.shader-web-background-fallback {
background: url("https://placekitten.com/666/666");
background-position: center;
background-size: cover;
background-attachment: fixed;
}
</ style > Die shader-web-background-fallback -CSS-Klasse wird auf HTML-Dokumentroot und die Leinwand angewendet.
shader-web-background-fallback -CSS-Klasse zu liefern, es funktioniert jedoch möglicherweise nicht bei einigen Browsern. Für die Kreuzkompatibilität wird möglicherweise benutzerdefinierter Fehlerbehandler benötigt.
Weitere Informationen finden Sie unter Abschnitt "Handhabungsfehler".
Siehe die volle Shader-Web-Background-API
Das an den Shaderwebbackground übergebene Konfigurationsobjekt (Konfigurationsaufruf) im obigen Beispiel führt zu einer minimalen Rendering -Pipeline, die aus einem Fragment Shader namens image besteht. Ein neuer statischer <canvas id="shader-web-background"> Element, das das gesamte Ansichtsfenster abdeckt, wird der Seite mit z-index: -9999 hinzugefügt, das hinter anderen Seitenelementen angezeigt wird.
HINWEIS: Das Standard <canvas> wird nur dann an Dokument <body> angehängt, wenn der gesamte DOM -Baum konstruiert ist. Auch die tatsächliche Darstellung von Shaderrahmen erfolgt erst, wenn die Seite vollständig geladen ist, obwohl Shader sofort zusammengestellt werden.
Uniformen bieten Shader den Eingang der Welt außerhalb der GPU. Die Beschreibung dieses Mechanismus ist aus dem Umfang dieser Dokumentation. Ich habe beschlossen, keine Abstraktion über diesen Teil von WebGL zu erstellen, da sie bereits ziemlich präzise ist. Siehe WebglrenderingContext.uniform -Dokumentation.
Nehmen wir an, Sie möchten Ihrem Shader einen Zeitwert zur Verfügung stellen, der in Sekundenschnelle gemessen wird, seit deren geladener Moment. Definieren Sie zuerst eine Uniform im image Shader:
uniform float iTime; Der Name iTime ist willkürlich, sollte jedoch mit dem übereinstimmen, was Sie in der Konfiguration angeben:
shaderWebBackground . shade ( {
shaders : {
image : {
uniforms : {
iTime : ( gl , loc ) => gl . uniform1f ( loc , performance . now ( ) / 1000 )
}
}
}
} ) ; Die Funktion (gl, loc) => gl.uniform1f(loc, performance.now() / 1000) wird vor dem Rendern jedes Shader -Rahmens aufgerufen. Wenn Sie mit JavaScript -Pfeilfunktionen nicht vertraut sind, ist dies ein Äquivalent zu:
function ( gl , loc ) {
gl . uniform1f ( loc , performance . now ( ) / 1000 )
} Überprüfen Sie die Dokumentation der Standard -JavaScript -Leistung.Now () -Funktion, die die Anzahl der Millisekunden zurückgibt, seit die Seite geladen wurde. Das Teilen durch 1000 führt zu einem in Sekunden gemessenen Gleitpunktwert.
Zusammenfassung: Sie können diesen Mechanismus verwenden, um jede API als Eingabe Ihrer Shader anzupassen. Überprüfen Sie Projektdemos für Beispiele, wie Sie Eingaben integrieren wie:
In der Erklärung der "Textur" -Forientierung wird der sampler2D -Typ verwendet:
uniform sampler2D iWebCam; Der einheitliche Name ist willkürlich. Zum Beispiel verbindet Shadertoy Texturen unter dem Namen iChannel0 , iChannel1 usw., und dies ist die Konvention, die hauptsächlich in dieser Dokumentation verwendet wird.
Eine solche Uniform kann eingestellt werden mit:
shaderWebBackground . shade ( {
onInit : ( ctx ) => {
ctx . iWebCam = initializeTexture ( ctx . gl ) ;
} ,
shaders : {
image : {
uniforms : {
iWebCam : ( gl , loc , ctx ) => ctx . texture ( loc , ctx . iWebCam ) ;
}
}
}
} ) ;Die Textur , die als zweites Argument an ctx.texture übergeben wurde, kann entweder eine Instanz von WebGltexture oder eine Referenz auf den Puffer eines anderen Shaders in der Pipeline sein. Überprüfen Sie den Abschnitt und den API - Kontext: Puffer.
Weitere Informationen zum Laden einer Textur aus einem Bild finden Sie im Abschnitt Texturen.
Alle Shader, mit Ausnahme des letzten in der Pipeline, haben Texturen zugeordnet, um sie zu rendern. Standardmäßig werden diese Texturen als RGBA HALF_FLOAT (16-Bit) mit linearer Interpolation initialisiert und an die Kante geklemmt. Die Texturinitialisierung kann angepasst werden. Weitere Informationen finden Sie unter API - Shader: Texturdokumentation.
Hier ist ein umfassendes Beispiel für ein Konfigurationsobjekt mit Kommentaren. Es wird Shadertoy -Konventionen verwendet, um Puffer und Uniformen zu benennen, aber denken Sie daran, dass die Benennung willkürlich ist und möglicherweise an die Bedürfnisse Ihres Projekts angepasst wird.
// 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" ) ;
}
} ) ; Die API soll selbsterklärend sein. Überprüfen Sie die API -Spezifikation für Details. Im obigen Beispiel sind mehrere Shader definiert. Sie werden nach einer Sequenz bearbeitet, die als Multipass in der Shadertoy -Nomenklatur bezeichnet wird. Der letzte der definierten Shader wird auf den Bildschirm rendern. Die Ausgabe früherer Shader, einschließlich der Rückkopplungsschleife des vorherigen Frame, kann leicht an Uniformen übergeben werden.
Es werden mehrere Validierungen für die mitgelieferte Konfiguration durchgeführt, um häufige Probleme zu vermeiden, die in der Regel ansonsten schwer zu debuggen sind. Der SRC/Test/HTML/Fehler/Ordner enthält alle Fehler -Testfälle, die auch auf der Live -Demo der Fehlerbehandlung überprüft werden können.
Alle Fehler und Warnungen sind auf der Konsole sichtbar.
Sehen:
// 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 )
}
}
}
} ) ; HINWEIS: Erste Mauskoordinaten finden Sie in der onInit -Funktion, da das erste mousemove -Ereignis lange nach dem Start des Shaders stattfinden kann. Shader -Koordinaten beginnen in der unteren linken Ecke der Leinwand und sind mit der Mitte des Pixels ausgerichtet - (0.5, 0.5) .
API -Referenz:
Demos:
python -m http.server 8000 Wenn es nicht auf Ihrem neuesten Ubuntu funktioniert, als sudo apt install python-is-python3 ausführen.
Siehe Textur: Blue Marmor to Flat Earth Mapping Demo
Texturen können auf die gleiche Weise eingestellt werden, wie Puffer als Uniformen festgelegt werden, aber zuerst müssen wir sie laden. Zum Beispiel durch Definieren von benutzerdefiniertem Versprechen, das wiederverwendet werden kann:
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 ;
} ) ; Die onInit -Funktion ist ein bequemer Ort für das Aufrufen 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 )
}
}
}
} ) ; Diese Bibliothek kann Shadertoy -Code mit minimalem Aufwand verwenden - eine einfache Shader -Wraping:
< 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 > Das id -Attribut des <script> wird so eingestellt, dass Shadertoy -Registerkarte als Image reflektiert wird. Die meisten Shader verwenden mindestens diese 2 Uniformen, und es ist einfach, ihre Werte in der Konfiguration bereitzustellen:
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 ) ,
}
}
}
} ) ;Shadertoy -Demos:
Dafür gibt es keine automatisierte Lösung. Sie müssen den Common Teil direkt in Ihre Shader kopieren, direkt über dem anderen Shadertoy -Code.
texture ? In Shadertoy -Texturen werden mit der texture zugegriffen, während es in WebGL 1 texture2D ist. Hier ist eine einfache Problemumgehung, die vor dem ursprünglichen Code hinzugefügt werden muss:
#define texture texture2D In Shadertoy kann jede "Kanal" -Bindung eine Textur separate Sampler -Parameter wie Interpolation oder Verpackung haben. Diese Funktionalität kann nicht einfach auf WebGL 1 portiert werden, aber die meisten Shader, die diese Funktionen weitergeben, können mit codebasierten Problemumgehungen angepasst werden. Wenn beispielsweise die Textur wiederholt werden soll, kann so etwas ein funktionaler Austausch der texture in einem bestimmten Shader sein:
vec4 repeatedTexture( in sampler2D channel, in vec2 uv) {
return texture2D (channel, mod (uv, 1 .));
}Siehe auch API - Shader: Textur.
Sie können Ihre Shader nach Shadertoy -Puffernamen nennen:
BufferABufferBBufferCBufferDImageUnd dann verdrahten Sie sie zusammen:
<!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 ist möglich, den Standard -Scheitelpunkt -Shader für jeden Fragment -Shader zu ändern, indem das folgende Skript im <head> angegeben wird:
< 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 > HINWEIS: Der type ist auf x-shader/x-vertex eingestellt und das id Attribut wird mit Vertex Suffix vorbereitet. Das Scheitelpunktattribut sollte V .
Hinweis: varying vec2 uv kann angegeben werden, um zwischen Scheitelpunkt- und Fragment -Shadern (standardmäßig nicht hinzugefügt) zu teilen.
git clone https://github.com/xemantic/shader-web-background.git
cd shader-web-background
./gradlew compileJsDer Compiler von Google Closure wird ausgelöst, mit dem Quellen mithilfe von Typinformationen überprüft und in minifiedes JavaScript -Dateien umgewandelt werden:
Dieses Projekt wurde unter Verwendung von Intellij IDEA mit Google-Java-Format-Plugin aktiviert. Das auffälligste Element dieses Stils sind 2 Leerzeichen anstelle von 4 für das Rendern von Registerkarten.
Entweder:
<section id="projects-using-shader-web-background"> Index.html und scrollenOder senden Sie mir einen Link mit Beschreibung.