SharpGL-Mouse Detection Clicking on OpenGL Elements with Selection and Selection

I am implementing 2D graphics in WPF using the SharpGL library. I managed to draw some primitive objects on the screen, and I need to detect mouse clicks on these objects.

I reviewed the OpenGL tutorial on how to select and select graphic objects, but I was not able to get it to work. In my test application, I draw three triangles on the screen, and when I click the mouse I draw the same three triangles in GL_SELECT mode, hoping to detect if any of the triangles was pressed. I am not sure if this is the right approach. The Hit test always returns all elements from the selection buffer.

I know that the width and height parameters in PickMatrix are incorrect, and I'm not quite sure that the correct values ​​will be there. Is it the width and height of the whole view?

 private void OpenGLControl_OpenGLDraw(object sender, SharpGL.SceneGraph.OpenGLEventArgs args) { //// Get the OpenGL object. OpenGL gl = args.OpenGL; //set background to white gl.ClearColor(1.0f, 1.0f, 1.0f, 1.0f); //// Clear the color and depth buffer. gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT); DrawScene(); gl.Flush(); } private void DrawScene() { OpenGL gl = openGLControl.OpenGL; gl.Color(1.0, 0.0, 0.0); DrawTriangle(-0.2, 0.6, 0.0, 0.8, 0.2, 0.6); gl.Color(0.0, 1.0, 0.0); DrawTriangle(-0.2, 0.2, 0.0, 0.4, 0.2, 0.2); gl.Color(0.0, 0.0, 1.0); DrawTriangle(-0.2, -0.2, 0.0, 0.0, 0.2, -0.2); } private void SelectObjects(double mouseDownX, double mouseDownY) { OpenGL gl = openGLControl.OpenGL; int BUFSIZE = 512; uint[] selectBuf = new uint[BUFSIZE]; gl.SelectBuffer(BUFSIZE, selectBuf); gl.RenderMode(OpenGL.GL_SELECT); gl.InitNames(); gl.PushName(0); int[] viewport = new int[4]; gl.GetInteger(OpenGL.GL_VIEWPORT, viewport); //how to define the width and height of an element? gl.PickMatrix(mouseDownX, (double)(viewport[3] - mouseDownY), 50.0, 50.0, viewport); gl.LoadIdentity(); gl.LoadName(1); gl.Color(1.0, 0.0, 0.0); DrawTriangle(-0.2, 0.6, 0.0, 0.8, 0.2, 0.6); gl.LoadName(2); gl.Color(0.0, 1.0, 0.0); DrawTriangle(-0.2, 0.2, 0.0, 0.4, 0.2, 0.2); gl.LoadName(3); gl.Color(0.0, 0.0, 1.0); DrawTriangle(-0.2, -0.2, 0.0, 0.0, 0.2, -0.2); gl.Flush(); int hits = gl.RenderMode(OpenGL.GL_RENDER); processHits(hits, selectBuf); } private void processHits(int hits, uint[] buffer) { uint bufferIterator = 0; for (uint i = 0; i < hits; i++) { uint numberOfNamesInHit = buffer[bufferIterator]; Console.WriteLine("hit: " + i + " number of names in hit " + numberOfNamesInHit); uint lastNameIndex = bufferIterator + 2 + numberOfNamesInHit; for (uint j = bufferIterator + 3; j <= lastNameIndex; j++) { Console.WriteLine("Name is " + buffer[j]); } bufferIterator = bufferIterator + numberOfNamesInHit + 3; } } private void OnMouseClick(object sender, MouseEventArgs e) { System.Windows.Point position = e.GetPosition(this); SelectObjects(position.X, position.Y); } 

The output is always the same:

hit: 0 number of names per hit 1

First name 1

hit: 1 number of names per hit 1

Name 2

hit: 2 numbers of names per hit 1

Name 3

+5
source share
2 answers

width and height are the size of the selection area in pixels. To detect an object under the mouse pointer, 1x1 must be accurate (you want to determine what is under the screen rectangle 1 pixel per 1 pixel).

gluPickMatrix update (multiply) the current matrix by the selection matrix. Your PickMatrix followed by LoadIdentity makes no sense, since glLoadIdentity reset the current matrix for the identity.

For your sample to work, set up your matrix before rendering:

 glLoadIdentity(); setupMyProjMatrix(); 

Before choosing, configure the same matrix, previously multiplied by the selection matrix:

 glLoadIdentity(); glPickMatrix(); setupMyProjMatrix(); 

In your example, setupMyProjMatrix() does nothing.

In any case, you should avoid using selection in opengl. This is an outdated feature (removed in modern gl), terribly slow, and sometimes not very reliable, depending on sellers. You must calculate the test results yourself.

You should never, never ask for anything gl (glGet family). This will cause the processor to stop.

Sorry for the bad english.

+3
source

As Olivier said, avoid obsolete features. Instead, you can make a choice in two ways:

  • Select by launching all the front polygons using the radiation test, where you launch the beam from the eye point through the center of the pixel (at close range) until it hits the polygon or falls outside the selection range. This solution does not scale all this well for complex scenes, but it is rather trivial to implement it and offers some degree of flexibility for processing transparency, etc.

  • You can also make selections in the viewing space by rendering all objects with a color identifier to an off-screen texture. Then you can simply read the pixel value to select a 2D coordinate and match the color identifier with the object under that selection coordinate. The disadvantage here is that collecting multiple objects is more complicated, and that the processed batch must have the correct reject and shader settings. The surface is that this decision depends on the resolution and not so much on the complexity of the scene.

+2
source

Source: https://habr.com/ru/post/1201912/


All Articles