Отображает фрагментные шейдеры GLSL в качестве фона веб -сайта. Поддерживает шейдеры Shadertoy, Multiass-Ping-Pong Buffers, петли обратной связи, текстуры с плавающей точкой. Либо с WebGL 1 или 2, попытается работать везде, где это технически возможно.
Веб -сайт/Демо :? https://xemantic.github.io/shader-web-background?
❔ ??? Чтобы задать вопросы, перейдите на сервер Xemantic Discord ☕ ???
Я разработал эту библиотеку для использования сложных фрагментных шейдеров в рамках моего веб -дизайна и процесса разработки. Это инструмент, который, наконец, позволяет мне принять веб -браузер в качестве творческой среды кодирования. Если вы знакомы с GLSL, то это может помочь вам опубликовать вашу работу в Интернете. Если вы приезжаете из фона веб -разработки, то вы можете сначала узнать немного больше о шейдерах, например, из книги шейдеров. Я надеюсь, что примеры, представленные в этой документации, являются самоэкспланирующими. Если вы найдете это полезным, тогда
❤ Спонсор Xemanty на GitHub или https://www.buymeacoffee.com/kazik
Казик (Морисил) Погода
https://xemanty.com/
Оглавление
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 >Если вы предпочитаете учиться примером, вот список демонстраций, отображаемых с их выделенным исходным кодом:
https://xemantic.github.io/shader-web-background/#demo
Есть несколько способов настройки этой библиотеки к вашим потребностям:
Если вы хотите, чтобы ваши шейдеры начали рендеринг до того, как будут загружены какие -либо другие ресурсы, перейдите к этому методу. Просто возьмите содержимое:
https://xemantic.github.io/shader-web-background/dist/shader-web-background.min.js
и поместите его как <script> в <head> вашего HTML -файла.
См. Минимальную демонстрацию для справки (живая версия).
Добавьте этот код в <head> вашего HTML:
< script src =" https://xemantic.github.io/shader-web-background/dist/shader-web-background.min.js " > </ script > В будущем я опубликую shader-web-background в NPM. На данный момент вы можете просто загрузить последнее минимизированное распространение вместе с исходной картой и источниками.
Вам понадобится хотя бы один фрагментный шейдер, определяемый так:
< script type =" x-shader/x-fragment " id =" image " >
precision highp float ;
void main ( ) {
// ...
}
</ script > Поместите это в <head> вашего HTML. type должен быть x-shader/x-fragment , а атрибут id является произвольным.
id каждому из ваших шейдеров, если вы определяете их больше.
< script >
shaderWebBackground.shade( {
shaders : {
image : { }
}
} );
</ script >image имени шейдера должно соответствовать тому, что определено как атрибут id источника шейдера.
Этот шаг не является необходимым, однако добавив, что он улучшит опыт для небольшого количества пользователей, которые до сих пор не могут запускать шейдеры на своих устройствах.
Определите Starkback CSS -стиль, например, статический скриншот вашего шейдера:
< style >
.shader-web-background-fallback {
background: url("https://placekitten.com/666/666");
background-position: center;
background-size: cover;
background-attachment: fixed;
}
</ style > Класс CSS shader-web-background-fallback применяется к root html документа и холста.
shader-web-background-fallback , однако он может не работать на некоторых браузерах. Пользовательский обработчик ошибок может понадобиться для совместимости перекрестия.
Смотрите раздел ошибок обработки для деталей.
Смотрите полную API Shader-Web-Background
Объект конфигурации, переданный на вызов ShaderWebbackground.Shade (config) в приведенном выше примере, приведет к минимальному конвейеру рендеринга, состоящему из одного фрагментного шейдера с именем image . Новый статический <canvas id="shader-web-background"> Элемент, покрывающий весь порт просмотра, будет добавлен на страницу с z-index: -9999 , который будет отображаться за другими элементами страницы.
Примечание. Элемент по умолчанию <canvas> будет прикреплен к документу <body> только тогда, когда будет построено все дерево DOM. Кроме того, фактическое рендеринг кадров шейдеров не произойдет до тех пор, пока страница не будет полностью загружена, даже если шейдеры будут скомпилированы немедленно.
Униформа обеспечивает шейдеры с вводом из мира за пределами графического процессора. Описание этого механизма выходит за рамки этой документации. Я решил не создавать абстракцию над этой частью WebGL, потому что это уже довольно кратко. См. WebGlrenderingContext.Uniform Documentation.
Давайте предположим, что вы хотите предоставить свой шейдер с значением времени, измеренным за секунды с момента загрузки страницы. Сначала определите форму в шейдере image :
uniform float iTime; Имя iTime произвольное, но оно должно соответствовать тому, что вы указываете в конфигурации:
shaderWebBackground . shade ( {
shaders : {
image : {
uniforms : {
iTime : ( gl , loc ) => gl . uniform1f ( loc , performance . now ( ) / 1000 )
}
}
}
} ) ; Функция (gl, loc) => gl.uniform1f(loc, performance.now() / 1000) будет вызвана перед рендерингом каждой кадры шейдера. Если вы не знакомы с функциями стрелки JavaScript, это эквивалентно:
function ( gl , loc ) {
gl . uniform1f ( loc , performance . now ( ) / 1000 )
} Проверьте документацию стандартной функции javaScript.now (), которая возвращает количество миллисекунд с момента загрузки страницы. Разделение на 1000 приведет к тому, что значение с плавающей точкой измеряется за секунды.
Резюме: Вы можете использовать этот механизм для адаптации любого API в качестве ввода ваших шейдеров. Проверьте демонстрации проекта на наличие примеров, как интегрировать ввод, например:
В объявлении «Текстуры» униформ использует тип sampler2D :
uniform sampler2D iWebCam; Единое имя произвольно. Например, Shadertoy является привязкой текстур под именем iChannel0 , iChannel1 и т. Д., И это соглашение, используемое в основном в этой документации.
Такая униформа может быть установлена:
shaderWebBackground . shade ( {
onInit : ( ctx ) => {
ctx . iWebCam = initializeTexture ( ctx . gl ) ;
} ,
shaders : {
image : {
uniforms : {
iWebCam : ( gl , loc , ctx ) => ctx . texture ( loc , ctx . iWebCam ) ;
}
}
}
} ) ;Текстура , передаваемая как второй аргумент в CTX.Texture, может быть либо экземпляром WebGlTexture, либо ссылкой на буфер другого шейдера в трубопроводе. Проверьте комплексный пример конфигурации и API - контекст: буферы.
См. Раздел «Добавление текстур» для получения подробной информации о том, как загрузить текстуру с изображения.
Все шейдеры, за исключением последнего в трубопроводе, будут иметь связанные текстуры, с которыми сталкиваются. По умолчанию эти текстуры инициализируются как RGBA HALF_FLOAT (16bit) с плавающей точкой с линейной интерполяцией и зажимаются до края. Инициализация текстуры может быть настроена. См. API - Шейдер: документация по текстуре для деталей.
Вот полный пример объекта конфигурации с комментариями. Он использует соглашения Shadertoy для именования буферов и униформы, но имейте в виду, что именование является произвольным и может быть скорректировано с учетом потребностей вашего проекта.
// 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" ) ;
}
} ) ; API предназначен для того, чтобы быть самостоятельным. Проверьте спецификацию API для деталей. Есть несколько шейдеров, определенных в примере выше. Они будут обрабатываться в последовательности, называемой Multipass в номенклатуре Shadertoy. Последний из определенных шейдеров будет отображаться на экране. Выход предыдущих шейдеров, включая петлю обратной связи предыдущей кадра, отображаемой тем же шейдером, можно легко передавать в униформу.
Несколько валидаций выполняются на поставленной конфигурации, чтобы избежать общих проблем, которые обычно трудно отлаживать иначе. SRC/TEST/HTML/ошибки/папка содержит все тестовые случаи ошибок, которые также можно проверить на живой демонстрации обработки ошибок.
Все ошибки и предупреждения будут видны на консоли.
Видеть:
// 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 )
}
}
}
} ) ; ПРИМЕЧАНИЕ. Начальные координаты мыши представлены в функции onInit , потому что первое событие mousemove может произойти еще долго после начала шейдера. Координаты шейдера начинаются в левом нижнем углу холста и выровнены с серединой пикселя - (0.5, 0.5) .
Ссылка на API:
Демо:
python -m http.server 8000 если он не работает на вашем последнем Ubuntu, чем запустить sudo apt install python-is-python3 в первую очередь.
См. Текстура: синий мрамор в плоскую землю картирование демонстрации
Текстуры могут быть установлены таким же образом, как буферы устанавливаются как униформа, но сначала нам нужно загрузить их. Например, определяя пользовательское обещание, которое можно повторно использовано:
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 ;
} ) ; Функция onInit - довольно удобное место для вызова 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 )
}
}
}
} ) ; Эта библиотека может использовать код Шадертоя с минимальными усилиями - простая упаковка шейдера:
< 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 > Атрибут id на вкладке <script> для отражения вкладки Shadertoy под названием Image . Большинство шейдеров будут использовать по крайней мере эти 2 униформы, и легко предоставить их значения в конфигурации:
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:
Для этого нет автоматического решения. Вам придется скопировать Common часть непосредственно в свои шейдеры, чуть выше другого кода Шадертоя.
texture ? В Shadertoy текстуры доступны с функцией texture , в то время как в WebGL 1 это texture2D . Вот простой обходной путь, который будет добавлен перед исходным кодом:
#define texture texture2D В Shadertoy каждый «канал» привязка текстура может иметь отдельные параметры пробоотборника, такие как интерполяция или обертка. Эта функциональность не может быть легко перенесена в WebGL 1, но большинство шейдеров, передавающихся по этим функциям, можно скорректировать с помощью обходных путей на основе кода. Например, если текстура должна повторяться, то что -то подобное может быть функциональной заменой функции texture в данном шейдере:
vec4 repeatedTexture( in sampler2D channel, in vec2 uv) {
return texture2D (channel, mod (uv, 1 .));
}Смотрите также API - Шейдер: Текстура.
Вы можете назвать свои шейдеры в соответствии с именами буферов Shadertoy:
BufferABufferBBufferCBufferDImageА затем подключите их вместе:
<!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 > Можно изменить шейдер Vertex Default для каждого фрагментного шейдера, предоставив следующий сценарий в <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 > Примечание. type сценария устанавливается в x-shader/x-vertex , а атрибут id приготовлен с Vertex суффикс. Атрибут Vertex должен быть назван V
ПРИМЕЧАНИЕ. Из -за того, varying vec2 uv может быть указано, чтобы быть разделенным между вершиной и фрагментными шейдерами (не добавленным по умолчанию).
git clone https://github.com/xemantic/shader-web-background.git
cd shader-web-background
./gradlew compileJsЭто запустит компилятор Google закрытия, который проверит источники, используя информацию типа и переносит их в файлы с минимизированным JavaScript:
Этот проект был разработан с использованием INTELLIJ IDEA с включенным плагином Google-Java-формата. Наиболее заметным элементом этого стиля являются 2 места вместо 4 для рендеринга.
Или:
<section id="projects-using-shader-web-background">Или пришлите мне ссылку с описанием.