OpenGL拾取遇到点麻烦 (找错误)

我做一个鼠标拾取的程序,但总是拾取错误。
问题简单描述下,我用的Win32做的一个图形程序,我的绘制图形的函数代码如下
void OpenGL::Draw(GLfloat position_x,GLfloat position_y,GLfloat position_z,GLfloat angle,GLfloat angle_xz,GLfloat distance,GLfloat jump)
{

//这个结构是主显示渲染过程
{

glClearColor(0.5f,0.5f,0.5f,1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

//glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glInitNames();
glPushName(0);

glRotatef(angle_xz,1.0f,0.0f,0.0f);
glRotatef(angle,0.0f,1.0f,0.0f);

glTranslatef(0.0f,0.0f-jump,0);
glTranslatef(position_x+0.0f,position_y-1.0f,position_z);

//glPushMatrix();
//glTranslatef(5.0f,0.0f,0.0f);
//zhuzi(1.0f,1.0f,10.0f,10,10);
//glPopMatrix();

//地面绘制
glBindTexture(GL_TEXTURE_2D, texture[0]);
glBegin(GL_QUADS);
glTexCoord2f(100,100);
glVertex3f(50.0f,0.0f,50.0f);
glTexCoord2f(-100,100);
glVertex3f(-50.0f,0.0f,50.0f);
glTexCoord2f(-100,-100);
glVertex3f(-50.0f,0.0f, -50.0f);
glTexCoord2f(100,-100);
glVertex3f(50.0f,0.0f, -50.0f);
glEnd();

glPushMatrix();

glLoadName(1);
glBegin(GL_TRIANGLES);
glVertex3f(0.0f,0.0f,0.0f);
glVertex3f(1.0f,1.0f,0.0f);
glVertex3f(1.0f,0.0f,0.0f);
glEnd();
glPopMatrix();

glPopMatrix(); //恢复最初模型矩阵
}

SwapBuffers(hDC);
}

我在响应了一个鼠标左键的电击事件,事件代码如下

GLuint selectBuff[1024];

GLint hits, viewport[4];

glSelectBuffer(1024, selectBuff);

glGetIntegerv(GL_VIEWPORT, viewport);

glMatrixMode(GL_PROJECTION);
glPushMatrix();

glRenderMode(GL_SELECT);

glLoadIdentity();
gluPickMatrix(x, viewport[3] - y, 2,2, viewport);

gluPerspective(45.0f,(GLfloat)800/(GLfloat)600,0.1f,200.0f);

gl.Draw(camera.x,camera.y,camera.z,camera.angle,camera.angle_xz,camera.distance,camera.jump);

hits = glRenderMode(GL_RENDER);

if(hits == 1)
{
int i = hits; //这里出问题
}

// Restore the projection matrix
glMatrixMode(GL_PROJECTION);
glPopMatrix();

// Go back to modelview for normal rendering
glMatrixMode(GL_MODELVIEW);

我设置了断点,发现每次拾取的时候总是拾取一个命名为0的图元,我并没有命名0号图元啊,我想拾取我绘图函数中最后一个三角形,但总不成功,我还找不到问题的所在,希望达人指点下,不胜感激~~
我想知道我程序哪里出问题了,拾取的例子我有很多,但我的程序哪里出问题了我总找不到答案,希望有人能找到我程序的问题,谢谢了
最新回答
傲似公主

2024-06-06 14:40:59

这是一个关于拾取的 程序
我想要鼠标移动到 每个方块时方块改变颜色 移开时颜色在回复原来的样子
可是这个 程序只是在移动到方块上时改变颜色 而移动开时没有任何的变化
想了 很久不知道该如何解决这个问题
希望各位路过的哥哥 可以帮我看看 给我个解决的方法 谢谢

#include <stdio.h>
#include <stdlib.h>
#include <GL/glut.h>

int board[3][3];

void init(void)
{
int i,j;
for(i=0;i<3;i++)
for(j=0;j<3;j++)
board[i][j] = 0;
glClearColor(0.0, 0.0, 0.0, 0.0);
}

void drawSquares(GLenum mode)
{
GLuint i,j;
for (i=0;i<3;i++){
if(mode == GL_SELECT)
glLoadName(i);

for(j=0;j<3;j++){
if(mode == GL_SELECT)
glPushName(j);
glColor3f((GLfloat)i/3.0, (GLfloat)j/3.0,
(GLfloat)board[i][j]/3.0);
glRecti(i,j,i+1,j+1);
if(mode == GL_SELECT)
glPopName();
}
}

}

void processHits(GLint hits,GLuint buffer[])
{
GLint i,j;
GLuint ii = 0,jj = 0,names,*ptr;

printf("hits = %d\n",hits);
ptr = (GLuint *) buffer;

for(i=0;i < hits;i++)
names = *ptr;
printf(" number of names for this hit = %d\n", names);
ptr++;
ptr++;
ptr++;

printf(" names are ");
for (j =0;j<names;j++){
printf("%d ", *ptr);
if (j==0)
ii = *ptr;
else if (j == 1)
jj = *ptr;
ptr++;

}
printf("\n");

board[ii][jj] = 1;
}

#define BUFSIZE 512

void pickSquares(int x,int y)
{
GLuint selectBuf[BUFSIZE];
GLuint hits;
GLint viewport[4];

//if(hits >= 10)
// return;

glGetIntegerv(GL_VIEWPORT, viewport);
glSelectBuffer(BUFSIZE,selectBuf);
(void) glRenderMode(GL_SELECT);

glInitNames();
glPushName(0);

glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();

gluPickMatrix((GLdouble) x,(GLdouble)(viewport[3]-y),
5.0,5.0, viewport);
gluOrtho2D(0.0,3.0,0.0,3.0);
drawSquares(GL_SELECT);

glMatrixMode(GL_PROJECTION);
glPopMatrix();
glFlush();

hits = glRenderMode(GL_RENDER);
processHits(hits,selectBuf);
glutPostRedisplay();
}

void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
drawSquares(GL_RENDER);
glFlush();

}

