当前位置:网站首页>Opengl3.3 mouse picking up objects

Opengl3.3 mouse picking up objects

2022-07-07 23:53:00 Raring_ Ringtail

OpenGL3.3 Pick up objects with the mouse

This article is translated from :http://www.lighthouse3d.com/tutorials/opengl-selection-tutorial/

stay 3D Picking or selecting specific items in a scene may be useful for some applications . You can perform a selection by clicking on an object , This requires a way to determine which object the mouse is placed on .

A simple solution to this is to use color coding , Draw each pickable object in a specific color . Read the pixel where the mouse is located to provide color , So that objects can be recognized .

Rendering in select mode uses very simple shaders , Apply a constant color to pixels . Color is a unified variable , Set each object to a unique value before drawing it .

Vertex shaders can be as follows :

#version 330
 
uniform mat4 m_pvm;
 
in vec4 position;
 
void main()
{
    
    gl_Position = m_pvm * position ;
}

Fragment shaders are simple :

#version 330
 
uniform int code;
 
out vec4 outputF;
 
void main()
{
    
    outputF = vec4(code/255.0, 0, 0, 0);
}

It is important to , We got it code It's an integer, not a floating-point number . stay RGB In mode , Each component has only 256 Possible values , So when you use floating point numbers to set colors ,OpenGL The closest possible color will be selected , This may not be exactly the same as the value you provided .

Please note that , We will divide by 255.0, Instead of dividing by 255. Using the latter method will be integer division , The result will also be an integer (0 or 1).

If there is more than 255 Objects to choose from , be uniform Of code It can be ivec4 type .

Suppose our scenario has 4 A chess piece , As shown in the figure below :

 Insert picture description here

In this example , We have four clickable objects , We will assign it from 1 To 4 Code for . The background of the selected rendering routine can be set to black , So zero means there is no choice . When using the selector , We will get the following image ( The contrast is greatly improved ):

 Insert picture description here
The image will never be presented to the user , Because choosing to render does not swap buffers .

The following routine receives mouse window coordinates , And perform the necessary steps to determine which object is selected . First call the select renderer , Then make a choice . then , It reads pixels from the background buffer and checks the returned color .

To read pixels , We're going to use functions glReadPixels.
void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *data);

Parameters :

  • x,y: Coordinates of the first pixel of the rectangular block to be read
  • width,height: The size of the block .
  • format: Format of pixel data :GL_STENCIL_INDEX, GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL, GL_RED, GL_GREEN, GL_BLUE, GL_RGB, GL_BGR, GL_RGBA, GL_BGRA
  • type: Data type of pixel component :GL_UNSIGNED_BYTE, GL_BYTE, GL_UNSIGNED_SHORT, GL_SHORT, GL_UNSIGNED_INT, GL_INT, GL_HALF_FLOAT, GL_FLOAT, GL_UNSIGNED_BYTE_3_3_2, GL_UNSIGNED_BYTE_2_3_3_REV, GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT_5_6_5_REV, GL_UNSIGNED_SHORT_4_4_4_4, GL_UNSIGNED_SHORT_4_4_4_4_REV, GL_UNSIGNED_SHORT_5_5_5_1, GL_UNSIGNED_SHORT_1_5_5_5_REV, GL_UNSIGNED_INT_8_8_8_8, GL_UNSIGNED_INT_8_8_8_8_REV, GL_UNSIGNED_INT_10_10_10_2, GL_UNSIGNED_INT_2_10_10_10_REV, GL_UNSIGNED_INT_24_8, GL_UNSIGNED_INT_10F_11F_11F_REV, GL_UNSIGNED_INT_5_9_9_9_REV, or GL_FLOAT_32_UNSIGNED_INT_24_8_REV
  • data: Returned pixel data .
void processSelection(int xx, int yy) {
    
 
    unsigned char res[4];
    GLint viewport[4]; 
 
    renderSelection();
 
    glGetIntegerv(GL_VIEWPORT, viewport);
    glReadPixels(xx, viewport[3] - yy, 1,1,GL_RGBA, GL_UNSIGNED_BYTE, &res);
    switch(res[0]) {
    
        case 0: printf("Nothing Picked \n"); break;
        case 1: printf("Picked yellow\n"); break;
        case 2: printf("Picked red\n"); break;
        case 3: printf("Picked green\n"); break;
        case 4: printf("Picked blue\n"); break;
        default:printf("Res: %d\n", res[0]);
    }
}

To get the right pixels , We must set the mouse window coordinates ( The upper left corner is the origin ) Convert to frame buffer coordinates ( The origin of the lower left corner ). This requires us to know the height of the viewport . function glGetIntegerv Can be used for this purpose , take GL_VIEWPORT As the first parameter . Return variable viewport Is a containing 4 An array of items , This array provides x and y Viewport window coordinates ( The starting point : top left corner ), Then the width and height of the viewport . then , You can read pixels , And decode the retrieved color correctly .

The selection of the renderer must follow the same steps as the regular procedure for geometric transformation , So that the object is in the same position on the screen . Usually , The selected renderer is a simplified version of the regular renderer , Where only a subset of the objects are drawn , And no graphic effect is set , For example, lighting .

The object subset includes all clickable objects and related occlusions . The idea is , If some pieces are in a space invisible to the user , Then they should not appear in color coded images . This can be done by painting the occlusion with the same color as the background ( For example, the wall of the room ) To make it easy .

void renderSelection(void) {
    
 
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
    //set matrices to identity
    ...
    // set camera as in the regular rendering function
    ....
 
    // use the selection shader
    glUseProgram(selectionProgramID);
 
    //perform the geometric transformations to place the first pawn
    ...
    // set the uniform with the appropriate color code
    glProgramUniform1i(selectionProgramID, codeVarLocation, 1);
    // draw first pawn
    ...
     
    // repeat the above steps for the remaining objects, using different codes
 
    //don't swap buffers
    //glutSwapBuffers();
 
    // restore clear color if needed
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
}

download :

  • With complete source code and shaders VS2010 project (ZIP

The project needs glew and freeglut or glut.


Welcome to my official account. Notes on Jiangda

原网站

版权声明
本文为[Raring_ Ringtail]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/02/202202130554126125.html