Picking Tutorial
拾取教程
Cheking the Color
检查颜色
Checking the color of the pixel where the mouse was clicked involves reading that same pixel from the back buffer. This can be accomplished using the following function:
检查从后缓冲区内读取鼠标点击位置的像素的颜色。它能名使用以下的函数来完成:
void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);
Parameters:
- x,y : the bottom left corner x,y: 左下角的坐标
- width, length: the size of the area to be read width, length: 将读取的区域大小
- format: The type of data to be read. In here it is assumed to GL_RGB. format: 将读取的数据类型。在这里我们将用GL_RGB.
- type: the data type of the elements of the pixel. In here we'll use GL_UNSIGNED_BYTE. type: 像素元素的数据类型。在这里我们将用GL_UNSIGNED_BYTE.
- pixels: An array where the pixels will be stored. This is the result of the function pixels: 用来存储像素的数组。它将是这个函数的结果。
Both format and type have a lot of other possibilities, check the Red or Blue books for more information.
格式和类型有其它多种可能的值,检查红宝书来获取更多信息。
Just as when using the OpenGL API it is necessary to invert the y coordinate. Reading the viewport information is therefore also required when using this approach. After getting the viewport info, it is possible to call glReadPixels as shown in the code bellow. The x and y parameters represent the cursor position. Width and height are both set to one since only a single pixel is being read. Afterwards it is just a matter of checking the values of the pixel.
只是使用OpenGL API时,需要翻转y的坐标。当使用这种方法时,读取视口信息也是必须的。在得到视口信息之后,就可以像下面展示的一样来调用glReadPixels。x和y参数代表鼠标的位置。Width和Height被设置成1,因为只有一个像素被读取。以后就只是检查像素的值的事情了。
void processPick ()
{
GLint viewport[4];
GLubyte pixel[3];
glGetIntegerv(GL_VIEWPORT,viewport);
glReadPixels(cursorX,viewport[3]-cursorY,1,1,
GL_RGB,GL_UNSIGNED_BYTE,(void *)pixel);
printf("%d %d %d\n",pixel[0],pixel[1],pixel[2]);
if (pixel[0] == 255)
printf ("You picked the 1st snowman on the 1st row");
else if (pixel[1] == 255)
printf ("You picked the 1st snowman on the 2nd row");
else if (pixel[2] == 255)
printf ("You picked the 2nd snowman on the 1st row");
else if (pixel[0] == 250)
printf ("You picked the 2nd snowman on the 2nd row");
else
printf("You didn't click a snowman!");
printf ("\n");
}
To get this approach running without problems there are a few things that you should be aware. First set your colors using unsigned bytes as opposed to floats. When in RGB mode there are only 256 possible values for each component, so when you set a color using floats OpenGL will pick the nearest color possible. Secondly make sure your monitor is set to True Color. Otherwise the color presented on screen is only an approximation to the required color and therefore when reading back the pixels there is a possibility that the values wont match with the set values. Finally make sure you disable dithering, lighting and texturing for the color coded rendering function, since any of these operations may change the original color.
要没有任意问题的使用这种方法,你有一些事情应该注意。第一就是使用unsigned bytes来设置你的颜色而不是使用浮点数。当在RGB模式时,对第一部分只有256种可能的值,所以你使用浮点数来设置颜色值,OpenGL将会可能的是近的颜色。第二是确保你的显示器被设置成True Color.否则显示在屏幕的颜色只是要求颜色的一种近似,因此当读回像素的值时,可能与设置的值不相符。最后,确保你在颜色编码绘制函数中禁用抖动(dither)、光照和纹理,因为任何这些操作都可能会改变原始的颜色。
If you really want to work with floats to set the color, or you can't guarantee that the monitor will be set to True Color then you can always to a test to check what the specified colors will look like when rendered.
如果你确实想用浮点数来设置颜色,或者你不能保证显示器被设置成True Color,你可以总是做一个测试来检查指定的颜色在绘制时将如果显示。
This approach requires that before your application starts you must render blocks of the requested colors and read them back using glReadPixels to get the real rendered colors. Store those colors in an array and use them instead of the colors you specified when rendering.
这种方法需要你的应用程序在启动时绘制一块要求的颜色然后使用glReadPixels读回来得到真实的绘制颜色。把那些颜色存到一个数组并使用它们来代表你在绘制时指定的颜色。
Be careful when choosing the colors though. If the values for each component are not set sufficiently apart then the may turn out to be the same color when rendered. For instance when setting the red component to 250, using unsigned bytes, with the monitor set to High Color instead of True Color, you actually get a red component of 255. This is because there are less possible values for each component when using only 16 bits to specify a color instead of 32 or 24. Check out the pixel packing values in the Red Book to find out about the possible combinations of bits for each component with 16 bits.
要小心的是,当选择颜色时,如果每个部分的值设置的不足够与其它部分都区分,它们可能在绘制时变得一样。例如,当使用unsigned byte 设置红色部分为250,显示器设置为High Color而不是True Color,你实际上得到的红色部分是255.这是因为当只使用16比特而不是32或24来指定一个颜色,每个部分的可能值变少了。检查红宝书中像素pack值来找到16比特时可能的颜色值。