Fragment shader, just math - no framework. JS window is webgl bootstrap and texture loading/attaching to canvas. HTML window is the fragment and vertex shaders. Basically I'm making a 3D scene that is projected on the canvas by using distance fields (mathematical formulas that represent an object.)
Created
November 17, 2021 08:19
-
-
Save LeetCodes/1c7f7cc53e0d99382b64679f55fb9e3a to your computer and use it in GitHub Desktop.
Cube Mapped Box/WebGL Fragment Shader
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- VertexShader code here --> | |
<script id="vertexShader" type="x-shader/x-vertex">#version 300 es | |
precision highp float; | |
in vec2 a_texCoord; | |
in vec4 vPosition; | |
out vec2 v_texcoord; | |
void main() { | |
gl_Position = vPosition; | |
v_texcoord = a_texCoord; | |
} | |
</script> | |
<!-- FragmentShader code here --> | |
<script id="fragmentShader" type="x-shader/x-fragment">#version 300 es | |
#if __VERSION__ < 130 | |
#define TEXTURE2D texture2D | |
#else | |
#define TEXTURE2D texture | |
#endif | |
precision highp float; | |
out vec4 fragColor; | |
uniform sampler2D iChannel0; | |
uniform sampler2D iChannel1; | |
uniform sampler2D iChannel2; | |
uniform sampler2D iChannel3; | |
uniform vec2 v_texCoord; | |
uniform vec4 mouse; | |
uniform vec2 resolution; | |
uniform float time; | |
#define R resolution | |
#define T time | |
#define M mouse | |
#define PI 3.14159265359 | |
#define PI2 6.28318530718 | |
#define MAX_DIST 100. | |
#define MIN_DIST .0001 | |
float hash21(vec2 p){ return fract(sin(dot(p,vec2(26.34,45.32)))*4324.23); } | |
mat2 rot(float a){ return mat2(cos(a),sin(a),-sin(a),cos(a)); } | |
float vmax(vec3 p){ return max(max(p.x,p.y),p.z); } | |
//@iq | |
float cap( vec3 p, float h, float r ){ | |
vec2 d = abs(vec2(length(p.xz),p.y)) - vec2(h,r); | |
return min(max(d.x,d.y),0.0) + length(max(d,0.0)); | |
} | |
//@iq | |
float vcap( vec3 p, float h, float r ){ | |
p.y -= clamp( p.y, 0.0, h ); | |
return length( p ) - r; | |
} | |
float modPolar(inout vec2 p, float rep) { | |
float angle = 2.*PI/rep; | |
float a = atan(p.y, p.x) + angle/2.; | |
float c = floor(a/angle); | |
a = mod(a,angle) - angle/2.; | |
p = vec2(cos(a), sin(a))*length(p); | |
return (abs(c) >= (rep/2.)) ? abs(c) : c; | |
} | |
float box(vec3 p, vec3 b){ | |
vec3 d = abs(p) - b; | |
return length(max(d,vec3(0))) + vmax(min(d,vec3(0))); | |
} | |
vec3 hit=vec3(0),hitPoint=vec3(0); | |
mat2 ria,gia,turn,spin; | |
const float sz = 3.; | |
const float hf = sz*.5; | |
vec2 map(vec3 pos, float sg){ | |
vec2 res = vec2(1e5,0.); | |
pos.y+=1.25;; | |
vec3 q = pos-vec3(0,2.5,0); | |
vec3 b = pos-vec3(0,1.05,0); | |
q.yx*=spin; | |
q.zx*=spin; | |
float d1 = box(q,vec3(1.5))-.0423; | |
if(d1<res.x){ | |
res = vec2(d1,2.); | |
hit=q; | |
} | |
b.xz=abs(abs(abs(b.xz)-12.)-6.)-3.; | |
vec3 hitb = b; | |
float pillar = cap(b,.3,1.5); | |
vec3 tb =vec3(b.x,abs(b.y),b.z); | |
float pcap = box(tb-vec3(0,1.45,0),vec3(.5,.15,.5))-.005; | |
pcap=min(cap(tb-vec3(0,1.3,0),.4,.05),pcap); | |
modPolar(b.xz,16.); | |
vec3 bt = b-vec3(.3,-1.1,0); | |
float grv = vcap(bt,2.2,.045); | |
pillar = max(pillar,-grv); | |
pillar = min(pcap,pillar); | |
if(pillar<res.x) | |
{ | |
res = vec2(pillar*.75,3.); | |
hit=hitb; | |
} | |
float ground =pos.y+.5; | |
if(ground<res.x){ | |
res = vec2(ground,1.); | |
hit=pos; | |
} | |
return res; | |
} | |
vec3 normal(vec3 p, float t){ | |
float e = MIN_DIST*t; | |
vec2 h =vec2(1,-1)*.5773; | |
vec3 n = h.xyy * map(p+h.xyy*e,0.).x+ | |
h.yyx * map(p+h.yyx*e,0.).x+ | |
h.yxy * map(p+h.yxy*e,0.).x+ | |
h.xxx * map(p+h.xxx*e,0.).x; | |
return normalize(n); | |
} | |
vec2 marcher(vec3 ro, vec3 rd, int maxsteps, float sg){ | |
float d = 0.; | |
float m = 0.; | |
for(int i=0;i<maxsteps;i++){ | |
vec2 ray = map(ro + rd * d, sg); | |
if(ray.x<MIN_DIST*d||d>MAX_DIST) break; | |
d += ray.x * .85; | |
m = ray.y; | |
} | |
return vec2(d,m); | |
} | |
// Tri-Planar blending function. GPU Gems 3 - Ryan Geiss: | |
vec3 tex3D(sampler2D t, in vec3 p, in vec3 n ){ | |
n = max(abs(n), MIN_DIST); | |
n /= dot(n, vec3(1)); | |
vec3 tx = texture(t, p.yz).xyz; | |
vec3 ty = texture(t, p.zx).xyz; | |
vec3 tz = texture(t, p.xy).xyz; | |
return mat3(tx*tx, ty*ty, tz*tz)*n; | |
//return (tx*tx*n.x + ty*ty*n.y + tz*tz*n.z); | |
} | |
float sface; | |
vec3 getFace(int face, vec3 p){ | |
float cir = 0.; | |
vec2 uv; | |
if(face==0) uv=p.yz; | |
if(face==1) uv=p.zx; | |
if(face==2) uv=p.xy; | |
if(face==3) uv=p.xy; | |
if(face==4) uv=p.xz; | |
if(face==5) uv=p.zy; | |
uv*=2.; | |
float px = fwidth(uv.x); | |
vec2 grid_uv = fract(uv)-.5; | |
vec2 grid_id = floor(uv); | |
float chk = mod(grid_id.y + grid_id.x,2.) * 2. - 1.; | |
float hs = hash21(grid_id); | |
if(hs>.5) grid_uv.x*=-1.; | |
vec2 d2 = vec2(length(grid_uv-.5), length(grid_uv+.5)); | |
vec2 gx = d2.x<d2.y? vec2(grid_uv-.5) : vec2(grid_uv+.5); | |
float circle = length(gx)-.5; | |
float circle2 =abs(circle)-.025; | |
circle2=smoothstep(.001+px,-px,circle2); | |
circle=(chk>0.^^ hs>.5)?smoothstep(-px,.001+px,circle):smoothstep(.001+px,-px,circle); | |
cir= mix(cir,.0,circle); | |
cir= mix(cir,1.,circle2); | |
sface=mix(0.,1.,circle); | |
return vec3(cir); | |
} | |
// based on bmp mapping from | |
// https://www.shadertoy.com/view/ld3yDn | |
vec3 doBumpMap( vec3 p, vec3 n, float bf, float per, int face){ | |
vec2 e = vec2(per*MIN_DIST, 0); | |
mat3 m = mat3( | |
getFace(face, p - e.xyy), | |
getFace(face, p - e.yxy), | |
getFace(face, p - e.yyx) | |
); | |
vec3 g = vec3(0.299, 0.587, 0.114) * m; | |
g = (g - dot(getFace(face, p), vec3(0.299, 0.587, 0.114)) )/e.x; g -= n*dot(n, g); | |
return normalize( n + g*bf ); | |
} | |
vec4 FC = vec4(0.019,0.019,0.019,0.); | |
vec4 render(inout vec3 ro, inout vec3 rd, inout vec3 ref, bool last, inout float d, vec2 uv) { | |
vec3 C = vec3(0); | |
vec2 ray = marcher(ro,rd,128, 1.); | |
hitPoint = hit; | |
gia=ria; | |
d = ray.x; | |
float m = ray.y; | |
float alpha = 0.; | |
if(d<MAX_DIST) | |
{ | |
vec3 p = ro + rd * d; | |
vec3 n = normal(p,d); | |
vec3 lpos =vec3(3.,8,3.); | |
vec3 lpos2 =vec3(5.,5,-5.); | |
vec3 l = normalize(lpos-p); | |
vec3 l2 = normalize(lpos2-p); | |
vec3 h = vec3(.5); | |
vec3 hp = hitPoint; | |
vec3 cuv; | |
int face; | |
vec3 tn = n; | |
vec3 cn = n; | |
if(m==2.){ | |
tn = n; | |
tn.yx*=spin; | |
tn.zx*=spin; | |
//https://www.shadertoy.com/view/3sVBDd | |
//finding the face of a cube using normal | |
vec3 aN = abs(tn); | |
ivec3 idF = ivec3(tn.x<-.25? 0 : 5, tn.y<-.25? 1 : 4, tn.z<-.25? 2 : 3); | |
face = aN.x>.5? idF.x : aN.y>.5? idF.y : idF.z; | |
// set coords | |
if(face==0) cuv = hp.xyz; | |
if(face==1) cuv = hp.xyz; | |
if(face==2) cuv = hp.xyz; | |
if(face==3) cuv = hp.xyz; | |
if(face==4) cuv = hp.zyx; | |
if(face==5) cuv = hp.xyz; | |
// get bump map surface | |
n=doBumpMap( cuv, n, .05, d, face); | |
} | |
float diff = clamp(dot(n,l),0.,1.); | |
float diff2 = clamp(dot(n,l2),0.,1.); | |
float fresnel = pow(clamp(1.+dot(rd, n), 0., 1.), 9.); | |
fresnel = mix(.01, .7, fresnel); | |
float shdw = 1.0; | |
for( float t=.01; t < 11.; ) | |
{ | |
float h = map(p + l*t,0.).x; | |
if( h<MIN_DIST ) { shdw = 0.; break; } | |
shdw = min(shdw, 16.*h/t); | |
t += h; | |
if( shdw<MIN_DIST || t>32. ) break; | |
} | |
float shdw2 = 1.0; | |
for( float t=.01; t < 11.; ) | |
{ | |
float h = map(p + l2*t,0.).x; | |
if( h<MIN_DIST ) { shdw2 = 0.; break; } | |
shdw2 = min(shdw2, 16.*h/t); | |
t += h; | |
if( shdw2<MIN_DIST || t>32. ) break; | |
} | |
diff = mix(diff,diff*shdw,.75); | |
diff2 = mix(diff2,diff2*shdw2,.75); | |
vec3 diffMix =vec3(0); | |
diffMix = diff * vec3(0.502,0.290,0.000); | |
diffMix += diff2 * vec3(0.004,0.510,0.894); | |
vec3 view = normalize(p - ro); | |
vec3 ret = reflect(normalize(lpos), n); | |
float spec = 0.5 * pow(max(dot(view, ret), 0.), (m==2.||m==4.)?24.:64.); | |
// materials | |
if(m==1.){ | |
h=tex3D(iChannel1,hitPoint*.25,n).rgb; | |
C = (diffMix*h); | |
ref = vec3(clamp(.35-fresnel-(d*.01),.01,1.)); | |
} | |
if(m==2.){ | |
h = mix(tex3D(iChannel0,cuv*.55,tn).rgb, tex3D(iChannel2,cuv*.75,tn).rgb ,sface); | |
C = (diffMix*h)+spec; | |
ref = vec3(clamp(sface-fresnel,.01,.9)); | |
} | |
if(m==3.){ | |
h=clamp(tex3D(iChannel2,hitPoint*.5,tn).rrr+.5+fresnel,vec3(0),vec3(.8));//vec3(.2); | |
C = (diffMix*h); | |
ref = clamp((h-fresnel)-.5,vec3(0),vec3(1)); | |
} | |
C = mix(FC.rgb,C,exp(-.00015*d*d*d)); | |
ro = p+n*.001; | |
rd = reflect(rd,n); | |
} else { | |
if(last) C = mix(FC.rgb,C,exp(-.000015*d*d*d)); | |
} | |
C = clamp(C,vec3(0),vec3(1)); | |
return vec4(C,alpha); | |
} | |
void main() | |
{ | |
float timer = T*04.*PI/180.; | |
turn = rot(timer); | |
spin = rot(T*15.*PI/180.); | |
vec2 F = gl_FragCoord.xy; | |
vec2 uv = (2.*F.xy-R.xy)/max(R.x,R.y); | |
vec3 ro = vec3(0,0,7.75); | |
vec3 rd = normalize(vec3(uv,-1)); | |
//mouse | |
float x = M.xy == vec2(0) ? 0. : -(M.y/R.y * 1. - .5) * PI; | |
float y = M.xy == vec2(0) ? 0. : -(M.x/R.x * 1. - .5) * PI; | |
if(x<-.15)x=-.15; | |
mat2 rx = rot(x+.1); | |
mat2 ry = rot(y+timer); | |
ro.yz *= rx; | |
rd.yz *= rx; | |
ro.xz *= ry; | |
rd.xz *= ry; | |
// reflection loop (@BigWings) | |
vec3 C = vec3(0); | |
vec3 ref=vec3(0), fil=vec3(1); | |
float d =0.; | |
float numBounces = 2.; | |
// 3 is pretty but slows down | |
for(float i=0.; i<numBounces; i++) { | |
vec4 pass = render(ro, rd, ref, i==numBounces-1., d, uv); | |
C += pass.rgb*fil; | |
fil*=ref; | |
if(i==0.) FC = vec4(FC.rgb,exp(-.000075*d*d*d)); | |
} | |
C = mix(C,FC.rgb,1.-FC.w); | |
// gamma | |
C = clamp(C,vec3(0),vec3(1)); | |
C = pow(C, vec3(.4545)); | |
fragColor = vec4(C,1.); | |
} | |
</script> | |
<div id="container" /> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Mouse Class for movments and attaching to dom // | |
class Mouse { | |
constructor(element) { | |
this.element = element || window; | |
this.drag = false; | |
this.x = | |
~~(document.documentElement.clientWidth, window.innerWidth || 0) / 2; | |
this.y = | |
~~(document.documentElement.clientHeight, window.innerHeight || 0) / 2; | |
this.pointer = this.pointer.bind(this); | |
this.getCoordinates = this.getCoordinates.bind(this); | |
this.events = ["mouseenter", "mousemove"]; | |
this.events.forEach((eventName) => { | |
this.element.addEventListener(eventName, this.getCoordinates); | |
}); | |
this.element.addEventListener("mousedown", () => { | |
this.drag = true; | |
}); | |
this.element.addEventListener("mouseup", () => { | |
this.drag = false; | |
}); | |
} | |
reset = () => { | |
this.x = | |
~~(document.documentElement.clientWidth, window.innerWidth || 0) / 2; | |
this.y = | |
~~(document.documentElement.clientHeight, window.innerHeight || 0) / 2; | |
}; | |
getCoordinates(event) { | |
event.preventDefault(); | |
const x = event.pageX; | |
const y = event.pageY; | |
if (this.drag) { | |
this.x = x; | |
this.y = y; | |
} | |
} | |
pointer() { | |
return { | |
x: this.x, | |
y: this.y | |
}; | |
} | |
} | |
const woodTexture = "https://assets.codepen.io/163598/tile01.jpg"; | |
const rockTexture = "https://assets.codepen.io/163598/texture3.jpg"; | |
const stoneTexture = "https://assets.codepen.io/163598/texture2.jpg"; | |
const textureList = [stoneTexture, woodTexture, rockTexture]; | |
// Boostrap for WebGL and Attaching Shaders // | |
// Fragment & Vertex Shaders in HTML window // | |
class Render { | |
constructor() { | |
this.start = Date.now(); | |
this.umouse = [0.0, 0.0, 0.0, 0.0]; | |
this.tmouse = [0.0, 0.0, 0.0, 0.0]; | |
// Setup WebGL canvas and surface object // | |
// Make Canvas and get WebGl2 Context // | |
let width = (this.width = ~~(document.documentElement.clientWidth, | |
window.innerWidth || 0)); | |
let height = (this.height = ~~(document.documentElement.clientHeight, | |
window.innerHeight || 0)); | |
const canvas = (this.canvas = document.createElement("canvas")); | |
const container = document.getElementById("container"); | |
canvas.id = "GLShaders"; | |
canvas.width = width; | |
canvas.height = height; | |
this.mouse = new Mouse(canvas); | |
document.body.appendChild(canvas); | |
const gl = (this.gl = canvas.getContext("webgl2")); | |
if (!gl) { | |
console.warn("WebGL 2 is not available."); | |
return; | |
} | |
// WebGl and WebGl2 Extension // | |
this.gl.getExtension("OES_standard_derivatives"); | |
this.gl.getExtension("EXT_shader_texture_lod"); | |
this.gl.getExtension("OES_texture_float"); | |
this.gl.getExtension("WEBGL_color_buffer_float"); | |
this.gl.getExtension("OES_texture_float_linear"); | |
this.gl.viewport(0, 0, canvas.width, canvas.height); | |
// always nice to let people resize | |
window.addEventListener( | |
"resize", | |
() => { | |
let width = ~~(document.documentElement.clientWidth, | |
window.innerWidth || 0); | |
let height = ~~(document.documentElement.clientHeight, | |
window.innerHeight || 0); | |
this.mouse.reset(); | |
this.canvas.width = width; | |
this.canvas.height = height; | |
this.gl.viewport(0, 0, this.canvas.width, this.canvas.height); | |
this.resolution = new Float32Array([width, height]); | |
this.gl.uniform2fv( | |
this.gl.getUniformLocation(this.program, "resolution"), | |
this.resolution | |
); | |
this.clearCanvas(); | |
}, | |
false | |
); | |
this.init(); | |
} | |
// Shader Bootstrap code // | |
createShader = (type, source) => { | |
const shader = this.gl.createShader(type); | |
this.gl.shaderSource(shader, source); | |
this.gl.compileShader(shader); | |
const success = this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS); | |
if (!success) { | |
console.log(this.gl.getShaderInfoLog(shader)); | |
this.gl.deleteShader(shader); | |
return false; | |
} | |
return shader; | |
}; | |
createWebGL = (vertexSource, fragmentSource, images) => { | |
// Setup Vertext/Fragment Shader functions | |
this.vertexShader = this.createShader(this.gl.VERTEX_SHADER, vertexSource); | |
this.fragmentShader = this.createShader( | |
this.gl.FRAGMENT_SHADER, | |
fragmentSource | |
); | |
// Setup Program and Attach Shader functions | |
this.program = this.gl.createProgram(); | |
this.gl.attachShader(this.program, this.vertexShader); | |
this.gl.attachShader(this.program, this.fragmentShader); | |
this.gl.linkProgram(this.program); | |
this.gl.useProgram(this.program); | |
if (!this.gl.getProgramParameter(this.program, this.gl.LINK_STATUS)) { | |
console.warn( | |
"Unable to initialize the shader program: " + | |
this.gl.getProgramInfoLog(this.program) | |
); | |
return null; | |
} | |
// Create and Bind buffer // | |
const buffer = this.gl.createBuffer(); | |
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, buffer); | |
this.gl.bufferData( | |
this.gl.ARRAY_BUFFER, | |
new Float32Array([-1, 1, -1, -1, 1, -1, 1, 1]), | |
this.gl.STATIC_DRAW | |
); | |
const vPosition = this.gl.getAttribLocation(this.program, "vPosition"); | |
this.gl.enableVertexAttribArray(vPosition); | |
this.gl.vertexAttribPointer( | |
vPosition, | |
2, // size: 2 components per iteration | |
this.gl.FLOAT, // type: the data is 32bit floats | |
false, // normalize: don't normalize the data | |
0, // stride: 0 = move forward size * sizeof(type) each iteration to get the next position | |
0 // start at the beginning of the buffer | |
); | |
this.clearCanvas(); | |
this.importUniforms(images); | |
}; | |
/** | |
Textures | |
*/ | |
isPowerOf2 = (value) => { | |
return (value & (value - 1)) == 0; | |
}; | |
getImage = (url) => { | |
return new Promise((resolve, reject) => { | |
let img = new Image(); | |
img.crossOrigin = "Anonymous"; | |
img.addEventListener("load", (e) => resolve(img)); | |
img.addEventListener("error", () => { | |
reject(new Error(`Failed to load image's URL: ${url}`)); | |
}); | |
img.src = url; | |
}); | |
}; | |
loadTexture = (textureList) => { | |
const lockNames = [ | |
this.gl.TEXTURE0, | |
this.gl.TEXTURE1, | |
this.gl.TEXTURE2, | |
this.gl.TEXTURE3 | |
]; | |
const textureOptions = [ | |
[this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE], | |
[this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE], | |
[this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST], | |
[this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST] | |
]; | |
let promises = textureList.map((item) => this.getImage(item)); | |
Promise.all(promises).then((images) => { | |
const amount = images.length; | |
let textures = []; | |
for (let ii = 0; ii < amount; ++ii) { | |
const texture = this.gl.createTexture(); | |
this.gl.bindTexture(this.gl.TEXTURE_2D, texture); | |
// Upload the image into the texture. | |
this.gl.texImage2D( | |
this.gl.TEXTURE_2D, | |
0, | |
this.gl.RGBA, | |
this.gl.RGBA, | |
this.gl.UNSIGNED_BYTE, | |
images[ii] | |
); | |
if ( | |
this.isPowerOf2(images[ii].width) && | |
this.isPowerOf2(images[ii].height) | |
) { | |
this.gl.generateMipmap(this.gl.TEXTURE_2D); | |
} else { | |
// Set the parameters so we can render any size image. | |
this.gl.texParameteri(...textureOptions[0]); | |
this.gl.texParameteri(...textureOptions[1]); | |
this.gl.texParameteri(...textureOptions[2]); | |
this.gl.texParameteri(...textureOptions[3]); | |
} | |
// add the texture to the array of textures. | |
textures.push(texture); | |
} | |
// lookup the sampler locations. | |
const u_image0Location = this.gl.getUniformLocation( | |
this.program, | |
"iChannel0" | |
); | |
const u_image1Location = this.gl.getUniformLocation( | |
this.program, | |
"iChannel1" | |
); | |
const u_image2Location = this.gl.getUniformLocation( | |
this.program, | |
"iChannel2" | |
); | |
// set which texture units to render with. | |
this.gl.uniform1i(u_image0Location, 0); // texture unit 0 | |
this.gl.uniform1i(u_image1Location, 1); // texture unit 1 | |
this.gl.uniform1i(u_image2Location, 2); // texture unit 1 | |
this.gl.activeTexture(this.gl.TEXTURE0); | |
this.gl.bindTexture(this.gl.TEXTURE_2D, textures[0]); | |
this.gl.activeTexture(this.gl.TEXTURE1); | |
this.gl.bindTexture(this.gl.TEXTURE_2D, textures[1]); | |
this.gl.activeTexture(this.gl.TEXTURE2); | |
this.gl.bindTexture(this.gl.TEXTURE_2D, textures[2]); | |
}); | |
console.log("done loading textures"); | |
}; | |
clearCanvas = () => { | |
this.gl.clearColor(0, 0, 0, 0); | |
this.gl.clear(this.gl.COLOR_BUFFER_BIT); | |
}; | |
// add other uniforms here | |
importUniforms = (images) => { | |
const width = ~~(document.documentElement.clientWidth, | |
window.innerWidth || 0); | |
const height = ~~(document.documentElement.clientHeight, | |
window.innerHeight || 0); | |
this.resolution = new Float32Array([width, height]); | |
this.gl.uniform2fv( | |
this.gl.getUniformLocation(this.program, "resolution"), | |
this.resolution | |
); | |
// get the uniform ins from the shader fragments | |
this.ut = this.gl.getUniformLocation(this.program, "time"); | |
this.ms = this.gl.getUniformLocation(this.program, "mouse"); | |
this.loadTexture(images); | |
}; | |
// things that need to be updated per frame | |
updateUniforms = () => { | |
let tm = (Date.now() - this.start) / 1000; | |
//prevent time from getting too big | |
if (tm > 2000) this.start = Date.now(); | |
this.gl.uniform1f(this.ut, (Date.now() - this.start) / 1000); | |
const mouse = this.mouse.pointer(); | |
this.umouse = [mouse.x, this.canvas.height - mouse.y, 0]; | |
const factor = 0.15; | |
this.tmouse[0] = | |
this.tmouse[0] - (this.tmouse[0] - this.umouse[0]) * factor; | |
this.tmouse[1] = | |
this.tmouse[1] - (this.tmouse[1] - this.umouse[1]) * factor; | |
this.tmouse[2] = this.mouse.drag ? 1 : 0; | |
this.gl.uniform4fv(this.ms, this.tmouse); | |
this.gl.drawArrays( | |
this.gl.TRIANGLE_FAN, // primitiveType | |
0, // Offset | |
4 // Count | |
); | |
}; | |
// setup shaders and send to render loop | |
init = () => { | |
this.createWebGL( | |
document.getElementById("vertexShader").textContent, | |
document.getElementById("fragmentShader").textContent, | |
textureList | |
); | |
this.renderLoop(); | |
}; | |
renderLoop = () => { | |
this.updateUniforms(); | |
this.animation = window.requestAnimationFrame(this.renderLoop); | |
}; | |
} | |
const demo = new Render(document.body); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
html { | |
height: 100%; | |
} | |
img { | |
display: none; | |
} | |
body { | |
background: #000; | |
overflow: hidden; | |
padding: 0; | |
margin: 0; | |
width: 100%; | |
height: 100%; | |
text-align: center; | |
} | |
canvas { | |
height: 100%; | |
width: 100%; | |
margin: auto; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment