Copy data to OpenGL buffer

I’m trying to implement a parallax mapping shader following this post.
In the (C++) code, at the end of the renderQuad function, the the array quadVertices is copied into the GL Buffer. How can I do the same in Processing?

Links to the glsl files:
Vertex Shader
Fragment Shader

Tutorial on shaders for processing example of filters using shaders, other types of shaders.

Thank you for the links! However, in these examples the arguments are uniform, while the shader I’m trying to implement requires vertex specific information. Any idea how I can pass that for each vertex?

I tried the following but it did not work. (The glsl files are the ones from the links in the 1st post)

void setup(){
  size(1000, 800, P3D);

  PImage bricks_dif = loadImage("bricks_diffuse.jpg");
  PImage bricks_normal = loadImage("bricks_normal.jpg");
  PImage bricks_disp = loadImage("bricks_disp.jpg");
  
  parallax = loadShader("fragmentShader2.glsl", "vertexShader2.glsl");
  parallax.set("diffuseMap", bricks_dif);
  parallax.set("normalMap", bricks_normal);
  parallax.set("depthMap", bricks_disp);
  parallax.set("heightScale", 0.2);
}

void draw(){
  background(140, 80, 80);
  
  shader(parallax);
  
  translate(width/2, height/2, 0);

  normal(0, 0, 1);
  rotateY(-PI/4);
  rotateX(PI/4);
  renderQuad();
}

