hint(DISABLE_OPTIMIZED_STROKE) & Processing Matrices

Hello everybody,

I have been struggling with this issue and I can’t seem to find a solution.

I want to create a Sphere looking Particle system, using billboarding and a normal map for shading, to avoid having to handle actual spheres.

So far it works great as you can see :

Sketch :


import peasy.*;

//Camera
PeasyCam cam;

//Shader informations
PShader pointShader;
PImage normalMap;

float weight = 10;

//Lights
PVector lightPos; 
PVector lightPosCamSpace;

ArrayList<PVector> points;


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

  cam = new PeasyCam(this, 100);
  //hint(DISABLE_OPTIMIZED_STROKE);

  normalMap = loadImage("normalMapSphere.png");

  pointShader = loadShader("normPointLightFrag.glsl", "normPointLightVert.glsl");
  pointShader.set("normalMap", normalMap);
  pointShader.set("weight", weight);
  strokeWeight(weight);
  strokeCap(SQUARE);
  stroke(255);

  points = new ArrayList();
  for (int i = 0; i < 10000; i++) {
    points.add(new PVector(random(-100, 100), random(-100, 100), random(-100, 100)));
  }

  lightPos = new PVector();
  lightPosCamSpace = new PVector();
}


void draw() {
  background(0);
  lightPos.set(200*cos(millis()/2000f), 200*sin(millis()/500f), 200*sin(millis()/2000f));

  PMatrix modelview = getMatrix();
  modelview.mult(lightPos, lightPosCamSpace);
  pointShader.set("lightPos", lightPosCamSpace);
  pointShader.set("time", millis()/1000f);

  shader(pointShader);
  beginShape(POINTS);
  for (int i = 0; i < points.size(); i++) {
    vertex(points.get(i).x, points.get(i).y, points.get(i).z);
  }
  endShape();


  //Light positionning
  pushMatrix();
  translate(lightPos.x, lightPos.y, lightPos.z);
  fill(255);
  sphere(10);
  popMatrix();


  surface.setTitle("fps " + frameRate);
}

The normal map of the sphere :
normalMapSphere|500x500

Vertex Shader

uniform mat4 projection;
uniform mat4 modelview;
uniform mat4 modelviewInv;
uniform mat3 normalMatrix;
uniform mat4 view;


uniform mat4 transform;

uniform float weight;
uniform vec3 lightPos;
uniform float time;

attribute vec4 position;
attribute vec4 color;
attribute vec2 offset;

varying vec4 vertColor;
varying vec2 texCoord;

varying vec3 ecVertex;

void main() {

  vec4 pos = modelview * position;

  vec4 clip = projection * pos;

  gl_Position = clip + projection * vec4(offset, 0, 0);

  //Calculate direction in vertex Shader
  ecVertex = pos.xyz + vec3(offset, 0);

  texCoord = (vec2(0.5) + offset / weight);

  vertColor = color;
}

Fragment Shader

#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif

uniform sampler2D normalMap;

uniform mat4 projection;
uniform mat4 modelview;
uniform mat3 normalMatrix;

uniform vec3 lightPos;

//varying vec3 direction;
varying vec3 ecVertex;
varying vec4 vertColor;
varying vec2 texCoord;

void main() {
  
  vec4 tex = texture2D(normalMap, texCoord) * vertColor;

  vec3 direction = normalize(lightPos.xyz - ecVertex);   


  vec3 normal = normalize(texture2D(normalMap, texCoord).xyz *2.0 - 1.0);
  vec3 ecNormal = normalize(normalMatrix * normal);  

  float diff = max(0.0, dot(direction, ecNormal));
  float amb = 0.1;

  vec3 color = vec3(1., 0, 0) * (diff + amb);

  if(tex.a < 0.5)
        discard;
  gl_FragColor = vec4(color, 1.);
}

Now I want to move my particles in my vertex shader. For that, I use the hint(DISABLE_OPTIMIZED_STROKE), and this is where it goes wrong.

The lighting behave correctly for a camera leaved untouched, and does not take into account any camera manipulation.

Any idea of the matrix manipulation I am doing wrong?


import peasy.*;

//Camera
PeasyCam cam;

//Shader informations
PShader pointShader;
PImage normalMap;

float weight = 10;

//Lights
PVector lightPos; 
PVector lightPosCamSpace;

