webGLで同等の事をする。
前回のpythonソースをwebGLに書き直すと、openGL部分は、ほぼ一緒ですが、音楽部分が別物です。
<script id="vs" type="x-shader/x-vertex"> #version 300 es void main() { gl_Position = vec4(ivec2(gl_VertexID&1,gl_VertexID>>1)*2-1,0,1); } </script> <script id="fs" type="x-shader/x-vertex"> #version 300 es precision highp float; uniform vec2 resolution; uniform float time; out vec4 fragColor; void main() { vec2 p = (2.0 * gl_FragCoord.xy - resolution.xy) / resolution.y; p += vec2(cos(time), sin(time)) * 0.5; float g = exp(-1.5 * dot(p,p)); fragColor = vec4(g, g, g, 1.0); } </script> <script id="vs_mzk" type="x-shader/x-vertex"> #version 300 es out vec2 gain; uniform float sampleRate; #define PI2 6.2831 #define speed 3.0 float sound(float time) { return sin(6.2831*440.0*fract(time)); } void main() { float time = float(gl_VertexID) / sampleRate; gain = vec2(sound(time)); } </script> <script id="fs_mzk" type="x-shader/x-fragment"> #version 300 es void main() {} </script> <canvas id="canvas" width="360" height="240"></canvas> <script type="text/javascript"> var gl = canvas.getContext("webgl2") || canvas.getContext("experimental-webgl2"); var compileShader = function(prog, src, type){ var sh = gl.createShader(type); gl.shaderSource(sh, src.replace(/^\n/, "")); gl.compileShader(sh); if (!gl.getShaderParameter(sh, gl.COMPILE_STATUS)) { alert(gl.getShaderInfoLog(sh)); } gl.attachShader(prog, sh); gl.deleteShader(sh); }; var p = gl.createProgram(); compileShader(p, vs.text, gl.VERTEX_SHADER); compileShader(p, fs.text, gl.FRAGMENT_SHADER); gl.linkProgram(p); gl.useProgram(p); gl.uniform2f(gl.getUniformLocation(p, "resolution"), canvas.width, canvas.height); var audio = new AudioContext(); var sampleRate = audio.sampleRate; var bufferSize = audio.sampleRate * 10; // 10 sec var audioBuffer = audio.createBuffer(2, bufferSize, audio.sampleRate); var node = audio.createBufferSource(); var p_mzk = gl.createProgram(); compileShader(p_mzk, vs_mzk.text, gl.VERTEX_SHADER); compileShader(p_mzk, fs_mzk.text, gl.FRAGMENT_SHADER); gl.transformFeedbackVaryings(p_mzk, ['gain'], gl.SEPARATE_ATTRIBS); gl.linkProgram(p_mzk); gl.useProgram(p_mzk); gl.uniform1f(gl.getUniformLocation(p_mzk, "sampleRate"), sampleRate); var VBOs = [gl.createBuffer(),gl.createBuffer()]; for (var i = 0; i < 2; ++i) { gl.bindBuffer(gl.ARRAY_BUFFER, VBOs[i]); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(bufferSize*2), gl.STATIC_DRAW); } gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, VBOs[0]); gl.enable(gl.RASTERIZER_DISCARD); gl.beginTransformFeedback(gl.POINTS); gl.drawArrays(gl.POINTS, 0, bufferSize); gl.endTransformFeedback(); gl.disable(gl.RASTERIZER_DISCARD); gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, null); gl.bindBuffer(gl.ARRAY_BUFFER, VBOs[0]); var aryBuffer = new ArrayBuffer(bufferSize*4*2); var dataView = new DataView(aryBuffer); gl.getBufferSubData(gl.ARRAY_BUFFER, 0, dataView); var buf = new Float32Array(aryBuffer); var data0 = audioBuffer.getChannelData(0); var data1 = audioBuffer.getChannelData(1); for(var i = 0; i < bufferSize; i++) { data0[i] = buf[i*2]; data1[i] = buf[i*2+1]; } node.buffer = audioBuffer; node.loop = false; node.connect(audio.destination); var zero = Date.now(); gl.useProgram(p); node.start(0); (function () { gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); gl.uniform1f(gl.getUniformLocation(p, "time"), (Date.now() - zero) * 0.001); gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); requestAnimationFrame(arguments.callee); })(); </script>
これで、C言語、python、webGLが揃いました。shader中心で書いていると、これだけあれば、他のソースは要らないです。
これを状況によって、ちょっと変化させる程度で済みます。
でも、今度compute shaderに手を出すので、ここで1回まとめてみました。
これだけミニ化していると説明要素の密度が濃すぎて解説は書きようが無いです。
いずれ、pythonとwebGLとのコマンドの違いは書くつもりです。
ブログには、webGLが使えるみたいなので試してみました。ちょっとうるさいので消音してあります。
以前
を書きましたが、必要以上のwebGLのミニ化は、それ程、魅力的では無くなってしまったので、一応、参考ということでリンクを貼っておきました。