plunkerでshadertoy sandbox その 8

# 概要
plunkerでshadertoyのglsl動かしてみた。
textureとtextureLodを実装してみた。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/6706d5ef-d324-ab34-e0b4-ef73ceecadb6.png)

# 投入したソース

```
#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;




```

# 成果物

https://embed.plnkr.co/plunk/PKqMq9KdHYFne6h2


以上。