ArrayList<PVector> points;


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

  cam = new PeasyCam(this, 100);
  hint(DISABLE_OPTIMIZED_STROKE);

  normalMap = loadImage("normalMapSphere.png");

  pointShader = loadShader("normPointLightFrag.glsl", "normPointLightVert.glsl");
  pointShader.set("normalMap", normalMap);
  pointShader.set("weight", weight);
  strokeWeight(weight);
  strokeCap(SQUARE);
  stroke(255);

  points = new ArrayList();
  for (int i = 0; i < 10000; i++) {
    points.add(new PVector(random(-100, 100), random(-100, 100), random(-100, 100)));
  }

  lightPos = new PVector();
  lightPosCamSpace = new PVector();
}


void draw() {
  background(0);
  lightPos.set(200*cos(millis()/2000f), 200*sin(millis()/500f), 200*sin(millis()/2000f));

  PMatrix modelview = getMatrix();
  modelview.mult(lightPos, lightPosCamSpace);
  pointShader.set("lightPos", lightPosCamSpace);
  pointShader.set("time", millis()/1000f);

  shader(pointShader);
  beginShape(POINTS);
  for (int i = 0; i < points.size(); i++) {
    vertex(points.get(i).x, points.get(i).y, points.get(i).z);
  }
  endShape();


  //Light positionning
  pushMatrix();
  translate(lightPos.x, lightPos.y, lightPos.z);
  fill(255);
  sphere(10);
  popMatrix();


  surface.setTitle("fps " + frameRate);
}

new Vertex Shader

uniform mat4 projection;
uniform mat4 modelview;
uniform mat4 modelviewInv;
uniform mat3 normalMatrix;
uniform mat4 view;


uniform mat4 transform;

uniform float weight;
uniform vec3 lightPos;
uniform float time;

attribute vec4 position;
attribute vec4 color;
attribute vec2 offset;

varying vec4 vertColor;
varying vec2 texCoord;

varying vec3 ecVertex;

void main() {

  vec4 position2 = position;
  position2.xyz += 30. * vec3(cos(time/2. + position.x/100), cos(time/2. + position.y/100), cos(time/2. + position.z/100)); 

  vec4 pos = modelview * position2;

  vec4 clip = projection * pos;

  gl_Position = clip + projection * vec4(offset, 0, 0);

  //Calculate direction in vertex Shader
  ecVertex = pos.xyz + vec3(offset, 0);

  texCoord = (vec2(0.5) + offset / weight);

  vertColor = color;
}

Thanks for your help!

Hey!

I solved my problem and found the reason of the weird behavior.
The issue comes from the normal Matrix that behaves differently if hint(DISABLE_OPTIMIZED_STROKE) or hint(ENABLE_OPTIMIZED_STROKE).

I tried to recalculate the normalMatrix, but it doesn’t change anything.

If someone have an explanation about it… Digging into Proccessing sources did not help me understand :frowning:

Modified sketch that shows the problem :


import peasy.*;

//Camera
PeasyCam cam;

//Shader informations
PShader pointShader;
PImage normalMap;

float weight = 10;

//Lights
PVector lightPos; 
PVector lightPosCamSpace;

ArrayList<PVector> points;

int modes;


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

  cam = new PeasyCam(this, 100);
  //hint(DISABLE_OPTIMIZED_STROKE);

  normalMap = loadImage("normalMapSphere.png");

  pointShader = loadShader("normPointLightFrag.glsl", "normPointLightVert.glsl");
  pointShader.set("normalMap", normalMap);
  pointShader.set("weight", weight);
  pointShader.set("modes", 0);

  strokeWeight(weight);
  strokeCap(SQUARE);
  stroke(255);

  points = new ArrayList();
  for (int i = 0; i < 2000; i++) {
    points.add(new PVector(random(-100, 100), random(-100, 100), random(-100, 100)));
  }

  lightPos = new PVector();
  lightPosCamSpace = new PVector();

  modes = 0;
}


void draw() {

  background(0);
  lightPos.set(200*cos(millis()/2000f), 200*sin(millis()/4000f), 200*sin(millis()/2000f));

  PMatrix3D normalMatrix = ((PGraphicsOpenGL)g).modelview.get();
  normalMatrix.invert();
  normalMatrix.transpose();
  PMatrix modelview = getMatrix();
  modelview.mult(lightPos, lightPosCamSpace);
  pointShader.set("lightPos", lightPosCamSpace);

  pointShader.set("normalMatrix", normalMatrix);
  pointShader.set("time", millis()/1000f);

  shader(pointShader);
  beginShape(POINTS);
  for (int i = 0; i < points.size(); i++) {
    vertex(points.get(i).x, points.get(i).y, points.get(i).z);
  }
  endShape();


  //Light positionning
  pushMatrix();
  translate(lightPos.x, lightPos.y, lightPos.z);
  fill(255);
  sphere(10);
  popMatrix();


  surface.setTitle("fps " + frameRate);
}