void renderQuad(){
  PVector pos1 = new PVector(-1.0f,  1.0f, 0.0f);
  PVector pos2 = new PVector(-1.0f, -1.0f, 0.0f);
  PVector pos3 = new PVector( 1.0f, -1.0f, 0.0f);
  PVector pos4 = new PVector( 1.0f,  1.0f, 0.0f);
  // texture coordinates
  PVector uv1 = new PVector(0.0f, 1.0f);
  PVector uv2 = new PVector(0.0f, 0.0f);
  PVector uv3 = new PVector(1.0f, 0.0f);
  PVector uv4 = new PVector(1.0f, 1.0f);
  // normal vector
  PVector nm = new PVector(0.0f, 0.0f, 1.0f);
  
  // calculate tangent/bitangent vectors of both triangles
  PVector tangent1 = new PVector(0, 0, 0), bitangent1 = new PVector(0, 0, 0);
  PVector tangent2 = new PVector(0, 0, 0), bitangent2 = new PVector(0, 0, 0);
  // triangle 1
  // ----------
  PVector edge1 = PVector.sub(pos2, pos1);
  PVector edge2 = PVector.sub(pos3, pos1);
  PVector deltaUV1 = PVector.sub(uv2, uv1);
  PVector deltaUV2 = PVector.sub(uv3, uv1);
  
  float f = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV2.x * deltaUV1.y);
  
  tangent1.x = f * (deltaUV2.y * edge1.x - deltaUV1.y * edge2.x);
  tangent1.y = f * (deltaUV2.y * edge1.y - deltaUV1.y * edge2.y);
  tangent1.z = f * (deltaUV2.y * edge1.z - deltaUV1.y * edge2.z);
  tangent1.normalize();
  
  bitangent1.x = f * (-deltaUV2.x * edge1.x + deltaUV1.x * edge2.x);
  bitangent1.y = f * (-deltaUV2.x * edge1.y + deltaUV1.x * edge2.y);
  bitangent1.z = f * (-deltaUV2.x * edge1.z + deltaUV1.x * edge2.z);
  bitangent1.normalize();
  
  // triangle 2
  // ----------
  edge1 = PVector.sub(pos3, pos1);
  edge2 = PVector.sub(pos4, pos1);
  deltaUV1 = PVector.sub(uv3, uv1);
  deltaUV2 = PVector.sub(uv4, uv1);
  
  f = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV2.x * deltaUV1.y);
  
  tangent2.x = f * (deltaUV2.y * edge1.x - deltaUV1.y * edge2.x);
  tangent2.y = f * (deltaUV2.y * edge1.y - deltaUV1.y * edge2.y);
  tangent2.z = f * (deltaUV2.y * edge1.z - deltaUV1.y * edge2.z);
  tangent2.normalize();
  
  
  bitangent2.x = f * (-deltaUV2.x * edge1.x + deltaUV1.x * edge2.x);
  bitangent2.y = f * (-deltaUV2.x * edge1.y + deltaUV1.x * edge2.y);
  bitangent2.z = f * (-deltaUV2.x * edge1.z + deltaUV1.x * edge2.z);
  bitangent2.normalize();
  
  
  float quadVertices[] = {
      // positions            // normal         // texcoords  // tangent                          // bitangent
      pos1.x, pos1.y, pos1.z, nm.x, nm.y, nm.z, uv1.x, uv1.y, tangent1.x, tangent1.y, tangent1.z, bitangent1.x, bitangent1.y, bitangent1.z,
      pos2.x, pos2.y, pos2.z, nm.x, nm.y, nm.z, uv2.x, uv2.y, tangent1.x, tangent1.y, tangent1.z, bitangent1.x, bitangent1.y, bitangent1.z,
      pos3.x, pos3.y, pos3.z, nm.x, nm.y, nm.z, uv3.x, uv3.y, tangent1.x, tangent1.y, tangent1.z, bitangent1.x, bitangent1.y, bitangent1.z,
  
      pos1.x, pos1.y, pos1.z, nm.x, nm.y, nm.z, uv1.x, uv1.y, tangent2.x, tangent2.y, tangent2.z, bitangent2.x, bitangent2.y, bitangent2.z,
      pos3.x, pos3.y, pos3.z, nm.x, nm.y, nm.z, uv3.x, uv3.y, tangent2.x, tangent2.y, tangent2.z, bitangent2.x, bitangent2.y, bitangent2.z,
      pos4.x, pos4.y, pos4.z, nm.x, nm.y, nm.z, uv4.x, uv4.y, tangent2.x, tangent2.y, tangent2.z, bitangent2.x, bitangent2.y, bitangent2.z
  };
  
  int w = 300;
  
  beginShape();
  parallax.set("aPos", pos1);
  parallax.set("aNormal", nm);
  parallax.set("aTexCoords", uv1);
  parallax.set("aTangent", tangent1);
  parallax.set("aBitangent", bitangent1);
  vertex(-w, -w, 0, w, w);
  
  parallax.set("aPos", pos2);
  parallax.set("aNormal", nm);
  parallax.set("aTexCoords", uv2);
  parallax.set("aTangent", tangent1);
  parallax.set("aBitangent", bitangent1);
  vertex( w, -w, 0, 2*w, w);
  
  parallax.set("aPos", pos3);
  parallax.set("aNormal", nm);
  parallax.set("aTexCoords", uv3);
  parallax.set("aTangent", tangent1);
  parallax.set("aBitangent", bitangent1);
  vertex( w,  w, 0, 2*w, 2*w);
  
  endShape(CLOSE);
  
  beginShape();
  parallax.set("aPos", pos1);
  parallax.set("aNormal", nm);
  parallax.set("aTexCoords", uv1);
  parallax.set("aTangent", tangent2);
  parallax.set("aBitangent", bitangent2);
  vertex(-w, -w, 0, w, w);
  
  parallax.set("aPos", pos3);
  parallax.set("aNormal", nm);
  parallax.set("aTexCoords", uv3);
  parallax.set("aTangent", tangent2);
  parallax.set("aBitangent", bitangent2);
  vertex( w,  w, 0, 2*w, 2*w);
  
  parallax.set("aPos", pos4);
  parallax.set("aNormal", nm);
  parallax.set("aTexCoords", uv4);
  parallax.set("aTangent", tangent2);
  parallax.set("aBitangent", bitangent2);
  vertex(-w,  w, 0, w, 2*w);
  
  endShape(CLOSE);
}

Maybe this gives you ideas: https://github.com/processing/processing/wiki/Advanced-OpenGL

