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!