Created
March 20, 2020 09:21
-
-
Save 9re/5f869b0470315f5cdf790b074e427974 to your computer and use it in GitHub Desktop.
vernal equinox: 2 webcam + midi + shader study
This file contains 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
import {initGLSLCode} from './glslcode'; | |
const fragment = `#ifdef GL_ES | |
precision mediump float; | |
#endif | |
uniform float time; | |
uniform vec2 mouse; | |
uniform vec2 resolution; | |
uniform float scale; | |
uniform float timeScale; | |
uniform float strength; | |
uniform float rotation; | |
uniform float mr; | |
uniform float tx; | |
uniform float ty; | |
uniform sampler2D channel0; | |
uniform sampler2D channel1; | |
float random (in vec2 st) { | |
return fract(sin(dot(st.xy, | |
vec2(12.9898,78.233))) | |
* 43758.5453123); | |
} | |
float noise(vec2 st) { | |
vec2 i = floor(st); | |
vec2 f = fract(st); | |
vec2 u = f*f*(3.0-2.0*f); | |
return mix( mix( random( i + vec2(0.0,0.0) ), | |
random( i + vec2(1.0,0.0) ), u.x), | |
mix( random( i + vec2(0.0,1.0) ), | |
random( i + vec2(1.0,1.0) ), u.x), u.y); | |
} | |
mat2 rotate2d(float angle){ | |
return mat2(cos(angle),-sin(angle), | |
sin(angle),cos(angle)); | |
} | |
void triangularCoord(vec2 u, vec2 st, out vec4 color) { | |
u = mod(u, 1.0); | |
if (u.x + u.y < 1.0) { | |
color = texture2D(channel0, st); | |
} else { | |
color = texture2D(channel1, st); | |
} | |
} | |
void hexCoord(vec2 u, vec2 st, out vec4 color) { | |
u -= 1.0; | |
u = mod(u, 3.0); | |
if (u.x < 1.0 && u.y < 1.0 || u.y < 1.0 && u.x + u.y < 2.0 || | |
u.x > 1.0 && u.x < 2.0 && u.y > 2.0 || u.x < 1.0 && u.x + u.y > 3.0) { | |
color = texture2D(channel0, st); | |
} else if (u.x > 1.0 && u.x < 2.0 && u.y > 1.0 && u.y < 2.0 || u.x > 2.0 && u.y < 1.0|| | |
u.x < 2.0 && u.y < 1.0 && u.x + u.y > 2.0 || u.x > 2.0 && u.y > 1.0 && u.x + u.y < 4.0) { | |
color = texture2D(channel1, st); | |
} else { | |
color = texture2D(channel1, st); | |
color.g *= 0.8; | |
color.b *= 0.8; | |
color.a = 0.9; | |
color * 1.1; | |
} | |
} | |
const mat2 triangle = mat2(1., 0., -1./sqrt(3.), 2./sqrt(3.)); | |
void main() | |
{ | |
vec2 st = gl_FragCoord.xy/resolution.xy; | |
vec2 pos = st * scale - (scale - 1.0) / 2.0; | |
pos = rotate2d(noise(pos + time * timeScale) * strength) * pos; | |
pos = -pos + vec2(tx, ty); | |
vec2 p = vec2(pos); | |
p.y *= resolution.y / resolution.x; | |
vec2 u = triangle * rotate2d(rotation) * p; | |
st = 1.0 - st; | |
vec4 c0, c1; | |
triangularCoord(u, st, c0); | |
hexCoord(u, st, c1); | |
gl_FragColor = mix(c0, c1, mr); | |
} | |
`; | |
console.log(fragment.split("\n").map((x,i) => `${i+1}\t${x}`).join("\n")); | |
navigator.requestMIDIAccess().then(onMidi, midiFailed); | |
var midi = null; | |
var inputs = []; | |
function onMidi(m){ | |
console.log("asd"); | |
midi = m; | |
const it = midi.inputs.values(); | |
for(let o = it.next(); !o.done; o = it.next()){ | |
inputs.push(o.value); | |
} | |
for(let cnt=0;cnt < inputs.length;cnt++){ | |
inputs[cnt].onmidimessage = onMIDIEvent; | |
} | |
} | |
function midiFailed(msg){ | |
console.log("[Error]:"+msg); | |
} | |
const midiValues = {}; | |
function onMIDIEvent(e){ | |
console.log(JSON.stringify(e.data)); | |
let data = e.data; | |
midiValues[data[0] + ':' + data[1]] = data[2]; | |
} | |
const videos = []; | |
function createTexture(gl, src) { | |
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); | |
return texture; | |
} | |
function createVideo(stream) { | |
const video = document.createElement('video'); | |
video.width = window.innerWidth; | |
video.height = window.innerHeight; | |
video.preload = 'auto'; | |
video.autoload = true; | |
video.autoplay = true; | |
video.style.display = 'none'; | |
// document.body.appendChild(video); | |
video.srcObject = stream; | |
return video; | |
} | |
let count = 0; | |
let handleSuccess = function(i, stream) { | |
videos[i] = createVideo(stream); | |
videos[i].addEventListener('play', () => { | |
if (++count === 2) { | |
start(); | |
} | |
}); | |
}; | |
function start() { | |
const myDiv = document.getElementById('myDiv'); | |
const canvas = document.createElement('canvas'); | |
canvas.setAttribute('width', '800'); | |
canvas.setAttribute('height', '800'); | |
myDiv.appendChild(canvas); | |
let texture0, texture1, channel0, channel1, scale, timeScale, strength, tx, ty, rotation, mr; | |
const callback = (program, gl) => { | |
if (texture0 === undefined) { | |
texture0 = createTexture(gl, videos[0]); | |
texture1 = createTexture(gl, videos[1]); | |
scale = gl.getUniformLocation(program, 'scale'); | |
timeScale = gl.getUniformLocation(program, 'timeScale'); | |
strength = gl.getUniformLocation(program, 'strength'); | |
tx = gl.getUniformLocation(program, 'tx'); | |
ty = gl.getUniformLocation(program, 'ty'); | |
rotation = gl.getUniformLocation(program, 'rotation'); | |
mr = gl.getUniformLocation(program, 'mr'); | |
channel0 = gl.getUniformLocation(program, 'channel0'); | |
channel1 = gl.getUniformLocation(program, 'channel1'); | |
} | |
if (midiValues['176:7']) { | |
gl.uniform1f(scale, midiValues['176:7'] / 127 * 32.0 + 1.0); | |
} else { | |
gl.uniform1f(scale, 1.0); | |
} | |
if (midiValues['177:7']) { | |
gl.uniform1f(timeScale, midiValues['177:7'] / 127 * 1.2 + .1); | |
} else { | |
gl.uniform1f(timeScale, .3); | |
} | |
if (midiValues['178:7']) { | |
gl.uniform1f(strength, midiValues['178:7'] / 127 * 2.5); | |
} else { | |
gl.uniform1f(strength, 0); | |
} | |
if (midiValues['179:7']) { | |
gl.uniform1f(tx, midiValues['179:7'] / 127); | |
} else { | |
gl.uniform1f(tx, 0); | |
} | |
if (midiValues['180:7']) { | |
gl.uniform1f(ty, midiValues['180:7'] / 127); | |
} else { | |
gl.uniform1f(ty, 0); | |
} | |
if (midiValues['181:7']) { | |
gl.uniform1f(rotation, midiValues['181:7'] / 127 * 5 * Math.PI / 6); | |
} else { | |
gl.uniform1f(rotation, 0); | |
} | |
if (midiValues['182:7']) { | |
gl.uniform1f(mr, midiValues['182:7'] / 127); | |
} else { | |
gl.uniform1f(mr, 0); | |
} | |
gl.uniform1i(channel0, 0); | |
gl.uniform1i(channel1, 1); | |
gl.activeTexture(gl.TEXTURE0); | |
gl.bindTexture(gl.TEXTURE_2D, texture0); | |
updateTexture(gl, texture0, videos[0]); | |
gl.activeTexture(gl.TEXTURE1); | |
gl.bindTexture(gl.TEXTURE_2D, texture1); | |
updateTexture(gl, texture1, videos[1]); | |
}; | |
initGLSLCode(canvas, fragment, {callback}); | |
} | |
var width = window.innerWidth; | |
var height = window.innerHeight; | |
navigator.mediaDevices.enumerateDevices() | |
.then(function(devices) { | |
devices.filter(device => device.kind === 'videoinput') | |
.forEach((device, i) => { | |
navigator.mediaDevices.getUserMedia({ | |
video: {facingMode: "environment", width: width, height: height, deviceId: {exact: device.deviceId}}, | |
audio: false | |
}).then(stream => handleSuccess(i, stream)) | |
.catch(err => { | |
console.error(err); | |
console.log(JSON.stringify(err)); | |
}); | |
}); | |
}); | |
function updateTexture(gl, texture, src) { | |
const level = 0; | |
const internalFormat = gl.RGBA; | |
const srcFormat = gl.RGBA; | |
const srcType = gl.UNSIGNED_BYTE; | |
gl.bindTexture(gl.TEXTURE_2D, texture); | |
gl.texImage2D(gl.TEXTURE_2D, level, internalFormat, srcFormat, srcType, src); | |
} |
This file contains 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
export function initGLSLCode(canvasElement, fs, options) { | |
var quality = 1, quality_levels = [ 0.5, 1, 2, 4, 8 ]; | |
var canvas, gl, buffer, currentProgram, vertexPosition, screenVertexPosition, | |
parameters = { startTime: Date.now(), time: 0, mouseX: 0.5, mouseY: 0.5, screenWidth: 0, screenHeight: 0 }, | |
surface = { centerX: 0, centerY: 0, width: 1, height: 1, isPanning: false, isZooming: false, lastX: 0, lastY: 0 }, | |
frontTarget, backTarget, screenProgram, getWebGL, resizer = {}, compileOnChangeCode = true, renderCallback, | |
textureIndex, canvasMetrics, onResize; | |
var image = new Image(); | |
function init() { | |
canvas = canvasElement; | |
if (options) { | |
renderCallback = options.callback; | |
canvasMetrics = options.canvasMetrics; | |
onResize = options.onResize | |
} | |
if (!document.addEventListener) { | |
document.location = 'http://get.webgl.org/'; | |
return; | |
} | |
// | |
try { | |
gl = canvas.getContext( 'experimental-webgl', { preserveDrawingBuffer: true } ); | |
} catch( error ) { } | |
if (!gl) { | |
alert("WebGL not supported, but code will be shown."); | |
} else { | |
buffer = gl.createBuffer(); | |
gl.bindBuffer( gl.ARRAY_BUFFER, buffer ); | |
gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( [ - 1.0, - 1.0, 1.0, - 1.0, - 1.0, 1.0, 1.0, - 1.0, 1.0, 1.0, - 1.0, 1.0 ] ), gl.STATIC_DRAW ); | |
// Create surface buffer (coordinates at screen corners) | |
surface.buffer = gl.createBuffer(); | |
} | |
resizer.offsetMouseX = 0; | |
resizer.offsetMouseY = 0; | |
resizer.isResizing = false; | |
resizer.currentWidth = 100; | |
resizer.currentHeight = 100; | |
resizer.minWidth = 100; | |
resizer.minHeight = 100; | |
resizer.maxWidth = 100; | |
resizer.maxHeight = 100; | |
resizer.element = document.createElement( 'div' ); | |
resizer.element.className = 'resizer'; | |
resizer.element.addEventListener( 'mousedown', function ( event ) { | |
if (event.button !== 2) { | |
resizer.offsetMouseX = event.clientX - resizer.currentWidth; | |
resizer.offsetMouseY = event.clientY - resizer.currentHeight; | |
resizer.isResizing = true; | |
event.preventDefault(); | |
} | |
}, false ); | |
if (gl) { | |
var surfaceMouseDown = function ( event ) { | |
if (event.shiftKey) { | |
resetSurface(); | |
} | |
if (event.button === 0) { | |
surface.isPanning = true; | |
document.body.style.cursor = 'move'; | |
} else { | |
surface.isZooming = true; | |
document.body.style.cursor = 'se-resize'; | |
} | |
surface.lastX = event.clientX; | |
surface.lastY = event.clientY; | |
event.preventDefault(); | |
}; | |
var noContextMenu = function ( event ) { | |
event.preventDefault(); | |
}; | |
canvas.addEventListener( 'mousedown', surfaceMouseDown, false ); | |
canvas.addEventListener( 'contextmenu', noContextMenu, false); | |
} | |
var clientXLast, clientYLast; | |
document.addEventListener( 'mousemove', function ( event ) { | |
var clientX = event.clientX; | |
var clientY = event.clientY; | |
if (clientXLast == clientX && clientYLast == clientY) | |
return; | |
clientXLast = clientX; | |
clientYLast = clientY; | |
var codeElement, dx, dy; | |
parameters.mouseX = clientX / window.innerWidth; | |
parameters.mouseY = 1 - clientY / window.innerHeight; | |
if (resizer.isResizing) { | |
resizer.currentWidth = Math.max(Math.min(clientX - resizer.offsetMouseX, resizer.maxWidth), resizer.minWidth); | |
resizer.currentHeight = Math.max(Math.min(clientY - resizer.offsetMouseY, resizer.maxHeight), resizer.minWidth); | |
event.preventDefault(); | |
} else if (surface.isPanning) { | |
dx = clientX - surface.lastX; | |
dy = clientY - surface.lastY; | |
surface.centerX -= dx * surface.width / window.innerWidth; | |
surface.centerY += dy * surface.height / window.innerHeight; | |
surface.lastX = clientX; | |
surface.lastY = clientY; | |
computeSurfaceCorners(); | |
event.preventDefault(); | |
} else if (surface.isZooming) { | |
dx = clientX - surface.lastX; | |
dy = clientY - surface.lastY; | |
surface.height *= Math.pow(0.997, dx + dy); | |
surface.lastX = clientX; | |
surface.lastY = clientY; | |
computeSurfaceCorners(); | |
event.preventDefault(); | |
} | |
}, false ); | |
function settleDown ( event ) { | |
resizer.isResizing = surface.isPanning = surface.isZooming = false; | |
document.body.style.cursor = 'default'; | |
} | |
function mouseLeave(event) { | |
settleDown(event); | |
} | |
document.addEventListener( 'mouseup', settleDown, false ); | |
document.addEventListener( 'mouseleave', mouseLeave, false ); | |
onWindowResize(); | |
window.addEventListener( 'resize', onWindowResize, false ); | |
compileScreenProgram(); | |
compile(fs); | |
if (gl) { animate(); } | |
} | |
function computeSurfaceCorners() { | |
if (gl) { | |
surface.width = surface.height * parameters.screenWidth / parameters.screenHeight; | |
var halfWidth = surface.width * 0.5, halfHeight = surface.height * 0.5; | |
gl.bindBuffer( gl.ARRAY_BUFFER, surface.buffer ); | |
gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( [ | |
surface.centerX - halfWidth, surface.centerY - halfHeight, | |
surface.centerX + halfWidth, surface.centerY - halfHeight, | |
surface.centerX - halfWidth, surface.centerY + halfHeight, | |
surface.centerX + halfWidth, surface.centerY - halfHeight, | |
surface.centerX + halfWidth, surface.centerY + halfHeight, | |
surface.centerX - halfWidth, surface.centerY + halfHeight ] ), gl.STATIC_DRAW ); | |
} | |
} | |
function resetSurface() { | |
surface.centerX = surface.centerY = 0; | |
surface.height = 1; | |
computeSurfaceCorners(); | |
} | |
function compile(fragment) { | |
if (!gl) { | |
if (!getWebGL) { | |
getWebGL = true; | |
} | |
return; | |
} | |
var program = gl.createProgram(); | |
//var fragment = document.getElementById('flarefs').textContent; | |
var vertex = (["attribute vec3 position;", | |
"attribute vec2 surfacePosAttrib;", | |
"varying vec2 surfacePosition;", | |
"void main() {", | |
" surfacePosition = surfacePosAttrib;", | |
" gl_Position = vec4( position, 1.0 );", | |
"}"]).join('\n'); | |
var vs = createShader( vertex, gl.VERTEX_SHADER ); | |
var fs = createShader( fragment, gl.FRAGMENT_SHADER ); | |
if ( vs == null || fs == null ) return null; | |
gl.attachShader( program, vs ); | |
gl.attachShader( program, fs ); | |
gl.deleteShader( vs ); | |
gl.deleteShader( fs ); | |
gl.linkProgram( program ); | |
if ( !gl.getProgramParameter( program, gl.LINK_STATUS ) ) { | |
var error = gl.getProgramInfoLog(program); | |
console.error(error); | |
console.error('VALIDATE_STATUS: ' + gl.getProgramParameter( program, gl.VALIDATE_STATUS ), 'ERROR: ' + gl.getError()); | |
return; | |
} | |
if (currentProgram) { | |
//gl.deleteProgram(currentProgram); | |
} | |
currentProgram = program; | |
// Cache uniforms | |
cacheUniformLocation( program, 'time' ); | |
cacheUniformLocation( program, 'mouse' ); | |
cacheUniformLocation( program, 'resolution' ); | |
cacheUniformLocation( program, 'backbuffer' ); | |
cacheUniformLocation( program, 'surfaceSize' ); | |
cacheUniformLocation( program, 'profile0'); | |
// Load program into GPU | |
gl.useProgram( currentProgram ); | |
// Set up buffers | |
surface.positionAttribute = gl.getAttribLocation(currentProgram, "surfacePosAttrib"); | |
gl.enableVertexAttribArray(surface.positionAttribute); | |
vertexPosition = gl.getAttribLocation(currentProgram, "position"); | |
gl.enableVertexAttribArray( vertexPosition ); | |
}; | |
function compileScreenProgram() { | |
if (!gl) { return; } | |
var program = gl.createProgram(); | |
var fragment = (["#ifdef GL_ES", | |
"precision mediump float;", | |
"#endif", | |
"uniform vec2 resolution;", | |
"uniform sampler2D texture;", | |
"void main() {", | |
" vec2 uv = gl_FragCoord.xy / resolution.xy;", | |
" gl_FragColor = texture2D( texture, uv );", | |
"}"]).join('\n'); | |
var vertex = (["attribute vec3 position;", | |
"void main() {", | |
" gl_Position = vec4( position, 1.0 );", | |
"}"]).join('\n'); | |
var vs = createShader( vertex, gl.VERTEX_SHADER ); | |
var fs = createShader( fragment, gl.FRAGMENT_SHADER ); | |
gl.attachShader( program, vs ); | |
gl.attachShader( program, fs ); | |
gl.deleteShader( vs ); | |
gl.deleteShader( fs ); | |
gl.linkProgram( program ); | |
if ( !gl.getProgramParameter( program, gl.LINK_STATUS ) ) { | |
console.error( 'VALIDATE_STATUS: ' + gl.getProgramParameter( program, gl.VALIDATE_STATUS ), 'ERROR: ' + gl.getError() ); | |
return; | |
} | |
screenProgram = program; | |
gl.useProgram( screenProgram ); | |
cacheUniformLocation( program, 'resolution' ); | |
cacheUniformLocation( program, 'texture' ); | |
screenVertexPosition = gl.getAttribLocation(screenProgram, "position"); | |
gl.enableVertexAttribArray( screenVertexPosition ); | |
} | |
function cacheUniformLocation( program, label ) { | |
if ( program.uniformsCache === undefined ) { | |
program.uniformsCache = {}; | |
} | |
program.uniformsCache[ label ] = gl.getUniformLocation( program, label ); | |
} | |
// | |
function createTarget( width, height ) { | |
var target = {}; | |
target.framebuffer = gl.createFramebuffer(); | |
target.renderbuffer = gl.createRenderbuffer(); | |
target.texture = gl.createTexture(); | |
// set up framebuffer | |
gl.bindTexture( gl.TEXTURE_2D, target.texture ); | |
gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null ); | |
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_MAG_FILTER, gl.NEAREST ); | |
gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST ); | |
gl.bindFramebuffer( gl.FRAMEBUFFER, target.framebuffer ); | |
gl.framebufferTexture2D( gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, target.texture, 0 ); | |
// set up renderbuffer | |
gl.bindRenderbuffer( gl.RENDERBUFFER, target.renderbuffer ); | |
gl.renderbufferStorage( gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, width, height ); | |
gl.framebufferRenderbuffer( gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, target.renderbuffer ); | |
// clean up | |
gl.bindTexture( gl.TEXTURE_2D, null ); | |
gl.bindRenderbuffer( gl.RENDERBUFFER, null ); | |
gl.bindFramebuffer( gl.FRAMEBUFFER, null); | |
return target; | |
} | |
function createRenderTargets() { | |
frontTarget = createTarget( parameters.screenWidth, parameters.screenHeight ); | |
backTarget = createTarget( parameters.screenWidth, parameters.screenHeight ); | |
} | |
// | |
var dummyFunction = function() {}; | |
function htmlEncode(str){ | |
return String(str) | |
.replace(/&/g, '&') | |
.replace(/"/g, '"') | |
.replace(/'/g, ''') | |
.replace(/</g, '<') | |
.replace(/>/g, '>'); | |
} | |
function createShader( src, type ) { | |
var shader = gl.createShader(type); | |
var line, lineNum, lineError, index = 0, indexEnd; | |
gl.shaderSource(shader, src); | |
gl.compileShader(shader); | |
if (!gl.getShaderParameter( shader, gl.COMPILE_STATUS)) { | |
var error = gl.getShaderInfoLog( shader ); | |
// Remove trailing linefeed, for FireFox's benefit. | |
while ((error.length > 1) && (error.charCodeAt(error.length - 1) < 32)) { | |
error = error.substring(0, error.length - 1); | |
} | |
console.error( error ); | |
return null; | |
} | |
return shader; | |
} | |
function onWindowResize( event ) { | |
var isMaxWidth = ((resizer.currentWidth === resizer.maxWidth) || (resizer.currentWidth === resizer.minWidth)), | |
isMaxHeight = ((resizer.currentHeight === resizer.maxHeight) || (resizer.currentHeight === resizer.minHeight)); | |
resizer.isResizing = false; | |
resizer.maxWidth = window.innerWidth - 75; | |
resizer.maxHeight = window.innerHeight - 125; | |
if (isMaxWidth || (resizer.currentWidth > resizer.maxWidth)) { | |
resizer.currentWidth = resizer.maxWidth; | |
} | |
if (isMaxHeight || (resizer.currentHeight > resizer.maxHeight)) { | |
resizer.currentHeight = resizer.maxHeight; | |
} | |
if (resizer.currentWidth < resizer.minWidth) { resizer.currentWidth = resizer.minWidth; } | |
if (resizer.currentHeight < resizer.minHeight) { resizer.currentHeight = resizer.minHeight; } | |
var setByResize = false; | |
if (onResize) { | |
onResize(); | |
setByResize = canvas.width > 0; | |
} | |
if (!setByResize) { | |
if (canvasMetrics) { | |
var size = canvasMetrics(); | |
canvas.width = size.width / quality; | |
canvas.height = size.height / quality; | |
canvas.style.width = size.width + 'px'; | |
canvas.style.height = size.height + 'px'; | |
} else { | |
canvas.width = window.innerWidth / quality; | |
canvas.height = window.innerHeight / quality; | |
canvas.style.width = window.innerWidth + 'px'; | |
canvas.style.height = window.innerHeight + 'px'; | |
} | |
} | |
parameters.screenWidth = canvas.width; | |
parameters.screenHeight = canvas.height; | |
computeSurfaceCorners(); | |
if (gl) { | |
gl.viewport( 0, 0, canvas.width, canvas.height ); | |
createRenderTargets(); | |
} | |
} | |
// | |
function animate() { | |
requestAnimationFrame( animate ); | |
render(); | |
} | |
function render() { | |
if (!currentProgram) return; | |
parameters.time = Date.now() - parameters.startTime; | |
// Set uniforms for custom shader | |
gl.useProgram( currentProgram ); | |
gl.uniform1f( currentProgram.uniformsCache[ 'time' ], parameters.time / 1000 ); | |
gl.uniform2f( currentProgram.uniformsCache[ 'mouse' ], parameters.mouseX, parameters.mouseY ); | |
gl.uniform2f( currentProgram.uniformsCache[ 'resolution' ], parameters.screenWidth, parameters.screenHeight ); | |
gl.uniform1i( currentProgram.uniformsCache[ 'backbuffer' ], 0 ); | |
gl.uniform2f( currentProgram.uniformsCache[ 'surfaceSize' ], surface.width, surface.height ); | |
gl.bindBuffer( gl.ARRAY_BUFFER, surface.buffer ); | |
gl.vertexAttribPointer( surface.positionAttribute, 2, gl.FLOAT, false, 0, 0 ); | |
gl.bindBuffer( gl.ARRAY_BUFFER, buffer ); | |
gl.vertexAttribPointer( vertexPosition, 2, gl.FLOAT, false, 0, 0 ); | |
gl.activeTexture( gl.TEXTURE0); | |
gl.bindTexture( gl.TEXTURE_2D, backTarget.texture ); | |
if (renderCallback) { | |
renderCallback(currentProgram, gl); | |
} | |
// Render custom shader to front buffer | |
gl.bindFramebuffer( gl.FRAMEBUFFER, frontTarget.framebuffer ); | |
gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT ); | |
gl.drawArrays( gl.TRIANGLES, 0, 6 ); | |
// Set uniforms for screen shader | |
gl.useProgram( screenProgram ); | |
gl.uniform2f( screenProgram.uniformsCache[ 'resolution' ], parameters.screenWidth, parameters.screenHeight ); | |
gl.uniform1i( screenProgram.uniformsCache[ 'texture' ], 1 ); | |
gl.bindBuffer( gl.ARRAY_BUFFER, buffer ); | |
gl.vertexAttribPointer( screenVertexPosition, 2, gl.FLOAT, false, 0, 0 ); | |
gl.activeTexture( gl.TEXTURE1 ); | |
gl.bindTexture( gl.TEXTURE_2D, frontTarget.texture ); | |
// Render front buffer to screen | |
gl.bindFramebuffer( gl.FRAMEBUFFER, null ); | |
gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT ); | |
gl.drawArrays( gl.TRIANGLES, 0, 6 ); | |
// Swap buffers | |
var tmp = frontTarget; | |
frontTarget = backTarget; | |
backTarget = tmp; | |
} | |
init(); | |
return { | |
program : currentProgram, | |
parameters : parameters, | |
gl | |
}; | |
}; |
This file contains 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> | |
<head> | |
<link href="style.css" rel="stylesheet"/> | |
</head> | |
<body> | |
<script id="fragmentShader" type="x-shader/x-fragment"> | |
#ifdef GL_ES | |
precision highp float; | |
#endif | |
uniform vec2 resolution; | |
uniform sampler2D texture; | |
void main() { | |
vec2 uv = gl_FragCoord.xy / resolution.xy; | |
gl_FragColor = texture2D( texture, uv ); | |
} | |
</script> | |
<script id="vertexShader" type="x-shader/x-vertex"> | |
attribute vec3 position; | |
void main() { | |
gl_Position = vec4( position, 1.0 ); | |
} | |
</script> | |
<script id="surfaceVertexShader" type="x-shader/x-vertex"> | |
attribute vec3 position; | |
attribute vec2 surfacePosAttrib; | |
varying vec2 surfacePosition; | |
void main() { | |
surfacePosition = surfacePosAttrib; | |
gl_Position = vec4( position, 1.0 ); | |
} | |
</script> | |
<div id="myDiv"></div> | |
<script src="./bundle.js"></script> | |
<!--<script src="//localhost:8080/bundle.js"></script>--> | |
</body> | |
</html> |
This file contains 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
{ | |
"name": "logo", | |
"version": "1.0.0", | |
"description": "", | |
"main": "logo.js", | |
"scripts": { | |
"build": "webpack", | |
"start": "webpack-dev-server", | |
"test": "echo \"Error: no test specified\" && exit 1" | |
}, | |
"author": "", | |
"license": "ISC", | |
"dependencies": { | |
"babel-loader": "^8.0.6", | |
"babel-preset-env": "^1.7.0", | |
"dat.gui": "^0.7.6", | |
"webpack": "^4.42.0", | |
"webpack-dev-server": "^3.10.3" | |
}, | |
"devDependencies": { | |
"@babel/core": "^7.8.7", | |
"@babel/preset-env": "^7.8.7", | |
"webpack-cli": "^3.3.11" | |
} | |
} |
This file contains 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
const webpack = require('webpack'); | |
module.exports = { | |
context: __dirname + "/src", | |
entry: "./camera", | |
output: { | |
path: __dirname + "/dist", | |
filename: "bundle.js" | |
}, | |
module: { | |
rules: [ | |
{ | |
test: /\.js$/, | |
use: [ | |
{ | |
loader: 'babel-loader', | |
options: { | |
presets: ['@babel/preset-env'] | |
} | |
} | |
] | |
}, | |
] | |
}, | |
plugins: [ | |
new webpack.DefinePlugin({ | |
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV) | |
}) | |
] | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment