picking
Posted by ul on Dec 24, 2013; 9:29am
URL: https://forum.jogamp.org/picking-tp4031052.html
Hi,
I'm considering a switch to OpenGL from Direct3D.
I'm using a shader approach to picking and I'm wondering whether something similar would be possible in OpenGL using Jogl?
I have dedicated the geometry shader for picking. It's possible to remove and insert this shader into the graphics pipeline. It's also possible to make the pipeline stop at this shader so nothing appears on screen. In the application there are two modes. One for drawing without the geometry shader and one for picking with the geometry shader present.
All objects that are drawn in a frame enter the geometry shader in the form of a sequence of triangles. In the shader a unigue integer is available as an identifier for each object. Id's are assigned by the application. Also the origin and direction of the pick ray is available in the geometry shader. For each triangle that arrives the shader checks whether it intersects with the pick ray. If it does, the distance from the pick ray origin to the intersection point with the triangle, and the object id is sent back to the application via a pipeline feature called stream output. The application then checks all hit candidates and selects the closest one to the pick point. The object id tells which object was picked.
[code]
struct StreamRecord { // stream output data
int objectID : OBJECT_ID;
float distance : DISTANCE;
};
// geometry shader writes to stream output if triangle intersects with pick ray
[maxvertexcount(1)]
void GS_pickShader(triangle CommonVertexStruct input[3], inout PointStream<StreamRecord> output) {
int id = input[0].objectID;
if (id >= 0) { // only consider non-negative object id:s
float d = ray_triangle_intersection(pickOrigin, pickDirection, input[0].posW, input[1].posW, input[2].posW);
if (d > ZERO) { // pick candidate
StreamRecord r = {id, d};
output.Append(r); // to stream output
}
}
}
[/code]
As a summary the application does this,
1. Insert and remove the pick shader (switches between draw and pick mode).
2. Calculate the pick ray and assign id's to objects.
3. Send pick ray and objects with id's to the pipeline.
4. Select the picked object among the candidates that are reported back from the pick shader.
The pick shader does this,
1. Determine whether the pick ray intersects with arriving triangles.
2. Report hits back to the application.
This approach turns out to be very fast because most calculations are done on the GPU. It's as fast as drawing one frame if not faster since no actual drawing is done in pick mode. The approach is also very general since every object with a surface is triangulated anyway as part of the drawing process so the triangles are for free in this sense. And no complex extra data structure must be maintained by the application other than what's kept for drawing anyway. In fact it's as close to a free lunch as it gets!