void reshape(int w,int h)
{
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,3.0,0.0,3.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

}

int main(int argc,char** argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(200,200);
glutInitWindowPosition(100,100);
glutCreateWindow(argv[0]);
init();
glutPassiveMotionFunc(pickSquares);
glutReshapeFunc(reshape);
glutDisplayFunc(display);
glutMainLoop();
return 0;
}

作者:eastcowboy 发表时间:2008-9-22 22:10:00

第1楼

/*

OpenGL演示程序

使用到的技术
1. 多窗口显示
2. OpenGL选择功能
3. 根据二维的窗口坐标计算出三维坐标

操作步骤
1. 程序运行后可以看到左边的“工具栏”和右边的“主窗口”
2. 在工具栏中用鼠标点击任意物体,即可选择该物体。
3. 在主窗口中移动鼠标,如果有物体被选择,则将该物体的“预览”绘制到鼠标处
4. 在主窗口中按下鼠标,如果有物体被选择,则在鼠标处添加一个与选择物体相同的物体
5. 最多可以添加MAX_OBJECT个物体

编程语言:C语言
调试环境:软件 -- Windows XP SP2 + Visual Studio 2005 SP1英文 + GLUT工具包3.7版
硬件 -- 奔腾4 3.0G + DDR 2G + IBM945G集成显卡

*/

//============================================================================
// 所需要的头文件
//============================================================================
#include <gl/glut.h>
#include <stdio.h>

//============================================================================
// 常量定义
//============================================================================

// 最大可以添加的物体数
#define MAX_OBJECT 10

//============================================================================
// 类型定义
//============================================================================

// “物体”数据,保存了物体的类型和位置
typedef struct _tag_Object {
int type; // 1 - 茶壶, 2 - 球, 3 - 圆锥
GLdouble pos_x;
GLdouble pos_y;
GLdouble pos_z;
} Object;

//============================================================================
// 全局变量
//============================================================================

// 当前已经添加的物体(数组)
Object object_list[MAX_OBJECT];

// 当前已经添加的物体数量
int object_count = 0;

// 主窗口中鼠标的位置(x, y)
int mouseX_AtMain = 0;
int mouseY_AtMain = 0;

// 当前选择的物体类型(0 - 未选择, 1 - 茶壶, 2 - 球, 3 - 圆锥)
int select_object_type = 0;

作者:eastcowboy 发表时间:2008-9-22 22:11:00

第2楼

//============================================================================
// 左边“菜单栏”所需要的函数
//============================================================================

