We are about to switch to a new forum software. Until then we have removed the registration on this forum.
I want to pass a shader a texture of encoded locations, and have it draw points at the decoded locations.
I have a particle system stored in a texture that's 3000x1, with the x and y locations encoded into RGBA.
Currently I'm having to use the CPU to loop through particles and use point() to draw it to a new texture. I know this is being done properly in a shader in the PixelFlow library, but I can't figure it out, studying particleRender.glsl.
How can I get a shader to replicate whats going on in draw()? It feels like it should be easy but from what I've read on the PShader page and book of shaders I can't piece it together.
Edit: I've updated with my attempt at hacking away at PixelFlow's particleRender.glsl, it isn't throwing errors, but it isn't drawing anything either. I'm not used to the way version 150 works so maybe it's something simple. I've tried lots of trouble shooting and I can't get that shader to draw anything at all.
edit2: I've worked at it for hours, only a tiny bit of progress, a little sign of life from the shader, but I have no idea what it's doing. It's drawing what seems to be a random quad.
PGraphics pgLocs;
PShader psRender;
void setup() {
size(800, 800, P3D);
int totalPoints = 3000;
pgLocs = createGraphics(totalPoints, 1, P2D);
psRender = loadShader("pointFrag.frag", "pointVert.glsl");
psRender.set("tex_position", pgLocs);
psRender.set("wh_viewport", width, height);
psRender.set("wh_position", totalPoints, 1);
psRender.set("point_size", 4);
psRender.set("totalPoints", totalPoints);
randomFill();
}
void randomFill() {
pgLocs.beginDraw(); // fill pgLocs with random locations
for (int i = 0; i < pgLocs.width; i++) {
PVector loc = new PVector(random(width)/width, random(height)/height);
pgLocs.set(i, 0, xyToRGBA(loc));
}
pgLocs.endDraw();
psRender.set("tex_position",pgLocs);
}
void keyPressed() {
randomFill();
}
void draw() {
stroke(0);
strokeWeight(5);
background(55);
// // What I wish would work
shader(psRender);
//ill(255,100);
//rect(0, 0, width, height);
pgLocs.loadPixels();
for (int i = 0; i < pgLocs.width; i++) { // What I'd like to do in a shader instead
color c = pgLocs.pixels[i];// //get pixel color
PVector loc = RGBAtoXY(c); // decode location
stroke(c); // set color just for fun
point(loc.x*width, loc.y*height); // show location was stored in the texture properly
}
filter(psRender);
}
color xyToRGBA(PVector loc) { // pack x into r g, y into b a
PVector l = loc.copy().mult(255);
int xi = floor(l.x);
int yi = floor(l.y);
int xr = floor((l.x-xi)*255);
int yr = floor((l.y-yi)*255);
return (yr << 24) | (xi << 16) | (xr << 8) | yi;
}
PVector RGBAtoXY(color c) {
int a = ((c >> 24) & 0xff) ;
int r = ((c >> 16) & 0xff) ;
int g = ((c >> 8) & 0xff) ;
int b = (c & 0xff) ;
return new PVector((r+g/255.0)/255.0, (b+a/255.0)/255.0);
}
pointFrag.frag
#version 150
uniform vec2 wh_viewport;
uniform sampler2D tex_position;
uniform sampler2D tex_sprite;
uniform vec4 col_A = vec4(1, 1, 1, 1.0);
uniform vec4 col_B = vec4(0, 0, 0, 0.0);
in vec2 location;
in float my_PointSize;
out vec4 out_frag;
void main(){
vec2 my_PointCoord = ((location * wh_viewport) - gl_FragCoord.xy) / my_PointSize + 0.5;
out_frag = vec4(1.0,0,0,0);
}
pointVert.glsl
#version 150
uniform float point_size;
uniform sampler2D tex_position;
uniform vec4 col_A = vec4(1, 1, 1, 1.0);
uniform vec4 col_B = vec4(0, 0, 0, 0.0);
uniform int totalPoints;
out vec2 location;
out float my_PointSize;
vec2 posDecode(vec4 c) {
float r = c.r;
float g = c.g/255.0;
float b = c.b;
float a = c.a/255.0;
return vec2((r+g), (b+a));
}
void main(){
float x = gl_VertexID/ float(totalPoints);
vec4 color = vec4(texture2D(tex_position, vec2(x,1.0)));
location = posDecode(color);
location.y = 1-location.y;
gl_Position = vec4(location * 2.0 - 1.0, 0, 1); //vec4(location.x,location.y,0,1);//
gl_PointSize = point_size;
my_PointSize = point_size;
}
edit3: Still no luck figuring it out. I found more of the puzzle in pixelflow. These calls seem important gl.glEnable(GL3.GL_PROGRAM_POINT_SIZE); gl.glDrawArrays(GL2.GL_POINTS, 0, num_points);
This is what I'm trying to implement this into. I think I could do a million path finders instead of tens of thousands.
Answers
I got it working. I'm using a magic number, I have no idea where it comes from and it's probably because I'm doing something wrong/improperly. Any ideas where this 1.731875 number in my vert shader comes from? It's needed to match the scale. Also none of my .set("var",var) type stuff is working with my shader, any idea what could cause that?
.....
....
sketch
To push values into the shader's "wh" variable, cast "width" and "height" to floats. (or send f[0] and f[1] for width and height respectively)
Vec'n' types expect to have floating point values. There are integer vectors uvec'n' and ivec'n' but that is a whole other can of worms. ;)
https://www.khronos.org/opengl/wiki/Data_Type_(GLSL)#Vectors
As for 1.731875, it is nearly the square root of 3 which would also be the length of a vector (1,1,1)... but that is all I have without guessing.