# Unable to apply shader to PGraphics in p5js

**URL:** <https://discourse.processing.org/t/unable-to-apply-shader-to-pgraphics-in-p5js/34322>\
**Category:** Coding Questions\
**Created:** [December 27, 2021, 6:56pm UTC](https://discourse.processing.org/t/unable-to-apply-shader-to-pgraphics-in-p5js/34322 "2021-12-27T18:56:48Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![urotas](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/urotas/32/15369_2.png) [@urotas](https://discourse.processing.org/u/urotas)\
**Post date:** [December 27, 2021, 6:56pm UTC](https://discourse.processing.org/t/unable-to-apply-shader-to-pgraphics-in-p5js/34322/1 "2021-12-27T18:56:48Z")

</div>

Hi. I’m trying to apply a shader to PGraphics. I was able to apply a shader to a canvas. But, when I tried to apply a shader to PGraphics as well, I could not.

Should I add something?

This is what I’m applying to the canvas

```js
p5.setup = () => {
  p5.createCanvas(100, 100, p5.WEBGL)
  backbuffer0 = p5.createGraphics(p5.width, p5.height, p5.WEBGL)
  theShader = p5.createShader(vs, fs)
  backbuffer0.fill(0)
  backbuffer0.noStroke()
  backbuffer0.rect(-49, -49, 1, 1)
  p5.shader(theShader)
  theShader.setUniform('resolution', [p5.width, p5.height])
  theShader.setUniform('buffer', backbuffer0)
  p5.rect(-50, -50, 100, 100)
}

```

And this is what I’m applying to the PGraphics

```js
p5.setup = () => {
  p5.createCanvas(100, 100, p5.WEBGL)
  backbuffer0 = p5.createGraphics(p5.width, p5.height, p5.WEBGL)
  backbuffer1 = p5.createGraphics(p5.width, p5.height, p5.WEBGL)
  theShader = p5.createShader(vs, fs)
  backbuffer0.fill(0)
  backbuffer0.noStroke()
  // backbuffer1.noStroke()
  backbuffer0.rect(-49, -49, 1, 1)
  backbuffer1.shader(theShader)
  theShader.setUniform('resolution', [p5.width, p5.height])
  theShader.setUniform('buffer', backbuffer0)
  backbuffer1.rect(-50, -50, 100, 100)
  p5.image(backbuffer1, -50, -50, p5.width, p5.height)
}

```

I am trying to achieve the life cycle with two PGraphics using this post as a reference. But, as a first step, I am not able to apply a shader to the PGraphics.

> [@Backbuffer in p5js](https://discourse.processing.org/t/backbuffer-in-p5js/29769/13):
>
> That is great and indeed this is a difficult example to make by yourself! One suggestion would be to use two p5.Graphics objects. Right now you copy canvas to backbuffer then render canvas. This works perfectly in your case. But this becomes problematic if you want to use more layers - for example, if you draw a text on top of the canvas, this will affect the backbuffer in the next frame. If you prepare, say, backbuffer0 and backbuffer1, you can do something like this (I haven’t tested the code…

Thanks

---

<div class="post-metadata">

**Author:** ![KumuPaul](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/kumupaul/32/13072_2.png) [@KumuPaul](https://discourse.processing.org/u/KumuPaul)\
**Post date:** [December 27, 2021, 7:33pm UTC](https://discourse.processing.org/t/unable-to-apply-shader-to-pgraphics-in-p5js/34322/2 "2021-12-27T19:33:49Z")

</div>

Generally speaking buffer swapping is not necessary with WEBGL fragment shaders that sample values from the previous state of a texture. I presume this is because the fragment shader output is written to a new buffer each frame. However if you had a shader that needed to sample both the previous state and the state before that then it would be useful. However it is not clear from the code you have shared what the problem is.

Here is an example of a shader that is used to draw a texture to a `p5.Graphics` object while sampling from the previous frame for the same `p5.Graphics` object:

https://openprocessing.org/sketch/1107781/embed/?plusEmbedHash=YTgzOTU1ZWUyYzAyNzYwNTI4NjYyZDVkMDFlMjMwYmIxNDg0ODdlMWU5MGEzYWVmOGE4NDk4MGY5ZDcyNjgzZGJmNDgxNDY3NTgzYjVkN2M1ZDI0OTBhNzU1MGI2YTNlOWMyMDE4YWQ5OTJkOTE2NmU0ODYzNDRmZjhmZDlkYjJBd01ybUJ0a2NWUkdPY2RIcEZyVlF5cVB4L3EvZTduaUJBL1lVbE1aSWI0N3VzMnh2cEpsNFFnUFdtMU9VVk53WjRMSXBWanpUSGNoN1lrZlA2OWdLdz09&plusEmbedTitle=true

---

<div class="post-metadata">

**Author:** ![urotas](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/urotas/32/15369_2.png) [@urotas](https://discourse.processing.org/u/urotas)\
**Post date:** [December 28, 2021, 1:47am UTC](https://discourse.processing.org/t/unable-to-apply-shader-to-pgraphics-in-p5js/34322/3 "2021-12-28T01:47:06Z")

</div>

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.

```auto
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.

 ![screenshot 2021-12-28 10.33.18](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/4/4668c39b66a0e11976a3fc1b138a20e35771aa2c.png)

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

---

<div class="post-metadata">

**Author:** ![KumuPaul](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/kumupaul/32/13072_2.png) [@KumuPaul](https://discourse.processing.org/u/KumuPaul)\
**Post date:** [December 28, 2021, 2:37am UTC](https://discourse.processing.org/t/unable-to-apply-shader-to-pgraphics-in-p5js/34322/4 "2021-12-28T02:37:30Z")

</div>

You need to call the `createShader()` function on the `p5.Graphics` on which you are using the shader (i.e. don’t call `p5.createShader()`, call `golTexture.createShader()`)

---

<div class="post-metadata">

**Author:** ![urotas](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/urotas/32/15369_2.png) [@urotas](https://discourse.processing.org/u/urotas)\
**Post date:** [December 28, 2021, 3:03am UTC](https://discourse.processing.org/t/unable-to-apply-shader-to-pgraphics-in-p5js/34322/5 "2021-12-28T03:03:30Z")

</div>

Wow, It’s solved! It was my basic misunderstanding.  
Thank you for taking the time to answer my question!
