Screen positions of many vertices

I am using OpenGL ES to display the sky in an astronomy app on Android. I need to display thousands of stars, which is no problem. But I need a fast and elegant way to retrieve the positions of those vertices in screen coordinates to know on which star a click (=selection) with the mouse occurred.

I tried with a TransformFeedback, which works but is too slow. I could compute the positions of all stars separately by inversion of the coordinate transformation, which is also slow.

Does anybody know, how other astronomy programs (like Stellarium for instance) perform this task? I do not need specific code but only a general hint on how to do this.

Thanks for your suggestions.

Edit: I have to add that I am using OpenGL ES 3 on an Android device.

have you tried gluProject? i have never had any performance issues using that, some thousand calls shoudl not take too long.

Why not going “color picking” ? That just requires you to render to another target, giving a unique id to each star, and read back from this target at the position of the mouse. This will be exact at the pixel. You might face issues if two or more stars are at the same pixel though.

Stellarium is open source !

if the star has a size of only one pixel on screen, it might be pretty hard to pick.
for a scenario like this, i would always be in favor of a “if abs(mousePosition-starPosition) < 10 pixels” solution.
if you have only big items on the screen, color picking may be a better way to do it.

True. But then you can probe the neighborhood. That would still be more accurate and fast than with using unProject, I suppose.

gluProject, not unProject :wink:

another word about performance: of course you have to calculate the star position only after the view has changed. if you change the view direction with mouse drag (=mouse click + mouse motion), i would recommend to calculate the screen position only after a mouse release event and store it in the star object class, which you probably have, e.g.

class Star {
double x, y, z; // position in the universe
int screenX, screenY; // position on your screen

I read you too quickly. You’re right, that’s also a clever idea. And I better understand your previous post too now :slight_smile:
But all of this ends up in a linear complexity algorithm. You need to do that for all stars. That might be sustainable for 1000 stars thought.
And if you have several stars very near from each others, your inequality will end up selecting not a single star. So you have to calculate distances and take the closest one.

If the OP wishes to keep doing it like this, that might be done in the vertex shader, outputting the screen coordinate values in an SSBO. Should be more fast.

Thanks a lot for your comments. I have to mention that I use OpenGL ES 3 on Android. I am afraid that thousands of calls to gluProject or gluUnProject are too slow on Android. For “color picking”, wouldn’t I have to call glReadPixel after each draw (which is slow)? I searched the Stellarium code for a solution but without success (its a large piece of code). The approach using SSBO sounds quite interesting, I will read more about that.

Is the viewpoint fixed? I.e. is the view always from Earth, or can it be from an arbitrary point in space?

If it’s fixed, build a cube-map spatial index. For each star, determine which of the six faces it should appear on, then transform its 3D position to a 2D position on that face. So for each face you have either a 2D array or a quadtree where each “cell” contains a list of stars within that cell. Upon receiving a click event, transform the position to the cube map space and perform a lookup. When clicking near an edge or corner, you’ll (ideally) need to consider the two or three faces adjacent to that edge or corner.

If the viewpoint isn’t fixed, the task is somewhat harder. You’ll need to use a 3D array or octree and perform a ray-cast based upon the viewpoint and the click coordinates.

Either way, you need some form of spatial index; you don’t want to be testing every star to determine which is closest.

Why after each draw ? After each picking action, and only if the view had changed (I’m supposing that time didn’t changed a lot, so stars remained at the same position, otherwise, you’ll have to take this into account too). Just read all the pixels back from your second rendertarget to the CPU. And then just get the color id at the matching index.

To avoid being “pixel-perfect”, you can use bigger primitives (such as icospheres) than actual stars when drawing to the special target.