Rendering many objects with a shader

Hello there! I made a fragment shader that can render circles, and would like to use it inside Processing as a replacement for Processing’s own functions.

An extra question, if it is appropriate to ask this much in one thread:

In the future, I would like to render many of these at once. How do I approach this? Can the shader() function be called repetitively? Do I make a uniform in my shader which is just an array of vec2s of a large size, then specify an int to specify how many are being sent? (I would also send the radius of each circle in another array, …or whatever else is necessary along). Is there another way of doing it? Does Processing not allow for something like this…? (There is no mention of sending a PVector array in the reference, or any other way to pass many vec-ns in, unless of course, I am allowed to do something like: shaderProgram.set("vec2array[" + i + ']')), where i is an index generated using a for loop. As far as I know, arrays in C and C++ need to have their sizes specified at compile time, and that GLSL does NOT allow for memory allocation in any way.)

Finally, here is all the code I’ve used:

PShader circles;

void setup() {
  size(640, 480, P2D);
  circles = loadShader("circ.glsl");
}


void draw() {
  background(0);

  circles.set("resolution", new float[]{(float) width, (float)height});
  circles.set("time", millis() * 0.001f);

  shader(circles);
}

(Those notes…is this too informal…? -_-)

// Everything but the last
// `9` minutes of:
// [ https://youtu.be/xf7Y988cPRk ]

//@TODO: Make this an "`API`"
// which stores data in arrays
// and renders using some other
// `function`..I dunno.

// Also, PARTICLE PHYSICS ANYONE!? :D?
// (..you still need the CPU's
//  batch data -_-)


#ifdef GL_FRAGMENT_PRECISION_HIGH
  precision highp float;
#else
  precision mediump float;
#endif

  // Data being transferred:
  uniform vec2 resolution;
uniform float time;

// Actual variables:
float scr; // Aspect ratio.
vec2 uv; //..."vec2 uv;". Yeah. :rofl:

// Function definitions:
void circle(float _radius, vec2 _pos);

void main(void) {
  uv = gl_FragCoord.xy /
    resolution.xy * 2.0 - 1.0;
  scr = resolution.x / resolution.y;


  // gl_FragColor += vec4(uv, 1.0, 1.0);
  // gl_FragColor = vec4(0.25, .0, .0, .0);

  gl_FragColor = vec4(.0, .0, .0, 1.);
  circle(.1, vec2(.5, .1));
  circle(.3, vec2(.1, .1));

  /*gl_FragColor.xyz *= mat3(
   1., 2., 1.,
   2., 1., 1.,
   2., 1., 1.);*/

  // gl_FragColor.a = dist;
  // ^^^ Remove background
}

// PLEASE NOTE: The screen's aspect
// ratio, "`scr`" MUST be available
// as a **global** variable in the
// shader program you use this
// function in! Pass it in as
// an argument to this function,
// otherwise.
// ..calling it `scr`, of course.

void circle(float circle_r, vec2 circle_pos) {
  vec2 circle_uv = gl_FragCoord.xy /
    resolution.xy * 2.0 - 1.0;

  // I know that these variables are a
  // nightmare to type, but this is `C`.
  // What now?

  circle_uv.x *= scr;
  circle_uv.x -= circle_pos.x;
  circle_uv.y += circle_pos.y;

  float circle_dist = circle_r - length(circle_uv);
  // ^^^ Again, you can use
  // `dot(uv, uv)` here.

  circle_dist = step(.0, circle_dist);
  gl_FragColor.rgb +=
    vec3(circle_dist);
  // gl_FragColor.a = circle_dist;
  // ^^^ Remove background..?
}

Hi :slight_smile:

The default light shader does use an array of vec, see

and you can indeed use

shdr.set("myUniform[" + i + "]", 3.5);

But I would ask… why do that? :slight_smile: Why not use also the vertex shader and send actual circles to the GPU?

Because if you draw a lot of circles using just the fragment shader it’s going to be much slower, or? Each pixel in the shader will have to be aware of all the existing circles (stored in an array) and the GLSL code will have to iterate over all the circles even if it will just draw one pixel belonging to one circle.

1 Like

Thank you so much for answering! I should’ve been more thoughtful. Using Processing’s built-in functions, which already do this for me is good enough :+1:.

Although I wonder if there is a way to get it to work with NDCs…
I’ll open another thread for that, perhaps.

1 Like