Picking 3D

Started by HikkiGuy, November 25, 2013, 00:24:31

Previous topic - Next topic

HikkiGuy

Guys please help. For last 2 days i tried to find some information about picking object in 3d. I have found many topics, tutorials and etc. Now i know what there's 2 ways - color picking and ray picking. But without full source code i can't understand all this stuff. If you have some simple code please just show it to me. I would be very thankful :З

quew8

I'm afraid it is not a simple topic. There is no "simple" code example to give. There are a multitude of ways of doing it each very different from the last. I suggest taking a look at some of the other threads about picking. For Example:

http://lwjgl.org/forum/index.php/topic,5157.0.html
http://lwjgl.org/forum/index.php/topic,4867.0.html

those are just a couple, but searching "picking" in the search bar gives lots of results. You will notice that most of these span several pages - an indication of the complexity for newcomers of this topic.

quew8

Also I just found this on JGO, skipped over most of it but maybe useful to you. http://www.java-gaming.org/topics/picking-techniques/31301/view/topicseen.html

abcdef

Any easy way to think about picking is as follows, when you render your code in opengl. By default you are at position (0,0,0) and have a rotation equal to the identity matrix so that (x,y,z) when multiplied by this rotation gives (x,y,z). As you render your scene you generally have a camera and this determines where to move to and what rotation to apply. To adjust the whole scene.

The rotation matrix you have is quite helpful as it automatically gives you forward ray vector (third row), the right ray vector (1st row) and the up ray vector (2nd row). If you use shaders to rotate the camera then you will have this by default, if you then add on the position vector you will have exactly what you are after.

Of course you may want to work out the ray at a different location other than center of the screen. You can do this on demand by doing some simple maths (just finding the hypotenuse vector of a simple right angled triangle, forward ray and vector of the difference between the clicked point and the center screen are the two sides you know).

ul

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. This could also be of help to the OP and that's why I post it here.

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.


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
		}
	}
}


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!  ;D