// 画出三个可以选择的物体
// 注意本函数有两个地方会用到。一是正常的绘制,二是用于OpenGL选择模式。
// 因此会用glLoadName这样的函数
void __left_display() {
static const GLfloat color_selected[] = {0.75f, 0.75f, 0.95f};
static const GLfloat color_unselected[] = {0.4f, 0.4f, 0.4f};

// 画一个茶壶
glLoadName(1);
glColor3fv( (select_object_type==1) ? color_selected : color_unselected );
glPushMatrix();
glTranslatef(75.0f, 470.0f*3/4, 0);
glutSolidTeapot(30);
glPopMatrix();

// 画一个球
glLoadName(2);
glColor3fv( (select_object_type==2) ? color_selected : color_unselected );
glPushMatrix();
glTranslatef(75.0f, 470.0f/2, 0);
glutSolidSphere(30.0, 20, 20);
glPopMatrix();

// 画一个圆锥
glLoadName(3);
glColor3fv( (select_object_type==3) ? color_selected : color_unselected );
glPushMatrix();
glTranslatef(75.0f, 470.0f/4, 0);
glRotatef(-90.0f, 1.0f, 0.0f, 0.0f);
glutSolidCone(30.0, 50.0, 30, 1);
glPopMatrix();
}

// 菜单栏需要绘制时调用此函数
void left_display(void) {
glClear(GL_COLOR_BUFFER_BIT);
__left_display();
glutSwapBuffers();
glutReportErrors();
}

// 在鼠标点击菜单栏时调用此函数
// 函数中会使用OpenGL的选择功能来判断哪个物体被选中
void left_mouse(int button, int state, int x, int y) {
GLdouble saved_projection_matrix[16];
GLint viewport[4];
GLuint select_buffer[512];
GLint buffer_count;

if( state != GLUT_DOWN )
return;

glGetDoublev(GL_PROJECTION_MATRIX, saved_projection_matrix);
glGetIntegerv(GL_VIEWPORT, viewport);
y = viewport[3] - y;

glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluPickMatrix(x, y, 1, 1, viewport);
glMultMatrixd(saved_projection_matrix);
glMatrixMode(GL_MODELVIEW);

glSelectBuffer(
sizeof(select_buffer)/sizeof(select_buffer[0]), select_buffer);
glRenderMode(GL_SELECT);
glInitNames();
glPushName(0);
__left_display();
buffer_count = glRenderMode(GL_RENDER);
if( buffer_count < 0 ) {
printf("OpenGL 选择缓冲区溢出\n");
} else if( buffer_count == 0 ) {
select_object_type = 0;
printf("未选择任何物体\n");
} else {
int i;
GLuint* ptr = select_buffer;
for(i=0; i<buffer_count; ++i) {
int name = select_buffer[i*4+3];
switch(name) {
case 1:
printf("选择了茶壶\n");
select_object_type = 1;
break;
case 2:
printf("选择了球\n");
select_object_type = 2;
break;
case 3:
printf("选择了圆锥\n");
select_object_type = 3;
break;
}
}
}

glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);

glutPostRedisplay();
}

作者:eastcowboy 发表时间:2008-9-22 22:11:00

第3楼

//============================================================================
// 左边“菜单栏”所需要的函数
//============================================================================

// 根据二维的窗口坐标计算出三维坐标,
// 计算结果放到pObj->pos_x, pObj->pos_y, pObj->pos_z中
// 注意:要正确使用本函数,必须开启深度测试。
// 即必须分配深度缓冲区,并且使用glEnable(GL_DEPTH_TEST)
void calc_xyz(int winx, int winy, Object* pObj) {
GLdouble modelview_matrix[16];
GLdouble projection_matrix[16];
GLint viewport[4];
GLfloat winz;

glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix);
glGetDoublev(GL_PROJECTION_MATRIX, projection_matrix);
glGetIntegerv(GL_VIEWPORT, viewport);

glReadPixels(winx, winy, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winz);
gluUnProject(winx, winy, winz,
modelview_matrix, projection_matrix, viewport,
&(pObj->pos_x), &(pObj->pos_y), &(pObj->pos_z));
}

