openGL学习笔记3
第三章主要就是与程序进行交互
首先来个简单的点击的程序,然后是作业题。
【题目描述】
绘制出红色、蓝色部分重叠矩形,鼠标点击相应区域,根据指针所覆盖5像素内方形块中对应的对象对其进行高亮,点击背景均恢复原状。
【分析】
基础的点击然后程序给出反应。需要利用鼠标回调函数、名字栈、拾取和选择、可选键盘回调函数,开始接触到一些reshape回调函数中各类矩阵的设置了。
【代码】
1 //绘制出红色、蓝色部分重叠矩形,鼠标点击相应区域,根据指针所覆盖5像素内方形块中对应的对象对其进行高亮,点击背景均恢复原状。 2 3 #include <stdlib.h> 4 #include <stdio.h> 5 #include <GL/glut.h> 6 7 GLint now; 8 9 void init() 10 { 11 now=0; 12 glClearColor (0.0, 0.0, 0.0, 0.0); 13 } 14 15 void drawObjects(GLenum mode) 16 { 17 GLdouble color1=0.5,color2=0.5; 18 if (now==1) 19 color1=1.0; 20 else if (now==2) 21 color2=1.0; 22 else if (now==3) 23 color1=color2=1.0; 24 if(mode == GL_SELECT) glLoadName(1); 25 glColor3f(color1, 0.0, 0.0); 26 glRectf(-0.5, -0.5, 1.0, 1.0); 27 if(mode == GL_SELECT) glLoadName(2); 28 glColor3f(0.0, 0.0, color2); 29 glRectf(-1.0, -1.0, 0.5, 0.5); 30 } 31 32 void display() 33 { 34 glClear(GL_COLOR_BUFFER_BIT); 35 drawObjects(GL_RENDER); 36 glFlush(); 37 } 38 39 void processHits (GLint hits, GLuint buffer[]) 40 { 41 unsigned int i, j; 42 GLint names, *ptr; 43 ptr = (GLint *) buffer; 44 if (hits==2) 45 {now=3;return;} 46 if (hits==0) 47 {now=0;return;} 48 for (i = 0; i < hits; i++) { // for each hit 49 names = *ptr; 50 ptr+=3; 51 for (j = 0; j < names; j++) { // for each name 52 if(*ptr==1) now=1; 53 else now=2; 54 ptr++; 55 } 56 } 57 } 58 59 #define SIZE 512 60 61 void mouse(int button, int state, int x, int y) 62 { 63 GLuint selectBuf[SIZE]; 64 GLint hits; 65 GLint viewport[4]; 66 67 if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) 68 { 69 glGetIntegerv (GL_VIEWPORT, viewport); 70 71 glSelectBuffer (SIZE, selectBuf); 72 glRenderMode(GL_SELECT); 73 74 glInitNames(); 75 glPushName(0); 76 77 glMatrixMode (GL_PROJECTION); 78 glPushMatrix (); 79 glLoadIdentity (); 80 // 5像素方形选择区域 81 gluPickMatrix ((GLdouble) x, (GLdouble) (viewport[3] - y), 82 5.0, 5.0, viewport); 83 gluOrtho2D (-2.0, 2.0, -2.0, 2.0); 84 drawObjects(GL_SELECT); 85 86 87 glMatrixMode (GL_PROJECTION); 88 glPopMatrix (); 89 glFlush (); 90 91 hits = glRenderMode (GL_RENDER); 92 processHits (hits, selectBuf); 93 94 glutPostRedisplay(); 95 } 96 } 97 98 99 void reshape(int w, int h) 100 { 101 glViewport(0, 0, w, h); 102 glMatrixMode(GL_PROJECTION); 103 glLoadIdentity(); 104 gluOrtho2D (-2.0, 2.0, -2.0, 2.0); 105 glMatrixMode(GL_MODELVIEW); 106 glLoadIdentity(); 107 } 108 109 int main(int argc, char** argv) 110 { 111 glutInit(&argc, argv); 112 glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); 113 glutInitWindowSize (500, 500); 114 glutInitWindowPosition (100, 100); 115 glutCreateWindow (argv[0]); 116 init (); 117 glutReshapeFunc (reshape); 118 glutDisplayFunc(display); 119 glutMouseFunc (mouse); 120 glutMainLoop(); 121 return 0; 122 }
【效果】
3.14作业题:
【题目描述】
创建一个简单的绘制程序,使得可用鼠标来创建一些简单的形状,如线段矩形和三角形,并可通过菜单来选择各种
模式,并允许用户改变绘制颜色。
附加功能:按CTRL+点击已绘制图像可高亮显示,CTRL+点击背景取消所有高亮
【分析】
没有曲线,都是基本图元,很好绘制。
通过创建一个list来进行display,每个元素是一个结构:颜色,点数组,绘制形式。
改变颜色功能只需要修改当前颜色nowcolor即可。
至于CTRL高亮和恢复:用到渲染模式和选择模式:在鼠标回调中用gluPickMatrix拾取区域,用hit来记录命中,利用名字空间处理重叠图元,修改对应结构中的颜色,再glutRedispaly即可高亮和恢复。
还有更多可添加的功能:比如绘制线段时确定一个端点后鼠标移动,相应线段会即时显示,可以用鼠标移动的函数进行处理。
【代码】
1 /*创建一个简单的绘制程序,使得可用鼠标来创建一些简单的形状,如线段矩形和三角形,并可通过菜单来选择各种 2 模式,并允许用户改变绘制颜色。 3 附加功能:按CTRL+点击已绘制图像可高亮显示,CTRL+点击背景取消所有高亮*/ 4 #include <stdlib.h> 5 #include <stdio.h> 6 #include <GL/glut.h> 7 #define MAX 10000 8 #define SIZE 512//buffer尺寸 9 struct graphic 10 { 11 int type;//1=线段 2=矩形 3=三角形 12 GLfloat color[3]; 13 GLfloat point[3][3]; 14 GLenum mode; 15 }showlist[MAX]; 16 //count 0不用 type 0不用 showlist 0不用 last 0不用 color 0用 point 0用 hisnow 0用 17 GLint count,hitsmax,hitsnow,nowtype,last[MAX],lastcount;//last:已高亮节点记录,带now的为当前绘制记录 18 GLenum nowmode; 19 GLfloat nowcolor[3],nowpoint[3][3],neww,newh; 20 21 void mymenu(int value) 22 { 23 if (value==1) 24 {nowtype=1;hitsmax=2;hitsnow=0;} 25 else if (value==2) 26 {nowtype=2;hitsmax=2;hitsnow=0;} 27 else if (value==3) 28 {nowtype=3;hitsmax=3;hitsnow=0;} 29 else if (value==4) 30 { 31 glClear(GL_COLOR_BUFFER_BIT); 32 glFlush(); 33 } 34 } 35 void drawObjects(GLenum mode) 36 { 37 GLint i; 38 for (i=1;i<=count;i++) 39 { 40 if(mode == GL_SELECT) glLoadName(i);//如果是进入了选择模式,则给名称,从1开始 41 glColor3fv(showlist[i].color);//设置当前绘制颜色 42 glPolygonMode(GL_FRONT_AND_BACK,showlist[i].mode);//设置当前绘制模式 43 if (showlist[i].type==1)//线段 44 { 45 glBegin(GL_LINES); 46 glVertex2fv(showlist[i].point[0]); 47 glVertex2fv(showlist[i].point[1]); 48 glEnd(); 49 } 50 else if (showlist[i].type==2)//矩形 51 { 52 glRectfv(showlist[i].point[0],showlist[i].point[1]); 53 } 54 else if (showlist[i].type==3)//三角形 55 { 56 glBegin(GL_POLYGON); 57 glVertex2fv(showlist[i].point[0]); 58 glVertex2fv(showlist[i].point[1]); 59 glVertex2fv(showlist[i].point[2]); 60 glEnd(); 61 } 62 } 63 } 64 void submenu1(int value) 65 { 66 if (value==1) 67 nowmode=GL_FILL; 68 else 69 nowmode=GL_LINE; 70 } 71 void submenu2(int value) 72 { 73 if (value==1) 74 {nowcolor[0]=0.5;nowcolor[1]=0.5;nowcolor[2]=0.5;} 75 else 76 {nowcolor[0]=0.5;nowcolor[1]=0;nowcolor[2]=0;} 77 } 78 79 void init() 80 { 81 int id1,id2; 82 hitsmax=hitsnow=nowtype=count=lastcount=0;//初始化各种数据 83 glClearColor (0.3, 0.1, 0.5, 0.0); 84 nowcolor[0]=0.5;nowcolor[1]=0.5;nowcolor[2]=0.5; 85 nowmode=GL_FILL; 86 87 //菜单初始化 88 id1=glutCreateMenu(submenu1);//次1 89 glutAddMenuEntry("填充",1); 90 glutAddMenuEntry("勾勒",2); 91 id2=glutCreateMenu(submenu2);//次2 92 glutAddMenuEntry("白色",1); 93 glutAddMenuEntry("红色",2); 94 glutCreateMenu(mymenu);//主菜单 95 glutAddMenuEntry("创建线段",1); 96 glutAddMenuEntry("创建矩形",2); 97 glutAddMenuEntry("创建三角形",3); 98 glutAddSubMenu("选择模式(默认填充)",id1); 99 glutAddSubMenu("改变颜色(默认白色)",id2); 100 glutAddMenuEntry("清屏",4); 101 glutAttachMenu(GLUT_RIGHT_BUTTON); 102 103 } 104 105 void display() 106 { 107 glClear(GL_COLOR_BUFFER_BIT); 108 drawObjects(GL_RENDER); 109 glFlush(); 110 } 111 112 void change(int i)//高亮函数 113 { 114 lastcount++; 115 last[lastcount]=i; 116 if (showlist[i].color[1]==0.0) 117 showlist[i].color[0]=1.0;//红色 118 else //白色 119 { 120 showlist[i].color[0]=1.0; 121 showlist[i].color[1]=1.0; 122 showlist[i].color[2]=1.0; 123 } 124 125 } 126 void recovery()//高亮恢复函数 127 { 128 for (;lastcount>0;lastcount--) 129 { 130 if (showlist[last[lastcount]].color [1]==0.0)//亮红 131 showlist[last[lastcount]].color [0]=0.5; 132 else //亮白 133 { 134 showlist[last[lastcount]].color[0]=0.5; 135 showlist[last[lastcount]].color[1]=0.5; 136 showlist[last[lastcount]].color[2]=0.5; 137 } 138 } 139 } 140 141 void processHits (GLint hits, GLuint buffer[])//hits处理函数 142 { 143 unsigned int i, j; 144 GLint names, *ptr; 145 ptr = (GLint *) buffer; 146 if (hits==0)//如果按ctrl+点击背景,则取消所有高亮 147 {recovery();return;} 148 for (i = 0; i < hits; i++) { //命中覆盖对象个数 149 names = *ptr; 150 ptr+=3; 151 for (j = 0; j < names; j++) { //对于每个对象(名称为索引) 152 change(*ptr);//高亮 153 ptr++; 154 155 } 156 } 157 } 158 void mouse(int button, int state, int x, int y) 159 { 160 GLuint selectBuf[SIZE]; 161 GLint hits,i,j; 162 GLint viewport[4]; 163 glGetIntegerv (GL_VIEWPORT, viewport); 164 if (glutGetModifiers ()==GLUT_ACTIVE_CTRL && button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)//CTRL+点击=高亮 165 { 166 recovery();//对已高亮元素进行恢复 167 glSelectBuffer (SIZE, selectBuf); 168 glRenderMode(GL_SELECT); 169 170 glInitNames(); 171 glPushName(0);//初始化名称堆栈等 172 173 glMatrixMode (GL_PROJECTION); 174 glPushMatrix (); 175 glLoadIdentity (); 176 // 5像素精度指针选择区域 177 gluPickMatrix ((GLdouble) x, (GLdouble) (viewport[3] - y), 178 5.0, 5.0, viewport); 179 gluOrtho2D (0, neww, 0, newh); 180 drawObjects(GL_SELECT); 181 182 183 glMatrixMode (GL_PROJECTION); 184 glPopMatrix (); 185 glFlush (); 186 187 hits = glRenderMode (GL_RENDER);//回渲染,处理hit 188 processHits (hits, selectBuf); 189 } 190 else if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)//绘制 191 { 192 nowpoint[hitsnow][0]=(GLdouble) x; 193 nowpoint[hitsnow][1]=(GLdouble) (viewport[3] - y); 194 hitsnow++; 195 if (hitsnow==hitsmax)//点数已达到绘制要求,存储当前点到showlist 196 { 197 count++; 198 for (i=0;i<3;i++) 199 { 200 showlist[count].color[i]=nowcolor[i]; 201 for (j=0;j<2;j++) 202 showlist[count].point[i][j]=nowpoint[i][j]; 203 } 204 showlist[count].type=nowtype; 205 showlist[count].mode=nowmode; 206 hitsnow=0; 207 } 208 } 209 glutPostRedisplay(); 210 } 211 212 213 void reshape(int w, int h)//改变形状时重新设置视口、投影、裁剪 214 { 215 glViewport(0, 0, w, h); 216 glMatrixMode(GL_PROJECTION); 217 glLoadIdentity(); 218 gluOrtho2D (0, w, 0, h); 219 neww=w; 220 newh=h;//把WH传给全局变量,供给hit函数的裁剪,来保证改变了窗口大小仍能使用所有功能 221 glMatrixMode(GL_MODELVIEW); 222 glLoadIdentity(); 223 } 224 int main(int argc, char** argv) 225 { 226 glutInit(&argc, argv); 227 glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);//初始化 228 glutInitWindowSize (500, 500); 229 glutInitWindowPosition (200,200); 230 glutCreateWindow ("绘图"); 231 init (); 232 glutReshapeFunc (reshape);//改变形状回调 233 glutDisplayFunc(display); //显示回调 234 glutMouseFunc (mouse);//鼠标回调 235 glutMainLoop(); 236 return 0; 237 }
【效果】
——————————————————————————心得———————————————————————————————————
1.要理解屏幕、视口、投影和世界的关系,在改变窗口大小后仍然能够绘制,注意Reshape函数里的内容
2.使用到的知识有:鼠标交互、菜单、类似显示列表、图元的各种参数设置、各种回调、渲染选择模式
3.曾经遇到显示不出来任何图像,然后改变窗口大小后发现原来是绘制出来了的,原因在于视口调整
4.在修改了参数后一定要GlutPostRedisplay重绘,不然不会发生变化的。