Skip to content

Commit 885336e

Browse files
committed
custom vertex shader support
1 parent 67680c7 commit 885336e

6 files changed

+214
-155
lines changed

README.md

+28
Original file line numberDiff line numberDiff line change
@@ -742,6 +742,34 @@ And then wire them together:
742742
</html>
743743
```
744744

745+
## Own vertex shader
746+
747+
It's possible to alter default vertex shader for each fragment shader by providing
748+
the following script in the `<head>`:
749+
750+
```javascript
751+
<script type="x-shader/x-vertex" id="shaderIdVertex">
752+
attribute vec2 V;
753+
varying vec2 uv;
754+
755+
void main(){
756+
gl_Position=vec4(V,0,1);
757+
}
758+
</script>
759+
<script type="x-shader/x-fragment" id="shaderId">
760+
// ...
761+
varying vec2 uv;
762+
// ...
763+
</script>
764+
```
765+
766+
:information_source: Note: the script `type` is set to `x-shader/x-vertex` and the
767+
`id` attribute is prepended with `Vertex` suffix. The vertex attribute should be named
768+
`V`.
769+
770+
:information_source: Note: `varying vec2 uv` can be specified to be shared between vertex
771+
and fragment shaders (not added by default).
772+
745773

746774
## General tips
747775

demo/minimal.html

+48-46
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
<meta http-equiv="X-UA-Compatible" content="IE=edge">
2727
<script>
2828
// -- https://xemantic.github.io/shader-web-background/
29-
const shaderWebBackground={};(()=>{'use strict';const r=(a,b)=>{b.initHalfFloatRGBATexture(b.width,b.height);a.texParameteri(a.TEXTURE_2D,
29+
const shaderWebBackground={};(()=>{'use strict';const t=(a,b)=>{b.initHalfFloatRGBATexture(b.width,b.height);a.texParameteri(a.TEXTURE_2D,
3030
a.TEXTURE_MIN_FILTER,a.LINEAR);a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MAG_FILTER,
3131
a.LINEAR);a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_S,a.CLAMP_TO_EDGE);a.texParameteri(a.TEXTURE_2D,
3232
a.TEXTURE_WRAP_T,a.CLAMP_TO_EDGE)},x=(a,b)=>{console.warn("shader-web-background cannot shade, adding fallback CSS classes");
@@ -38,79 +38,81 @@
3838
return a}
3939
function A(){const a=document.createElement("canvas"),b=a.style;a.id="shader-web-background";b.width=
4040
"100vw";b.height="100vh";b.position="fixed";b.top="0";b.left="0";b.zIndex=-9999;return a}
41-
const B=a=>'<script type="x-shader/x-fragment" id="'+a+'">';
42-
function D(a){const b=document.getElementById(a);y(b,"Missing shader source: "+B(a));
43-
y(b instanceof HTMLScriptElement&&"x-shader/x-fragment"===b.type,'Shader source element of id "'+
44-
a+'" should be of type: '+B(a));return b.text}
45-
function E(a,b){"loading"!==document.readyState?b():window.addEventListener(a,b)}
46-
class F{constructor(a,b,c,d){this.g=c;const k=a.gl;this.h=()=>{for(const f of d)f.u(k,
41+
function B(a,b,c){y(a instanceof HTMLScriptElement&&a.type===b,'Shader source element of id "'+
42+
c+'" should be of type: <script type="'+(b+'" id="'+c+'">'))}
43+
function D(a){const b=document.getElementById(a);y(b,'Missing shader source: <script type="x-shader/x-fragment" id="'+
44+
(a+'">'));B(b,"x-shader/x-fragment",a);return b.text}
45+
function E(a){a+="Vertex";const b=document.getElementById(a);return b?(B(b,"x-shader/x-vertex",
46+
a),b.text):"attribute vec2 V;void main(){gl_Position=vec4(V,0,1);}"}
47+
function F(a,b){"loading"!==document.readyState?b():window.addEventListener(a,b)}
48+
class G{constructor(a,b,c,d){this.g=c;const l=a.gl;this.h=()=>{for(const f of d)f.u(l,
4749
f.location,b)};this.i=()=>{var f=c.v,h=a.gl;h.bindBuffer(h.ARRAY_BUFFER,a.j);h.enableVertexAttribArray(f);
4850
h.vertexAttribPointer(f,2,h.FLOAT,!1,0,0);h.drawArrays(h.TRIANGLE_STRIP,0,4);h.disableVertexAttribArray(f);
4951
h.bindBuffer(h.ARRAY_BUFFER,null);f=a.gl;for(h=0;h<a.g;h++)f.activeTexture(f.TEXTURE0+
5052
h),f.bindTexture(f.TEXTURE_2D,null);a.g=0}}}
51-
function G(a){var b={antialias:!1,depth:!1,alpha:!1};try{return new H(a,b)}catch(c){throw new shaderWebBackground.GlError(c.message);
53+
function H(a){var b={antialias:!1,depth:!1,alpha:!1};try{return new I(a,b)}catch(c){throw new shaderWebBackground.GlError(c.message);
5254
}}
53-
function I(a,b,c,d,k,f){function h(e,m){try{{var n=q;const p=n.gl,v=J(n,e,p.VERTEX_SHADER,"attribute vec2 V;void main(){gl_Position=vec4(V,0,1);}"),
54-
O=J(n,e,p.FRAGMENT_SHADER,m),u=p.createProgram();p.attachShader(u,v);p.attachShader(u,
55-
O);p.linkProgram(u);var l=u}return l}catch(p){throw new shaderWebBackground.ConfigError(p.message);
56-
}}const q=G(a),w=[],g={gl:q.gl,canvas:a,width:0,height:0,cssPixelRatio:0,cssWidth:0,
55+
function J(a,b,c,d,l,f){function h(e,m,n){try{{var k=p;const q=k.gl,P=K(k,e,q.VERTEX_SHADER,m),
56+
Q=K(k,e,q.FRAGMENT_SHADER,n),v=q.createProgram();q.attachShader(v,P);q.attachShader(v,
57+
Q);q.linkProgram(v);var r=v}return r}catch(q){throw new shaderWebBackground.ConfigError(q.message);
58+
}}const p=H(a),w=[],g={gl:p.gl,canvas:a,width:0,height:0,cssPixelRatio:0,cssWidth:0,
5759
cssHeight:0,isOverShader:(e,m)=>{const n=a.getBoundingClientRect();return e>=n.left&&
5860
e<=n.right&&m>=n.top&&m<=n.bottom},toShaderX:e=>(e-a.getBoundingClientRect().left)*
5961
g.cssPixelRatio+.5,toShaderY:e=>a.height-(e-a.getBoundingClientRect().top)*g.cssPixelRatio-
6062
.5,s:()=>g.cssWidth!==a.clientWidth||g.cssHeight!==a.clientHeight?(g.resize(),!0):
6163
!1,resize:()=>{const e=window.devicePixelRatio||1,m=a.clientWidth,n=a.clientHeight,
62-
l=Math.floor(m*e),p=Math.floor(n*e);a.width=l;a.height=p;g.width=l;g.height=p;g.cssPixelRatio=
63-
e;g.cssWidth=m;g.cssHeight=n;q.gl.viewport(0,0,q.canvas.width,q.canvas.height);for(const v of w)v.g.l(l,
64-
p)},texture:(e,m)=>{{var n=q;const l=n.gl;m=m instanceof K?m.g:m;l.activeTexture(l.TEXTURE0+
65-
n.g);l.bindTexture(l.TEXTURE_2D,m);l.uniform1i(e,n.g++)}},buffers:{},initHalfFloatRGBATexture:(e,
66-
m)=>{q.h.g(e,m)}},P=Object.keys(b).length-1;let Q=0;for(const e in b){if(Q++<P){const l=
67-
b[e].texture||r;g.buffers[e]=L(q,()=>{l(q.gl,g)})}const m=M(q,h(e,D(e)),g.buffers[e]),
68-
n=b[e].uniforms||{};var t=Object.keys(n);for(const l of m.m)y(n[l.name],'No configuration for uniform "'+
69-
l.name+'" defined in shader "'+e+'"'),t=t.filter(p=>p!==l.name);0!==t.length&&console.warn('Extra uniforms configured for shader "'+
64+
k=Math.floor(m*e),r=Math.floor(n*e);a.width=k;a.height=r;g.width=k;g.height=r;g.cssPixelRatio=
65+
e;g.cssWidth=m;g.cssHeight=n;p.gl.viewport(0,0,p.canvas.width,p.canvas.height);for(const q of w)q.g.l(k,
66+
r)},texture:(e,m)=>{{var n=p;const k=n.gl;m=m instanceof L?m.g:m;k.activeTexture(k.TEXTURE0+
67+
n.g);k.bindTexture(k.TEXTURE_2D,m);k.uniform1i(e,n.g++)}},buffers:{},initHalfFloatRGBATexture:(e,
68+
m)=>{p.h.g(e,m)}},R=Object.keys(b).length-1;let S=0;for(const e in b){if(S++<R){const k=
69+
b[e].texture||t;g.buffers[e]=M(p,()=>{k(p.gl,g)})}const m=N(p,h(e,E(e),D(e)),g.buffers[e]),
70+
n=b[e].uniforms||{};var u=Object.keys(n);for(const k of m.m)y(n[k.name],'No configuration for uniform "'+
71+
k.name+'" defined in shader "'+e+'"'),u=u.filter(r=>r!==k.name);0!==u.length&&console.warn('Extra uniforms configured for shader "'+
7072
e+'", which are not present in the shader code - might have been removed by GLSL compiler if not used: '+
71-
t.join(", "));t=m.m.map(l=>({location:l.location,u:n[l.name]}));w.push(new F(q,g,
72-
m,t))}const C=()=>{g.s()&&d&&d(g.width,g.height,g);k&&k(g);for(const e of w)e.g.i(e.h,
73-
e.i);f&&f(g);requestAnimationFrame(C)};E("load",()=>{g.resize();c&&c(g);d&&d(g.width,
73+
u.join(", "));u=m.m.map(k=>({location:k.location,u:n[k.name]}));w.push(new G(p,g,
74+
m,u))}const C=()=>{g.s()&&d&&d(g.width,g.height,g);l&&l(g);for(const e of w)e.g.i(e.h,
75+
e.i);f&&f(g);requestAnimationFrame(C)};F("load",()=>{g.resize();c&&c(g);d&&d(g.width,
7476
g.height,g);requestAnimationFrame(C)});return g}
7577
shaderWebBackground.Error=class extends Error{constructor(a){super(a);this.name="shaderWebBackground.Error"}};
7678
shaderWebBackground.ConfigError=class extends shaderWebBackground.Error{constructor(a){super(a);
7779
this.name="shaderWebBackground.ConfigError"}};
7880
shaderWebBackground.GlError=class extends shaderWebBackground.Error{constructor(a){super(a);this.name=
7981
"shaderWebBackground.GlError"}};
8082
shaderWebBackground.shade=function(a){y(a,"Missing config argument");const b=a.canvas?
81-
z(a.canvas):A();y(a.shaders,"No shaders specified in config");try{const c=I(b,a.shaders,
82-
a.onInit,a.onResize,a.onBeforeFrame,a.onAfterFrame);a.canvas||E("DOMContentLoaded",
83-
()=>{document.body.appendChild(b)});return c}catch(c){(a.onError||x)(c,b)}};const N=[-1,1,1,1,-1,-1,1,-1];
84-
function R(a,b){return a.j(a.gl.getExtension(b),b+" extension is not supported")}
85-
class S{constructor(a,b){this.gl=a;this.j=b}g(){}}
86-
class T extends S{constructor(a,b){super(a,b);this.h=R(this,"OES_texture_half_float");
87-
R(this,"OES_texture_half_float_linear")}g(a,b){const c=this.gl;c.texImage2D(c.TEXTURE_2D,
83+
z(a.canvas):A();y(a.shaders,"No shaders specified in config");try{const c=J(b,a.shaders,
84+
a.onInit,a.onResize,a.onBeforeFrame,a.onAfterFrame);a.canvas||F("DOMContentLoaded",
85+
()=>{document.body.appendChild(b)});return c}catch(c){(a.onError||x)(c,b)}};const O=[-1,1,1,1,-1,-1,1,-1];
86+
function T(a,b){return a.j(a.gl.getExtension(b),b+" extension is not supported")}
87+
class U{constructor(a,b){this.gl=a;this.j=b}g(){}}
88+
class V extends U{constructor(a,b){super(a,b);this.h=T(this,"OES_texture_half_float");
89+
T(this,"OES_texture_half_float_linear")}g(a,b){const c=this.gl;c.texImage2D(c.TEXTURE_2D,
8890
0,c.RGBA,a,b,0,c.RGBA,this.h.HALF_FLOAT_OES,null)}}
89-
class U extends S{constructor(a,b){super(a,b);R(this,"EXT_color_buffer_float");this.gl.getExtension("OES_texture_float_linear")}g(a,
91+
class W extends U{constructor(a,b){super(a,b);T(this,"EXT_color_buffer_float");this.gl.getExtension("OES_texture_float_linear")}g(a,
9092
b){const c=this.gl;c.texImage2D(c.TEXTURE_2D,0,c.RGBA16F,a,b,0,c.RGBA,c.HALF_FLOAT,
9193
null)}}
92-
function V(a){a=a.split(/\r?\n/);const b=a.length.toString().length;var c=[];a.forEach((d,
93-
k)=>{k=(k+1).toString();k=k.length>=b?k:" ".repeat(b-k.length)+k;c.push(k+": "+d+
94-
"\n")});return c.join("")}function L(a,b){return new K(a.gl,()=>{b(a.gl)})}
95-
function M(a,b,c){const d=a.gl;a=[];const k=d.getProgramParameter(b,d.ACTIVE_UNIFORMS);
96-
for(let f=0;f<k;f++){const h=d.getActiveUniform(b,f);a.push({name:h.name,location:d.getUniformLocation(b,
94+
function X(a){a=a.split(/\r?\n/);const b=a.length.toString().length;var c=[];a.forEach((d,
95+
l)=>{l=(l+1).toString();l=l.length>=b?l:" ".repeat(b-l.length)+l;c.push(l+": "+d+
96+
"\n")});return c.join("")}function M(a,b){return new L(a.gl,()=>{b(a.gl)})}
97+
function N(a,b,c){const d=a.gl;a=[];const l=d.getProgramParameter(b,d.ACTIVE_UNIFORMS);
98+
for(let f=0;f<l;f++){const h=d.getActiveUniform(b,f);a.push({name:h.name,location:d.getUniformLocation(b,
9799
h.name)})}return{v:d.getAttribLocation(b,"V"),m:a,l:c?(f,h)=>c.l(f,h):()=>{},i:(f,
98100
h)=>{d.useProgram(b);f();c?(f=c.g,c.g=c.h,c.h=f,c.i(h)):h()}}}
99-
function J(a,b,c,d){a=a.gl;c=a.createShader(c);a.shaderSource(c,d);a.compileShader(c);
100-
if(!a.getShaderParameter(c,a.COMPILE_STATUS)){const k=String(a.getShaderInfoLog(c));
101-
a.deleteShader(c);b="Cannot compile shader - "+b+": "+k;console.log(b);console.log(V(d));
101+
function K(a,b,c,d){a=a.gl;c=a.createShader(c);a.shaderSource(c,d);a.compileShader(c);
102+
if(!a.getShaderParameter(c,a.COMPILE_STATUS)){const l=String(a.getShaderInfoLog(c));
103+
a.deleteShader(c);b="Cannot compile shader - "+b+": "+l;console.log(b);console.log(X(d));
102104
throw Error(b);}return c}
103-
class H{constructor(a,b){this.canvas=a;const c=(k,f)=>{if(!k)throw Error(f);return k};
104-
let d=a.getContext("webgl2",b);if(d)this.h=new U(d,c);else if(d=a.getContext("webgl",
105-
b))this.h=new T(d,c);c(d,"webgl context not supported on supplied canvas element: "+
105+
class I{constructor(a,b){this.canvas=a;const c=(l,f)=>{if(!l)throw Error(f);return l};
106+
let d=a.getContext("webgl2",b);if(d)this.h=new W(d,c);else if(d=a.getContext("webgl",
107+
b))this.h=new V(d,c);c(d,"webgl context not supported on supplied canvas element: "+
106108
a);this.gl=d;a=d.createBuffer();d.bindBuffer(d.ARRAY_BUFFER,a);d.bufferData(d.ARRAY_BUFFER,
107-
new Float32Array(N),d.STATIC_DRAW);d.bindBuffer(d.ARRAY_BUFFER,null);this.j=a;this.buffers=
109+
new Float32Array(O),d.STATIC_DRAW);d.bindBuffer(d.ARRAY_BUFFER,null);this.j=a;this.buffers=
108110
{};this.g=0}}
109-
function W(a){const b=a.gl,c=b.createTexture();b.bindTexture(b.TEXTURE_2D,c);a.o(b);
111+
function Y(a){const b=a.gl,c=b.createTexture();b.bindTexture(b.TEXTURE_2D,c);a.o(b);
110112
b.bindTexture(b.TEXTURE_2D,null);return c}
111-
class K{constructor(a,b){this.j=a.createFramebuffer();this.gl=a;this.o=b;this.g=this.h=
113+
class L{constructor(a,b){this.j=a.createFramebuffer();this.gl=a;this.o=b;this.g=this.h=
112114
null}l(){this.h&&this.gl.deleteTexture(this.h);this.g&&this.gl.deleteTexture(this.g);
113-
this.h=W(this);this.g=W(this)}i(a){const b=this.gl;b.bindFramebuffer(b.FRAMEBUFFER,
115+
this.h=Y(this);this.g=Y(this)}i(a){const b=this.gl;b.bindFramebuffer(b.FRAMEBUFFER,
114116
this.j);b.framebufferTexture2D(b.FRAMEBUFFER,b.COLOR_ATTACHMENT0,b.TEXTURE_2D,this.g,
115117
0);a();b.framebufferTexture2D(b.FRAMEBUFFER,b.COLOR_ATTACHMENT0,b.TEXTURE_2D,null,
116118
0);b.bindFramebuffer(b.FRAMEBUFFER,null)}};})()

0 commit comments

Comments
 (0)