《OpenGL超级宝典》P38“2.6使用OpenGL和GLUT生成动画”勘误

来源:互联网 发布:淘宝的旅游团怎么样 编辑:程序博客网 时间:2024/05/21 19:31

原文来自:http://zerfew.blog.163.com/blog/static/1938101692012730111051342/


书链接:《OpenGL超级宝典》


书中的源代码本来就是不全的,根据main中的函数调用,源代码缺失了ChangeSize()和SetupRC()两个函数。所以,将前一节两个函数粘贴过来,编译没有问题,运行后的小方块在窗口中心位置第一象限和第三象限不停闪耀。
运行有问题的源代码如下:

#include <windows.h>//#include "glee.h"#include <gl\gl.h>#include <gl\glu.h>#include <gl\glut.h>//方块的初始位置和大小GLfloat x1=0.0f;GLfloat y1=0.0f;GLfloat rsize=25;//在x和y方向的步进大小GLfloat xstep=1.0f;GLfloat ystep=1.0f;//追踪窗口宽度和高度的变化GLfloat windowWidth;GLfloat windowHeight;//绘制场景void RenderScene(void){ //用当前清除颜色清楚窗口 glClear(GL_COLOR_BUFFER_BIT); //把绘图颜色设置为红色 glColor3f(1.0f,0.0f,0.0f); //用当前颜色绘制一个填充矩形 glRectf(x1,y1,x1+rsize,y1-rsize); //刷新绘制命令并进行交换 //glFlush(); glutSwapBuffers();}//设置渲染状态void SetupRC(void){ glClearColor(0.0f,0.0f,1.0f,1.0f);}//设置渲染状态void ChangeSize(GLsizei w,GLsizei h){ GLfloat aspectRatio; //防止被0所除 if(h==0) h=1; //把视口设置为窗口的大小 glViewport(0,0,w,h); //重置坐标系统 glMatrixMode(GL_PROJECTION); glLoadIdentity(); //建立裁剪区域(左、右、底、顶、近、远) aspectRatio=(GLfloat)w/(GLfloat)h; if(w<=h) glOrtho(-100.0,100.0,-100.0/aspectRatio,100.0/aspectRatio,1.0,-1.0); else glOrtho(-100.0*aspectRatio,100.0*aspectRatio,-100.0,100.0,1.0,-1.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity();}//当空闲时由GLUT函数库调用void TimerFunction(int value){ //在到达左边或右边时翻转方向 if(x1>windowWidth-rsize||x1<-windowWidth) xstep=-xstep; //在到达顶边或底边时翻转方向 if(y1>windowHeight||y1<-windowHeight+rsize) ystep=-ystep; //实际移动方块 x1+=xstep; y1+=ystep; //检查边界 if(x1>(windowWidth-rsize+xstep)) x1=windowWidth-rsize-1; else if(x1<-(windowWidth+xstep)) x1=-windowWidth-1; if(y1>(windowHeight+ystep)) y1=windowHeight-1; else if(y1<-(windowHeight-rsize+ystep)) y1=-windowHeight+rsize-1; //用新坐标重新绘制场景 glutPostRedisplay(); glutTimerFunc(33,TimerFunction,1);}int main(int argc,char* argv[]){ glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB); glutInitWindowSize(800,600); glutCreateWindow("Bounce"); glutDisplayFunc(RenderScene); glutReshapeFunc(ChangeSize); glutTimerFunc(33,TimerFunction,1); SetupRC(); glutMainLoop(); return 0;}


经过演绎源代码,原来是 全局函数windowWidth和windowHeight未初始化。传承本书之前的惯例,将其初始化为100*100的裁剪区域。但运行后仍然存在问题:小方框反弹的矩形长或宽总有一个小于窗口。
ChangeSize()函数负责调整窗口的大小,查看源代码,裁剪区域是上一节的默认值100*100,所以问题就是要将其替换为新的随窗口w和h变化的windowWidth和windowHeight ChangeSize()这个函数挺有意思,我想了半天才想透它的道理:假设有一幅画,我们用四个很长的细木棍组成一个矩形(相当于窗口),将其放在画上面,那么木棍组成的矩形里面就是我们窗口可以看到的部分,移动四个木棍中的任何一个或者多个,相当于改变窗口的大小,也就是矩形的w和h在发生改变,但矩形中显示的画的部分大小却没有变哦,这跟小方框一直是正方形一个道理,它没有将原画进行拉伸,只是改变了显示的矩形的部分。
实现了小方框反弹的区域为实际窗口显示的部分的代码如下:

#include <windows.h>//#include "glee.h"#include <gl\gl.h>#include <gl\glu.h>#include <gl\glut.h>//方块的初始位置和大小GLfloat x1=0.0f;GLfloat y1=0.0f;GLfloat rsize=25;//在x和y方向的步进大小GLfloat xstep=1.0f;GLfloat ystep=1.0f;//追踪窗口宽度和高度的变化GLfloat windowWidth=100.0f;GLfloat windowHeight=100.0f;//绘制场景void RenderScene(void){ //用当前清除颜色清楚窗口 glClear(GL_COLOR_BUFFER_BIT); //把绘图颜色设置为红色 glColor3f(1.0f,0.0f,0.0f); //用当前颜色绘制一个填充矩形 glRectf(x1,y1,x1+rsize,y1-rsize); //刷新绘制命令并进行交换 //glFlush(); glutSwapBuffers();}//设置渲染状态void SetupRC(void){ glClearColor(0.0f,0.0f,1.0f,1.0f);}//设置渲染状态void ChangeSize(GLsizei w,GLsizei h){

windowWidth=100.0f; windowHeight=100.0f; GLfloat aspectRatio; //防止被0所除 if(h==0) h=1; //把视口设置为窗口的大小 glViewport(0,0,w,h); //重置坐标系统 glMatrixMode(GL_PROJECTION); glLoadIdentity(); //建立裁剪区域(左、右、底、顶、近、远) aspectRatio=(GLfloat)w/(GLfloat)h; if(w<=h) { windowHeight=windowHeight/aspectRatio; glOrtho(-windowWidth,windowWidth,-windowHeight,windowHeight,1.0,-1.0); } else { windowWidth*=aspectRatio; glOrtho(-windowWidth,windowWidth,-windowHeight,windowHeight,1.0,-1.0); } glMatrixMode(GL_MODELVIEW); glLoadIdentity();}//当空闲时由GLUT函数库调用void TimerFunction(int value){ //在到达左边或右边时翻转方向 if(x1>windowWidth-rsize||x1<-windowWidth) xstep=-xstep; //在到达顶边或底边时翻转方向 if(y1>windowHeight||y1<-windowHeight+rsize) ystep=-ystep; //实际移动方块 x1+=xstep; y1+=ystep; //检查边界 if(x1>(windowWidth-rsize+xstep)) x1=windowWidth-rsize-1; else if(x1<-(windowWidth+xstep)) x1=-windowWidth-1; if(y1>(windowHeight+ystep)) y1=windowHeight-1; else if(y1<-(windowHeight-rsize+ystep)) y1=-windowHeight+rsize-1; //用新坐标重新绘制场景 glutPostRedisplay(); glutTimerFunc(33,TimerFunction,1);}int main(int argc,char* argv[]){ glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB); glutInitWindowSize(800,600); glutCreateWindow("Bounce"); glutDisplayFunc(RenderScene); glutReshapeFunc(ChangeSize); glutTimerFunc(33,TimerFunction,1); SetupRC(); glutMainLoop(); return 0;}


原创粉丝点击