Thanks for the reply.
I am hoping to build my own GPU Particle System in the near future. It is my understanding that buffer swapping is required for this. So I wanted to make sure that p5js can do that.
I copied KumuPaul’s code to my local environment and tried to run it. But, for some reason, your life game did not show up in my local environment.
const vert = `
attribute vec3 aPosition;
// attribute vec2 aTexCoord;
varying highp vec2 vPos;
void main() {
vPos = (gl_Position = vec4(aPosition, 1.0)).xy;
}`
const fragInit = `
precision highp float;
uniform int width;
uniform int height;
uniform int size;
uniform float seed;
varying highp vec2 vPos;
float PHI = 1.61803398874989484820459;
void main() {
int scaledWidth = width / size;
int scaledHeight = height / size;
int x = int((vPos.x + 1.) / 2. * float(scaledWidth));
int y = int(((vPos.y * -1.) + 1.) / 2. * float(scaledHeight));
vec2 coord = vec2(float(x) / float(scaledWidth), float(y) / float(scaledHeight));
float r = fract(tan(distance((coord + vec2(0.3, 0)) * PHI, (coord + vec2(0.1, 0.2))) * seed) * (coord + vec2(0.1, 0)).x * 2701.);
if (r < 0.6) {
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
} else {
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
}
`
const fragGo = `
precision highp float;
uniform sampler2D state;
uniform int width;
uniform int height;
uniform int size;
varying highp vec2 vPos;
int get(ivec2 origin, int x, int y, int scaledWidth, int scaledHeight) {
// We're drawing from bottom left: -1, -1 to top right: 1, 1
// However texture2D/sampler2D work in a coordinate system from top left: 0, 0 to bottom right: 1, 1
highp vec2 texPos = vec2(
(float(origin.x + x) + 0.5) / float(scaledWidth),
(float(origin.y + y) + 0.5) / float(scaledHeight)
);
return int(texture2D(state, texPos).r);
}
float signf(int val) {
if (val < 0) {
return -1.;
} else if (val > 0) {
return 1.;
} else {
return 0.;
}
}
void main() {
int scaledWidth = (width) / size;
int scaledHeight = (height) / size;
// Convert our floating point position from -1 to 1, to an integer position
// from 0 to width/height
int x = int((vPos.x + 1.) / 2. * float(scaledWidth));
int y = int(((vPos.y * -1.) + 1.) / 2. * float(scaledHeight));
ivec2 origin = ivec2(x, y);
// test the basic texture sampling functionality
/*
float current = float(get(origin, 0, 0, scaledWidth, scaledHeight));
gl_FragColor = vec4(current, current, current, 1.0);
*/
int sum = get(origin, -1, -1, scaledWidth, scaledHeight) +
get(origin, -1, 0, scaledWidth, scaledHeight) +
get(origin, -1, 1, scaledWidth, scaledHeight) +
get(origin, 0, -1, scaledWidth, scaledHeight) +
get(origin, 0, 1, scaledWidth, scaledHeight) +
get(origin, 1, -1, scaledWidth, scaledHeight) +
get(origin, 1, 0, scaledWidth, scaledHeight) +
get(origin, 1, 1, scaledWidth, scaledHeight);
if (sum == 3) {
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
} else if (sum == 2) {
float current = float(get(origin, 0, 0, scaledWidth, scaledHeight));
gl_FragColor = vec4(current, current, current, 1.0);
} else {
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
}
}
`
export const Sketch = p5 => {
let size = 2
let golShader
let initShader
let init
let lastUpdate = 0
let generation = 0
let golTexture
p5.setup = function () {
p5.createCanvas(p5.windowWidth, p5.windowHeight, p5.WEBGL)
// p5.pixelDensity(1);
p5.background(0)
p5.noStroke()
p5.fill(255)
p5.textureMode(p5.NORMAL)
golTexture = p5.createGraphics(p5.width, p5.height, p5.WEBGL)
// golTexture.noStroke()
initShader = p5.createShader(vert, fragInit)
golShader = p5.createShader(vert, fragGo)
reset()
}
function reset() {
init = true
golTexture.shader(initShader)
initShader.setUniform('width', p5.width)
initShader.setUniform('height', p5.height)
initShader.setUniform('size', size)
initShader.setUniform('seed', p5.random(0, 10000000))
// frameRate(1);
// p5.noLoop(); // for debuging
generation = 0
lastUpdate = p5.millis()
}
p5.draw = function () {
let delta = p5.millis() - lastUpdate
let didUpdate = false
if (init || (maxFrameRate > 0 && delta > 1000 / maxFrameRate)) {
golTexture.quad(-1, -1, 1, -1, 1, 1, -1, 1)
lastUpdate = p5.millis()
generation++
}
p5.orbitControl(2, 2, 0.01)
p5.background('white')
p5.texture(golTexture)
p5.rect(-p5.width / 2, -p5.height / 2, p5.width, p5.height)
//p5.torus(30, 15);
if (init) {
golTexture.shader(golShader)
golShader.setUniform('state', golTexture)
golShader.setUniform('width', p5.width)
golShader.setUniform('height', p5.height)
golShader.setUniform('size', size)
init = false
}
}
/*
p5.mouseClicked = function() {
p5.redraw();
}*/
let maxFrameRate = 60
}
The console log showed INVALID_OPERATION: drawElements: no valid shader program in use
.
After commenting out golTexture.noStroke()
in setup function, the INVALID_OPERATION in Webgl disappeared, but the canvas still does not display the lifegame. A dot is displayed in the center of the canvas.
It can be run in the openProcessing environment, so it is most likely a problem with my local environment.
Have you ever encountered a case where such an INVALID_OPERATION is output?
I don’t know if this will help, but my local environment is as follows
PC Chip: Apple M1 Max
p5js Version: 1.4.0
And I built p5js environment by using create-react-app