// 根据物体类型的不同,绘制出不同的物体
// 1 - 茶壶, 2 - 球, 3 - 圆锥
void draw_object(int type) {
switch( type ) {
case 1:
glColor3f(0.2f, 0.7f, 0.5f);
glTranslatef(0.0f, 0.3f, 0.0f);
glutSolidTeapot(0.3);
break;
case 2:
glColor3f(0.3f, 0.6f, 0.8f);
glTranslatef(0.0f, 0.3f, 0.0f);
glutSolidSphere(0.3, 20, 20);
break;
case 3:
glColor3f(0.6f, 0.6f, 0.3f);
glRotatef(-90.0f, 1.0f, 0.0f, 0.0f);
glutSolidCone(0.3, 0.4, 30, 1);
break;
}
}

// 鼠标在主窗口中移动时,记录鼠标的位置
// 如果选择了物体类型,则通过glutPostRedisplay重新绘制主窗口,
// 绘制时会把所选的物体绘制在鼠标位置处
void main_passiveMotion(int x, int y) {
mouseX_AtMain = x;
mouseY_AtMain = 470 - y;
if( select_object_type != 0 )
glutPostRedisplay();
}

// 鼠标点击主窗口,尝试添加物体
// 若添加成功则调用glutPostRedisplay重新绘制,以便让添加的物体被绘制出来
void main_mouse(int button, int state, int x, int y) {
if( state != GLUT_DOWN )
return;
if( !select_object_type )
return;
if( object_count >= MAX_OBJECT ) {
printf("物体数量达到最大,无法再添加\n");
return;
}

object_list[object_count].type = select_object_type;
calc_xyz(x, 470 - y, &object_list[object_count]);
printf("在(%f, %f, %f)处增加物体。\n",
object_list[object_count].pos_x,
object_list[object_count].pos_y,
object_list[object_count].pos_z);
++object_count;

glutPostRedisplay();
}

// 主窗口需要绘制时调用本函数
void main_display(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// disable lighting
glDisable(GL_LIGHTING);

// ground
glColor3f(0.4f, 0.2f, 0.2f);
glBegin(GL_QUADS);
glVertex3f(-2.0f, 0.0f, -2.0f);
glVertex3f(-2.0f, 0.0f, 2.0f);
glVertex3f( 2.0f, 0.0f, 2.0f);
glVertex3f( 2.0f, 0.0f, -2.0f);
glEnd();

// mouse object
if( select_object_type != 0 ) {
Object dummy;
calc_xyz(mouseX_AtMain, mouseY_AtMain, &dummy);
glPushMatrix();
glTranslated(dummy.pos_x, dummy.pos_y, dummy.pos_z);
draw_object(select_object_type);
glPopMatrix();
}

// enable lighting
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);

// objects
{
int i;
glColor3f(1.0f, 1.0f, 0);
for(i=0; i<object_count; ++i) {
glPushMatrix();
glTranslated(object_list[i].pos_x,
object_list[i].pos_y,
object_list[i].pos_z);
draw_object(object_list[i].type);
glPopMatrix();
}
}

glutSwapBuffers();
glutReportErrors();
}

// 最大的窗口在需要绘制时调用本函数
void display(void) {
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);

glutSwapBuffers();
}

作者:eastcowboy 发表时间:2008-9-22 22:12:00

第4楼

// main函数
int main(int argc, char* argv[]) {
int window, left_window, main_window;

glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowPosition(100, 100);
glutInitWindowSize(640, 480);

// 父窗口
window = glutCreateWindow("OpenGL");
glutDisplayFunc(&display);

// 左边的子窗口
left_window = glutCreateSubWindow(window, 5, 5, 150, 470);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, 150.0, 0.0, 470.0, 100.0, -100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.375f, 0.375f, 0.0f);

glutDisplayFunc(&left_display);
glutMouseFunc(&left_mouse);

// 主体的子窗口
main_window = glutCreateSubWindow(window, 165, 5, 470, 470);

glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, 1.0, 0.5, 10.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(4.0, 3.0, 3.0,
0.0, 0.0, 0.0,
0.0, 1.0, 0.0);

glutDisplayFunc(&main_display);
glutMouseFunc(&main_mouse);
glutPassiveMotionFunc(&main_passiveMotion);

glutMainLoop();
}
懂鍀灬舍去丶

2024-06-06 12:18:51

你解决了吗?我也遇到同样的问题?能不能告诉我怎么回事?