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.
![]()
PGraphics pgLocs;
color xyToRGBA(PVector loc) {
PVector l = loc.copy();
l.mult(255);
float xr = l.x-floor(l.x);
float yr = l.y-floor(l.y);
xr *= 255;
yr *= 255;
return color(floor(l.x), floor(xr), floor(l.y), floor(yr));
}
PVector RGBAtoXY(color c) {
float r = red(c)/255.0;
float g = green(c)/65025.0;
float b = blue(c)/255.0;
float a = alpha(c)/65025.0;
return new PVector((r+g), (b+a));
}
PShader psRender;
PGraphics pgSprite;
void setup() {
size(800, 800, P3D);
pgLocs = createGraphics(3000, 1, P2D);
pgSprite = createGraphics(20, 20, P2D);
pgSprite.beginDraw();
pgSprite.background(0);
pgSprite.fill(255);
pgSprite.ellipseMode(CENTER);
pgSprite.ellipse(10, 10, 20, 20);
pgSprite.endDraw();
psRender = loadShader("pointVert.glsl", "pointFrag.frag");
psRender.set("tex_position", pgLocs);
psRender.set("tex_sprite", pgSprite);
psRender.set("wh_viewport", width, height);
psRender.set("wh_position", 3000, 1);
psRender.set("point_size", 4);
pgLocs.beginDraw();
for (int i = 0; i < pgLocs.width; i++) { // fill pgLocs with random locations
PVector loc = new PVector(random(width)/width, random(height)/height);
pgLocs.set(i, 0, xyToRGBA(loc));
}
pgLocs.endDraw();
noLoop();
}
void draw() {
stroke(0);
strokeWeight(5);
background(255);
//image(pgSprite,0,0);
shader(psRender); // What I wish would work
//fill(255);
//rect(0, 0, width, height);
for (int i = 0; i < pgLocs.width; i++) { // What I'd like to do in a shader instead
color c = pgLocs.get(i, 0); //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
}
}
pointFrag.frag
#version 150
uniform float point_size;
uniform ivec2 wh_position;
uniform sampler2D tex_position;
uniform vec4 col_A = vec4(1, 1, 1, 1.0);
uniform vec4 col_B = vec4(0, 0, 0, 0.0);
out vec2 location;
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(){
int point_id = gl_VertexID;
int row = point_id / wh_position.x;
int col = point_id - wh_position.x * row;
vec4 color = vec4(texture2D(tex_position, ivec2(col, row)));
location = posDecode(color);
gl_Position = vec4(location * 2.0 - 1.0, 0, 1);
gl_PointSize = point_size;
}
pointVert.glsl
#version 150
uniform float point_size;
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);
out vec4 out_frag;
in vec2 location;
void main(){
vec2 my_PointCoord = ((location * wh_viewport) - gl_FragCoord.xy) / point_size + 0.5;
float falloff = 1.0 - texture(tex_sprite, my_PointCoord.xy).a;
out_frag = mix(col_A, col_B, falloff);
out_frag = clamp(out_frag, 0.0, 1.0);
}