A uniform set from Processing can not be read as an attribute in the shader. You can set pos and tex coords using vertex(), normals using normal(), but the tangents I don’t know. I haven’t set custom attributes in Processing. You can search for “attribute” in the files in https://github.com/processing/processing/tree/master/core/src/processing/opengl

1 Like

PShape has a whole load of methods for attaching custom vertex attributes that are exceedingly under documented! :confounded: See from eg. https://github.com/processing/processing/blob/master/core/src/processing/opengl/PShapeOpenGL.java#L1115 That might be the better way to do what you’re doing.

PGraphics also has similar attrib methods.

1 Like

@neilcsmith Thank you for that, I think it is a great step in the right direction! This is what I’ve done so far, but it throws an error (multiple times)

PGraphicsOpenGL g_og;
PShader parallax;
PImage bricks_dif, bricks_normal, bricks_disp;

void settings(){
  size(1000, 800, P3D);
}

void setup(){
  g_og = (PGraphicsOpenGL)g;
  
  bricks_dif = loadImage("bricks_diffuse.jpg");
  bricks_normal = loadImage("bricks_normal.jpg");
  bricks_disp = loadImage("bricks_disp.jpg");
  
  parallax = loadShader("fragmentShader2.glsl", "vertexShader2.glsl");
  parallax.set("diffuseMap", bricks_dif);
  parallax.set("normalMap", bricks_normal);
  parallax.set("depthMap", bricks_disp);
  parallax.set("heightScale", 0.2);
  
  rectMode(CORNERS);
}

void draw(){
  background(140, 80, 80);
  
  shader(parallax);

  translate(width/2, height/2, 0);
 
  lights();
  spotLight(50, 50, 50, 800, 200, 800, -1, -0.25, -1, PI/3, 1);
  
  normal(0, 0, 1);
  rotateY(-PI/4);
  rotateX(PI/4);
  
  renderQuad();
}

void attrib(String name, PVector v, int n){
  if (n == 3){
    g_og.attrib(name, v.x, v.y, v.z);
  }
  if (n == 2){
    g_og.attrib(name, v.x, v.y);
  }
}

