概要
plunkerでshadertoyのglsl動かしてみた。
textureとtextureLodを実装してみた。
写真
投入したソース
#extension GL_EXT_shader_texture_lod : enable
precision mediump float;
uniform vec2 iResolution;
uniform float iGlobalTime;
uniform sampler2D iChannel0;
uniform sampler2D iChannel1;
uniform sampler2D iChannel2;
uniform vec4 iMouse;
uniform vec3 iChannelResolution[3];
uniform float iChannelTime[4];
#define iTime iGlobalTime
vec4 textureLod(sampler2D s, vec2 c, float b) {
return texture2DLodEXT(s, c, b);
}
vec4 texture(sampler2D s, vec2 c) {
return texture2D(s, c);
}
void mainImage2(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = fragCoord / iResolution.xy;
fragColor = texture(iChannel0, uv);
}
void mainImage0(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = fragCoord / iResolution.xy;
vec3 col = 0.5 + 0.5 * cos(iTime + uv.xyx + vec3(0, 2, 4));
fragColor = vec4(col, 1.0);
}
void mainImage1(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = fragCoord / iResolution.xy;
vec3 col = vec3(uv, 0);
fragColor = vec4(col, 1.0);
}
void mainImage3(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = fragCoord / iResolution.xy;
uv.x *= 3.0;
uv *= 0.1 + sin(iTime) * 0.5 + 0.5;
vec4 t = texture(iChannel0, uv);
vec4 t2 = textureLod(iChannel0, uv, 0.0);
fragColor = t2;
if (fragCoord.x / iResolution.x < 0.33)
{
fragColor = t;
}
if (fragCoord.x / iResolution.x > 0.66)
{
fragColor = abs(t - t2) * 10.0;
}
}
mat2 rot(float a) {
return mat2(sin(a), cos(a), -cos(a), sin(a));
}
void mainImage4(out vec4 fragColor, vec2 fragCoord) {
vec2 p = (fragCoord - .5 * iResolution.xy ) / iResolution.y;
float lod = log2(iChannelResolution[0].y / iResolution.y),
d = 55. / 6.283,
l = d * length(p) - 5.,
s = - (iTime + 30.) * .01,
l0 = s * floor(l - .5) ,
l1 = s * floor (l + .5) ;
if (fragCoord.x < 0.5 * iResolution.x)
{
if (fragCoord.y < 0.5 * iResolution.y)
{
fragColor = texture(iChannel0, p * rot(l0));
}
else
fragColor = textureLod(iChannel0, p * rot(l0), lod);
}
else
{
float k = smoothstep(-.8, .8, iResolution.y / d * (fract(l - .5) - .5));
if (fragCoord.y < 0.5 * iResolution.y)
{
fragColor = mix(texture(iChannel0, p * rot(l0)), texture(iChannel0, p * rot(l1)), k);
}
else
{
fragColor = mix(textureLod(iChannel0, p * rot(l0), lod), textureLod(iChannel0, p * rot(l1), lod), k);
}
}
}
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = fragCoord.xy / iResolution.xy;
vec3 col = textureLod(iChannel0, uv, (sin(iTime) + 1.) * 2.).xyz;
fragColor = vec4(col, 1.0);
}
void main() {
vec4 color = vec4(0.0, 0.0, 0.0, 1.0);
mainImage(color, gl_FragCoord.xy);
color.w = 1.0;
gl_FragColor = color;
}
サンプルコード
var gl;
var sc;
var AudioPlayer = function() {
"use strict";
this.audio = new Audio();
this.audio.volume = 0.5;
this.audio.loop = true;
this.sound = new AudioContext();
this.source = this.sound.createMediaElementSource(this.audio);
this.node = this.sound.createScriptProcessor(2048, 1, 1);
this.analyser = this.sound.createAnalyser();
this.data = new Uint8Array(this.analyser.frequencyBinCount);
this.analyser.smoothingTimeConstant = 0.8;
this.analyser.fftSize = 128;
this.source.connect(this.analyser);
this.analyser.connect(this.node);
this.node.connect(this.sound.destination);
this.source.connect(this.sound.destination);
this.loadMusic = function(url) {
this.audio.src = url;
this.audio.play();
};
this.getWave = function() {
this.analyser.getByteFrequencyData(this.data);
return this.data;
};
this.getTime = function() {
return this.audio.currentTime;
};
};
var repeat = (times, arr) => {
let result = [];
for (let i = 0; i < times; i++)
{
result = [...result, ...arr];
}
return result;
}
var audioPlayer;
var mx,
my,
cw,
ch;
cw = window.innerWidth;
ch = window.innerHeigh;
var mouseOriX = 0;
var mouseOriY = 0;
var mousePosX = 0;
var mousePosY = 0;
var mouseIsDown = false;
function piGetCoords(obj) {
var x = 0;
var y = 0;
do
{
x += obj.offsetLeft;
y += obj.offsetTop;
} while (obj = obj.offsetParent);
return {
mX: x,
mY: y
};
}
function onmousedown(ev) {
var c = document.getElementById('canvas');
var pos = piGetCoords(c);
mouseOriX = (ev.pageX - pos.mX) * c.width / c.offsetWidth;
mouseOriY = c.height - (ev.pageY - pos.mY) * c.height / c.offsetHeight;
mousePosX = mouseOriX;
mousePosY = mouseOriY;
mouseIsDown = true;
}
function onmousemove(ev) {
var c = document.getElementById('canvas');
if (mouseIsDown)
{
var pos = piGetCoords(c);
mousePosX = (ev.pageX - pos.mX) * c.width / c.offsetWidth;
mousePosY = c.height - (ev.pageY - pos.mY) * c.height / c.offsetHeight;
}
}
function onmouseup(ev) {
var c = document.getElementById('canvas');
mouseIsDown = false;
mouseOriX = -Math.abs(mouseOriX);
mouseOriY = -Math.abs(mouseOriY);
}
var ShaderDrawer = function(shader) {
'use strict';
var fs = gl.createShader(gl.FRAGMENT_SHADER);
var vs = gl.createShader(gl.VERTEX_SHADER);
var pr;
gl.getExtension("EXT_shader_texture_lod");
gl.shaderSource(vs, "attribute vec4 p;void main(){gl_Position = p;}");
gl.shaderSource(fs, shader);
gl.compileShader(vs);
if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS))
{
alert("ng0");
return null;
}
gl.compileShader(fs);
if (!gl.getShaderParameter(fs, gl.COMPILE_STATUS))
{
alert(gl.getShaderInfoLog(fs));
return null;
}
pr = gl.createProgram();
gl.attachShader(pr, vs);
gl.attachShader(pr, fs);
gl.linkProgram(pr);
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([1, 1, 1, -3, -3, 1]), gl.STATIC_DRAW);
this.prg = pr;
this.create_texture = function(source) {
var img = new Image();
img.onload = function() {
var tex = gl.createTexture();
console.log(tex);
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
gl.generateMipmap(gl.TEXTURE_2D);
};
img.src = source;
}
this.draw = function(tm, w, h, wave) {
var iChannelResolutions = new Float32Array(repeat(4, [w, h, 0]));
var mouse = [mousePosX, mousePosY, mouseOriX, mouseOriY];
gl.viewport(0, 0, w, h);
gl.useProgram(this.prg);
gl.uniform1i(gl.getUniformLocation(this.prg, "iChannel0"), 0);
gl.uniform1i(gl.getUniformLocation(this.prg, "iChannel1"), 0);
gl.uniform1i(gl.getUniformLocation(this.prg, "iChannel2"), 0);
gl.uniform2fv(gl.getUniformLocation(this.prg, "iResolution"), [w, h]);
gl.uniform3fv(gl.getUniformLocation(this.prg, "iChannelResolution"), iChannelResolutions);
gl.uniform4fv(gl.getUniformLocation(this.prg, "iMouse"), mouse);
gl.uniform1f(gl.getUniformLocation(this.prg, "iGlobalTime"), tm);
gl.enableVertexAttribArray(0);
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
gl.drawArrays(gl.TRIANGLES, 0, 3);
};
};
var Scene0 = function() {
'use strict';
this.init = function() {
var shader = document.getElementById('src').value;
this.sd = new ShaderDrawer(shader);
this.sd.create_texture('lib/noise.png');
this.sd.create_texture('lib/green.png');
this.sd.create_texture('lib/mfu.png');
};
this.draw = function(scenetime, wave) {
gl.clearColor(0, 0, 0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
this.sd.draw(scenetime, window.innerWidth, window.innerHeight, wave);
};
this.init();
return this;
};
var render = function() {
'use strict';
var wave = audioPlayer.getWave();
var timeCode = document.getElementById('timecode');
var demotime = audioPlayer.getTime();
if (timeCode)
{
timeCode.innerHTML = demotime.toFixed(3);
}
sc.draw(demotime, wave);
requestAnimationFrame(render);
};
var init = function() {
'use strict';
var timeOffset = 0;
var canvas = document.getElementById('canvas');
gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
audioPlayer.loadMusic('lib/svg_girl_theme.mp3');
canvas.addEventListener('mousemove', onmousemove, true);
canvas.addEventListener('mousedown', onmousedown, true);
canvas.addEventListener('mouseup', onmouseup, true);
sc = new Scene0();
requestAnimationFrame(render);
};
var resizeFunc = function() {
'use strict';
var canvas = document.getElementById('canvas');
canvas.setAttribute('width', 665);
canvas.setAttribute('height', 465);
};
var run = function() {
'use strict';
audioPlayer = new AudioPlayer();
resizeFunc();
var timecode = document.getElementById("timecode");
if (timecode)
{
timecode.style.display = "";
}
init();
};
window.onresize = resizeFunc;
成果物
以上。