PMatrix3D transposeInverse(PMatrix3D mat) {
  mat.invert();
  mat.transpose();
  return mat;
}




void mouseClicked() {
  modes= (modes + 1) % 6;
  switch (modes) {
  case 0:
    println("Case 0");
    println("Enabled optimized stroke");
    println("Diffuse shading");
    hint(ENABLE_OPTIMIZED_STROKE);
    pointShader.set("modes", 0);
    break;
  case 1:
    println("Case 1");
    println("Enabled optimized stroke");
    println("NormalMatrix * Normal shading");
    hint(ENABLE_OPTIMIZED_STROKE);
    pointShader.set("modes", 1);
    break;
  case 2:
    println("Case 2");
    println("Enabled optimized stroke");
    println("Normal shading");
    hint(ENABLE_OPTIMIZED_STROKE);
    pointShader.set("modes", 2);
    break;
  case 3:
    println("Case 3");
    println("Disabled optimized stroke");
    println("Diffuse shading");   
    hint(DISABLE_OPTIMIZED_STROKE);
    pointShader.set("modes", 3);
    break;
  case 4:
    println("Case 4");
    println("Disabled optimized stroke");
    println("NormalMatrix * Normal shading");
    hint(DISABLE_OPTIMIZED_STROKE);
    pointShader.set("modes", 4);
    break;
  case 5:
    println("Case 5");
    println("Disabled optimized stroke");
    println("Normal shading");    
    hint(DISABLE_OPTIMIZED_STROKE);
    pointShader.set("modes", 5);
    break;
  }
}

Vertex Shader

uniform mat4 projection;
uniform mat4 modelview;
uniform mat4 modelviewInv;
uniform mat3 normalMatrix;
uniform mat4 view;


uniform mat4 transform;

uniform float weight;
uniform vec3 lightPos;
uniform float time;

uniform int modes;

attribute vec4 position;
attribute vec4 color;
attribute vec2 offset;

varying vec4 vertColor;
varying vec2 texCoord;

varying vec3 ecVertex;

void main() {

  vec4 pos = modelview * position;

  vec4 clip = projection * pos;

  gl_Position = clip + projection * vec4(offset, 0, 0);

  ecVertex = pos.xyz + vec3(offset, 0);

  texCoord = (vec2(0.5) + offset / weight);

  vertColor = color;
}

Fragment Shader

#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif

uniform sampler2D normalMap;

uniform mat4 projection;
uniform mat4 modelview;
uniform mat3 normalMatrix;

uniform vec3 lightPos;

uniform int modes;

//varying vec3 direction;
varying vec3 ecVertex;
varying vec4 vertColor;
varying vec2 texCoord;

void main() {
  
  vec4 tex = texture2D(normalMap, texCoord) * vertColor;

  vec3 direction = normalize(lightPos.xyz - ecVertex);   


  vec3 normal = normalize(texture2D(normalMap, texCoord).xyz *2.0 - 1.0);
  vec3 ecNormal = normalize(normalMatrix * normal);  

  float diff = max(0.0, dot(direction, ecNormal));
  diff = max(0.0, dot(direction, normal));
  float amb = 0.1;

  vec3 color = vec3(0.);

  switch(modes){
    case 0:
      //Enabled optimized stroke
      color = vec3(1., 0, 0) * (diff + amb);
      break;
    case 1:
      //Enabled optimized stroke
      color = ecNormal;
      break;
    case 2:
      //Enabled optimized stroke
      color = normal;
      break;
    case 3:
      //Disabled optimized stroke
      color = vec3(1., 0, 0) * (diff + amb);
      break;
    case 4:
      //Disabled optimized stroke
      color = ecNormal;
      break;
    case 5:
      //Disabled optimized stroke
      color = normal;
      break;
}

  if(tex.a < 0.5)
        discard;
  gl_FragColor = vec4(color, 1.);
}

Cheers !

1 Like