void renderQuad(){
  PVector pos1 = new PVector(-1.0f,  1.0f, 0.0f);
  PVector pos2 = new PVector(-1.0f, -1.0f, 0.0f);
  PVector pos3 = new PVector( 1.0f, -1.0f, 0.0f);
  PVector pos4 = new PVector( 1.0f,  1.0f, 0.0f);
  // texture coordinates
  PVector uv1 = new PVector(0.0f, 1.0f);
  PVector uv2 = new PVector(0.0f, 0.0f);
  PVector uv3 = new PVector(1.0f, 0.0f);
  PVector uv4 = new PVector(1.0f, 1.0f);
  // normal vector
  PVector nm = new PVector(0.0f, 0.0f, 1.0f);
  
  // calculate tangent/bitangent vectors of both triangles
  PVector tangent1 = new PVector(0, 0, 0), bitangent1 = new PVector(0, 0, 0);
  PVector tangent2 = new PVector(0, 0, 0), bitangent2 = new PVector(0, 0, 0);
  // triangle 1
  // ----------
  PVector edge1 = PVector.sub(pos2, pos1);
  PVector edge2 = PVector.sub(pos3, pos1);
  PVector deltaUV1 = PVector.sub(uv2, uv1);
  PVector deltaUV2 = PVector.sub(uv3, uv1);
  
  float f = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV2.x * deltaUV1.y);
  
  tangent1.x = f * (deltaUV2.y * edge1.x - deltaUV1.y * edge2.x);
  tangent1.y = f * (deltaUV2.y * edge1.y - deltaUV1.y * edge2.y);
  tangent1.z = f * (deltaUV2.y * edge1.z - deltaUV1.y * edge2.z);
  tangent1.normalize();
  
  bitangent1.x = f * (-deltaUV2.x * edge1.x + deltaUV1.x * edge2.x);
  bitangent1.y = f * (-deltaUV2.x * edge1.y + deltaUV1.x * edge2.y);
  bitangent1.z = f * (-deltaUV2.x * edge1.z + deltaUV1.x * edge2.z);
  bitangent1.normalize();
  
  // triangle 2
  // ----------
  edge1 = PVector.sub(pos3, pos1);
  edge2 = PVector.sub(pos4, pos1);
  deltaUV1 = PVector.sub(uv3, uv1);
  deltaUV2 = PVector.sub(uv4, uv1);
  
  f = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV2.x * deltaUV1.y);
  
  tangent2.x = f * (deltaUV2.y * edge1.x - deltaUV1.y * edge2.x);
  tangent2.y = f * (deltaUV2.y * edge1.y - deltaUV1.y * edge2.y);
  tangent2.z = f * (deltaUV2.y * edge1.z - deltaUV1.y * edge2.z);
  tangent2.normalize();
  
  
  bitangent2.x = f * (-deltaUV2.x * edge1.x + deltaUV1.x * edge2.x);
  bitangent2.y = f * (-deltaUV2.x * edge1.y + deltaUV1.x * edge2.y);
  bitangent2.z = f * (-deltaUV2.x * edge1.z + deltaUV1.x * edge2.z);
  bitangent2.normalize();
  
  
  float quadVertices[] = {
      // positions            // normal         // texcoords  // tangent                          // bitangent
      pos1.x, pos1.y, pos1.z, nm.x, nm.y, nm.z, uv1.x, uv1.y, tangent1.x, tangent1.y, tangent1.z, bitangent1.x, bitangent1.y, bitangent1.z,
      pos2.x, pos2.y, pos2.z, nm.x, nm.y, nm.z, uv2.x, uv2.y, tangent1.x, tangent1.y, tangent1.z, bitangent1.x, bitangent1.y, bitangent1.z,
      pos3.x, pos3.y, pos3.z, nm.x, nm.y, nm.z, uv3.x, uv3.y, tangent1.x, tangent1.y, tangent1.z, bitangent1.x, bitangent1.y, bitangent1.z,
  
      pos1.x, pos1.y, pos1.z, nm.x, nm.y, nm.z, uv1.x, uv1.y, tangent2.x, tangent2.y, tangent2.z, bitangent2.x, bitangent2.y, bitangent2.z,
      pos3.x, pos3.y, pos3.z, nm.x, nm.y, nm.z, uv3.x, uv3.y, tangent2.x, tangent2.y, tangent2.z, bitangent2.x, bitangent2.y, bitangent2.z,
      pos4.x, pos4.y, pos4.z, nm.x, nm.y, nm.z, uv4.x, uv4.y, tangent2.x, tangent2.y, tangent2.z, bitangent2.x, bitangent2.y, bitangent2.z
  };
  
  int w = 150;
  
  beginShape();
  texture(bricks_dif);
  
  attrib("aPos", pos1, 3);
  attrib("aNormal", nm, 3);
  attrib("aTexCoords", uv1, 2);
  attrib("aTangent", tangent1, 3);
  attrib("aBitangent", bitangent1, 3);
  vertex(-w, -w, 0, w, w);
  
  attrib("aPos", pos2, 3);
  attrib("aNormal", nm, 3);
  attrib("aTexCoords", uv2, 2);
  attrib("aTangent", tangent1, 3);
  attrib("aBitangent", bitangent1, 3);
  vertex( w, -w, 0, 2*w, w);
  
  attrib("aPos", pos3, 3);
  attrib("aNormal", nm, 3);
  attrib("aTexCoords", uv3, 2);
  attrib("aTangent", tangent1, 3);
  attrib("aBitangent", bitangent1, 3);
  vertex( w,  w, 0, 2*w, 2*w);
  
  attrib("aPos", pos1, 3);
  attrib("aNormal", nm, 3);
  attrib("aTexCoords", uv1, 2);
  attrib("aTangent", tangent2, 3);
  attrib("aBitangent", bitangent2, 3);
  vertex(-w, -w, 0, w, w);
  
  attrib("aPos", pos3, 3);
  attrib("aNormal", nm, 3);
  attrib("aTexCoords", uv3, 2);
  attrib("aTangent", tangent2, 3);
  attrib("aBitangent", bitangent2, 3);
  vertex( w,  w, 0, 2*w, 2*w);
  
  attrib("aPos", pos4, 3);
  attrib("aNormal", nm, 3);
  attrib("aTexCoords", uv4, 2);
  attrib("aTangent", tangent2, 3);
  attrib("aBitangent", bitangent2, 3);
  vertex(-w,  w, 0, w, 2*w);
  
  endShape(CLOSE);
}

