float x = mod(aIndex, uSize.x);
float y = floor(aIndex/uSize.y);
vec2 uv = (vec2(x,y)+0.5)/uSize;
gl_Position = vec4(uv, 0.0, 1.0);
float x = mod(aIndex, uSize.x);
float y = floor(aIndex/uSize.y);
vec2 uv = (vec2(x,y)+0.5)/uSize;
gl_Position = vec4(uv.x*2.0-1.0, 1.0-uv.y*2.0, 0.0, 1.0);
uniform bool uMouseIsPressed;
const float SPEED = 0.05;
vec4 tex = texture(uData, vUv);
// ざっくりいうとマウス位置に向かって緩やかに進行する感じ
// uVelocityはマウスが離れてる場合減衰する。その場合velは一定。
vec2 v = normalize(uMouse - pos)*0.2;
vec2 w = normalize(v + vel);
vec4 data = vec4(pos + w * SPEED * uVelocity, w);
if(!uMouseIsPressed) data.zw = vel;
uniform float uPointScale;
float x = mod(aIndex, uSize.x);
float y = floor(aIndex/uSize.y);
vec2 uv = (vec2(x,y)+0.5)/uSize;
vec2 p = texture(uTex, uv).xy * uAdjust;
gl_Position = vec4(p, 0.0, 1.0);
gl_PointSize = 0.1 + uPointScale;
color = vec4(uBaseColor, 0.5);
createCanvas(windowWidth, windowHeight, WEBGL);
const _gl = this._renderer;
for(let k=0; k<TEX_SIZE*TEX_SIZE; k++){
const x = -1+2*(k%TEX_SIZE)/TEX_SIZE;
const y = -1+2*floor(k/TEX_SIZE)/TEX_SIZE;
indexBuf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, indexBuf);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(iArray), gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
dataBuf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, dataBuf);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(fArray), gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
const inputShader = createShader(inputVS, inputFS);
fbo0 = createFramebuffer({
width:TEX_SIZE, height:TEX_SIZE, format:FLOAT, textureFiltering:NEAREST
fbo1 = createFramebuffer({
width:TEX_SIZE, height:TEX_SIZE, format:FLOAT, textureFiltering:NEAREST
gl.bindBuffer(gl.ARRAY_BUFFER, indexBuf);
inputShader.enableAttrib(inputShader.attributes.aIndex, 1);
gl.bindBuffer(gl.ARRAY_BUFFER, dataBuf);
inputShader.enableAttrib(inputShader.attributes.aData, 4);
inputShader.setUniform("uSize",[TEX_SIZE, TEX_SIZE]);
_gl._setPointUniforms(inputShader);
gl.drawArrays(gl.POINTS, 0, TEX_SIZE*TEX_SIZE);
inputShader.unbindShader();
updateShader = createShader(updateVS, updateFS);
displayShader = createShader(displayVS, displayFS);
pfc = new p5wgex.PerformanceChecker(this.canvas);
gr = createGraphics(width, height);
gr.textAlign(CENTER, CENTER);
gr.text("GPGPU particle test", width/2, height/2);
const tx = (new p5.Texture(this._renderer, gr)).glTex;
gl.activeTexture(gl.TEXTURE0 + 2);
gl.bindTexture(gl.TEXTURE_2D, tx);
gl.activeTexture(gl.TEXTURE0);
const pg = gl.getParameter(gl.CURRENT_PROGRAM);
const loc = gl.getUniformLocation(pg, "uSampler");
const _gl = this._renderer;
gl.bindBuffer(gl.ARRAY_BUFFER, indexBuf);
updateShader.enableAttrib(updateShader.attributes.aIndex, 1);
updateShader.setUniform("uData", fbo0.color);
updateShader.setUniform("uSize",[TEX_SIZE, TEX_SIZE]);
updateShader.setUniform("uMouseIsPressed", mouseIsPressed);
const mouseVector = [2*mouseX/width-1, 1-2*mouseY/height];
const mouseCoeff = (width > height ? [width/height,1] : [1,height/width]);
updateShader.setUniform("uMouse", [mouseVector[0]*mouseCoeff[0], mouseVector[1]*mouseCoeff[1]]);
updateShader.setUniform("uVelocity", velocity);
updateShader.bindTextures();
gl.drawArrays(gl.POINTS, 0, TEX_SIZE*TEX_SIZE);
updateShader.unbindShader();
gl.bindBuffer(gl.ARRAY_BUFFER, indexBuf);
displayShader.enableAttrib(displayShader.attributes.aIndex, 1);
displayShader.setUniform("uTex", fbo0.color);
displayShader.setUniform("uSize",[TEX_SIZE, TEX_SIZE]);
const hueValue = floor((frameCount%1800)/5);
const col = color(`hsb(${hueValue}, 70%, 80%)`);
displayShader.setUniform("uBaseColor", [
red(col)/255, green(col)/255, blue(col)/255
const adjustment = (width > height ? [height/width,1] : [1,width/height]);
displayShader.setUniform("uAdjust", adjustment);
displayShader.setUniform("uPointScale", velocity);
_gl._setPointUniforms(displayShader);
gl.blendFunc(gl.ONE, gl.ONE);
displayShader.bindTextures();
gl.drawArrays(gl.POINTS, 0, TEX_SIZE*TEX_SIZE);
displayShader.unbindShader();
camera(0,0,1,0,0,0,0,1,0);
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);