1
$\begingroup$

I have an image and I want to draw an arbitrary number of objects on that image. The center coordinates of those objects are calculated inside a fragment shader after series of image processing operations. However, because fragment shader gets executed per-fragment, I cannot draw objects centered on those points in the same shader in a reasonably fast way. Somehow, I need to pass those center coordinates that I calculated in my fragment shader to another fragment shader in a second render pass, preferably as uniforms. Then I can use those coordinates in the second fragment shader to draw my objects in an efficient way.

I thought maybe I can render those points as white spots on a black texture, and after the first pass, I can search the raw data of the texture on the CPU side, then add those white points' coordinates into an array, and send them as uniforms. However, I guess it would be very inefficient as it is a very sparse data (a lot of black pixels and very few white pixels), and I would be doing thousands of iterations (even for a simple 720p image) on that raw data. So, I'm not sure if this should be the way to go.

How can I do this in an efficient way, in OpenGL ES 2.0?

P.S. I'm new to this area, please enlighten me if I made no sense.

$\endgroup$
2
  • $\begingroup$ "in OpenGL ES 2.0 & Metal" These APIs represent two very different classes of hardware. Also, are you sure you want to use a fragment shader to do this? Wouldn't it make more sense to use a compute shader (in Metal)? $\endgroup$ – Nicol Bolas Oct 16 '20 at 2:41
  • $\begingroup$ Yes, you're right, I guess I should remove the Metal part, it's a bit broad. $\endgroup$ – M. Samil Atesoglu Oct 16 '20 at 9:34
1
$\begingroup$

I'm assuming that you don't know how many objects there will be or have any way to index them until the image processing operations are completed, i.e. you have some final pass that determines for each pixel "do I want to put an object here, or no".

OpenGL ES 2.0 is pretty limiting. There may be no better way to do this than what you described: output from the fragment shader to a texture, pull it back to the CPU to extract the points, then put those into a uniform buffer for the second pass.

One thing you could attempt, though I'm unsure if it could be fully made to work in ES 2.0, is to do a parallel prefix sum over the output texture from the first pass. This would involve recursive fragment shader reduction passes (a little bit like generating mipmaps) that would first count up the number of objects within each region of the image, starting with 2×2 regions and doubling at each step until you've covered the full image, then go back down the mip chain and calculate the prefix sums, which are the number of objects "before" each region (using some defined ordering). At the end of that, you would have the exact index where to store each object into an output buffer.

FYI, in GL ES 3.1 and other more fully-featured APIs, there are shader atomic counters, which allow implementing an "append buffer"; your first fragment shader pass could output directly to this buffer, then turn around and use it for an input buffer, or for indirect draw parameters, on the next pass.

$\endgroup$
1
  • $\begingroup$ Thanks a lot for the information! $\endgroup$ – M. Samil Atesoglu Dec 8 '20 at 6:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.