And the error:

java.lang.ArrayIndexOutOfBoundsException: 41
	at processing.opengl.PGraphicsOpenGL$TessGeometry.addPolyVertex(PGraphicsOpenGL.java:10301)
	at processing.opengl.PGraphicsOpenGL$Tessellator$TessellatorCallback.vertex(PGraphicsOpenGL.java:13189)
	at processing.opengl.PJOGL$Tessellator$GLUCallback.vertex(PJOGL.java:646)
	at jogamp.opengl.glu.tessellator.GLUtessellatorImpl.callVertexOrVertexData(GLUtessellatorImpl.java:616)
	at jogamp.opengl.glu.tessellator.Render$RenderFan.render(Render.java:334)
	at jogamp.opengl.glu.tessellator.Render.RenderMaximumFaceGroup(Render.java:170)
	at jogamp.opengl.glu.tessellator.Render.__gl_renderMesh(Render.java:116)
	at jogamp.opengl.glu.tessellator.GLUtessellatorImpl.gluTessEndPolygon(GLUtessellatorImpl.java:556)
	at com.jogamp.opengl.glu.GLU.gluTessEndPolygon(GLU.java:896)
	at processing.opengl.PJOGL$Tessellator.endPolygon(PJOGL.java:610)
	at processing.opengl.PGraphicsOpenGL$Tessellator.tessellatePolygon(PGraphicsOpenGL.java:12612)
	at processing.opengl.PGraphicsOpenGL.tessellate(PGraphicsOpenGL.java:2288)
	at processing.opengl.PGraphicsOpenGL.endShape(PGraphicsOpenGL.java:2001)
	at processing.core.PApplet.endShape(PApplet.java:11080)
	at parallax_mapping_2.renderQuad(parallax_mapping_2.java:201)
	at parallax_mapping_2.draw(parallax_mapping_2.java:72)
	at processing.core.PApplet.handleDraw(PApplet.java:2412)
	at processing.opengl.PSurfaceJOGL$DrawListener.display(PSurfaceJOGL.java:871)
	at jogamp.opengl.GLDrawableHelper.displayImpl(GLDrawableHelper.java:692)
	at jogamp.opengl.GLDrawableHelper.display(GLDrawableHelper.java:674)
	at jogamp.opengl.GLAutoDrawableBase$2.run(GLAutoDrawableBase.java:443)
	at jogamp.opengl.GLDrawableHelper.invokeGLImpl(GLDrawableHelper.java:1293)
	at jogamp.opengl.GLDrawableHelper.invokeGL(GLDrawableHelper.java:1147)
	at com.jogamp.newt.opengl.GLWindow.display(GLWindow.java:759)
	at com.jogamp.opengl.util.AWTAnimatorImpl.display(AWTAnimatorImpl.java:81)
	at com.jogamp.opengl.util.AnimatorBase.display(AnimatorBase.java:452)
	at com.jogamp.opengl.util.FPSAnimator$MainTask.run(FPSAnimator.java:178)
	at java.util.TimerThread.mainLoop(Timer.java:555)
	at java.util.TimerThread.run(Timer.java:505)

I looked into the PGraphicsOpenGL implementation to try to determine what is causing this but it didn’t work :stuck_out_tongue: Any ideas on that?

1 Like

// Exemplifies the use of the ppixels uniform in the shader, that gives
// access to the pixels of the previous frame.

See also processing-3.5.4\modes\java\examples\Topics\Shaders\Conway.pde

i think it is useful for you