PShape::attrib() and PShape::setAttrib() dont work proprely

the attrib() and setAttrib() do not work proprely in all scenarios

The only way it works is when using attrib() in a not GROUP PShape.

Here is a working Exemple :

//
//  Working Exemple
//

PShape shape;
PShader shader;

public void setup() {
  size(500, 500, P2D);
  
  shape = createShape();
  shape.beginShape();
  
  // Visual
  shape.noStroke();
  shape.fill(255, 0, 0); // Not supposed to be Red
  
  // Custom Attribute
  shape.attrib("vert_color", 1.0, 0.5, 0.0, 1.0); // Supposed to be Orange
  
  shape.vertex(-100, -100);
  shape.vertex(100, -100);
  shape.vertex(100, 100);
  shape.vertex(-100, 100);
  
  shape.endShape();
  
  // Exemple shader
  shader = createShader();
}

public void draw() {
  background(255);
  
  shader(shader);
  translate(width/2, height/2);
  shape(shape);
}

public PShader createShader() {
  String[] vert = new String[] {
    "#version 110",
    "uniform mat4 transform;",
    "",
    "attribute vec4 position;",
    "attribute vec4 vert_color;",
    "",
    "varying vec4 vertColor;",
    "",
    "void main() {",
    "  gl_Position = transform * position;",
    "  vertColor = vert_color;",
    "}"
  };
  
  String[] frag = new String[] {
    "varying vec4 vertColor;",
    "",
    "void main() {",
    "  gl_FragColor = vertColor;",
    "}"
  };
  
  return new PShader(this, vert, frag);
}

Here is the first Exemple where it does not work.
When using PShapes that are GROUP attributes dont work and might give a java.lang.NullPointerException :

//
//  Does not work when shape is GROUP
//  ERROR : java.lang.NullPointerException
//

PShape shape;
PShape child;
PShader shader;

public void setup() {
  size(500, 500, P2D);
  
  child = createShape();
  child.beginShape();
  
  // Visual
  child.noStroke();
  child.fill(255, 0, 0); // Not supposed to be Red
  
  // Custom Attribute
  child.attrib("vert_color", 1.0, 0.5, 0.0, 1.0); // Supposed to be Orange
  
  child.vertex(-100, -100);
  child.vertex(100, -100);
  child.vertex(100, 100);
  child.vertex(-100, 100);
  
  child.endShape();
  
  shape = createShape(GROUP);
  shape.addChild(child);
  
  // Exemple shader
  shader = createShader();
}

public void draw() {
  background(255);
  
  shader(shader);
  translate(width/2, height/2);
  shape(shape);
}

public PShader createShader() {
  String[] vert = new String[] {
    "#version 110",
    "uniform mat4 transform;",
    "",
    "attribute vec4 position;",
    "attribute vec4 vert_color;",
    "",
    "varying vec4 vertColor;",
    "",
    "void main() {",
    "  gl_Position = transform * position;",
    "  vertColor = vert_color;",
    "}"
  };
  
  String[] frag = new String[] {
    "varying vec4 vertColor;",
    "",
    "void main() {",
    "  gl_FragColor = vertColor;",
    "}"
  };
  
  return new PShader(this, vert, frag);
}

Last not Working Exemple, when using the PShape::setAttrib() function, gives again a java.lang.NullPointerException :

//
//  Does not work when using PShape::setAttrib() later
//  ERROR : java.lang.NullPointerException
//

PShape shape;
PShader shader;

public void setup() {
  size(500, 500, P2D);
  
  shape = createShape();
  shape.beginShape();
  
  // Visual
  shape.noStroke();
  shape.fill(255, 0, 0); // Not supposed to be Red
  
  // Custom Attribute
  //shape.attrib("vert_color", 1.0, 0.5, 0.0, 1.0); // Not yet
  
  shape.vertex(-100, -100);
  shape.vertex(100, -100);
  shape.vertex(100, 100);
  shape.vertex(-100, 100);
  
  shape.endShape();
  
  // Set Custom Attributes
  for(int i=0; i<shape.getVertexCount(); i++) {
    shape.setAttrib("vert_color", i, 1.0, 0.5, 0.0, 1.0); // java.lang.NullPointerException, huh
  }
  
  // Exemple shader
  shader = createShader();
}

public void draw() {
  background(255);
  
  shader(shader);
  translate(width/2, height/2);
  shape(shape);
}

public PShader createShader() {
  String[] vert = new String[] {
    "#version 110",
    "uniform mat4 transform;",
    "",
    "attribute vec4 position;",
    "attribute vec4 vert_color;",
    "",
    "varying vec4 vertColor;",
    "",
    "void main() {",
    "  gl_Position = transform * position;",
    "  vertColor = vert_color;",
    "}"
  };
  
  String[] frag = new String[] {
    "varying vec4 vertColor;",
    "",
    "void main() {",
    "  gl_FragColor = vertColor;",
    "}"
  };
  
  return new PShader(this, vert, frag);
}

Am I doing somethong wrong or is this a bug ?

Thank you !

1 Like

In your second example, I see that you are calling shape.setAttrib() after shape.endShape(). That doesn’t look right.

When I change that and run either on Processing 3.3.6 I get a long list of error messages on shader(shader);:

Cannot compile vertex shader:ERROR: 0:1 " : version '110' is not supported ...

That looks like it might be a problem with your shader, not PShape … ?

Does it work without the version pragma? If that’s there the automatic rewriting of the shader for GL3+ doesn’t kick in.

The problem should not be the glsl version because the default processing attributes like : color and position are recognized and passed to the shader correctly.

Also, for the last exemple, all functions like setNormal(), setColor() and setAttrib() should be used outside beginShape and endShape while normal(), color() and attrib() should only be used inside beginShape and endShape so there is no problem there too.

I think it is a problem in the shape.setAttrib() function.

Good point. Looks like my initial guess was wrong.

Opened a issue on GitHub : https://github.com/processing/processing/issues/5560