OpenGL练习(一):二维图形和鼠标键盘事件
本帖最后由 Rainyboy 于 2011-5-3 20:58 编辑作为工程师的基本技能,无论是机械设计图还是规律变化图,画图本身不是什么难事。然而OpenGL作为使用得最广泛的底层绘图库类之一,是值得学习的。本帖包含了四个例子,是近来在重新学习这一图形工具时的习作,分别是:
1,一个单摆的演示动画;
2,一个旋转的正方形(可以通过键盘控制转动方向);
3,一个可以画圆、矩形和直线的小绘图工具(可以通过键盘控制绘图类型,有最简单的绘图预览);
4,一个弹性球在窗口内四处碰撞的演示动画。
=========================================================
主程序的代码和预编译头文件的内容在这里给出,后续四个楼层分别给出这四个练习的具体代码。
===程序的入口点:OpenGLTest.cpp====
#include "stdafx.h"
#include "Simple_Pendulum.h"
#include "Rotat_Block.h"
#include "SimplePaint.h"
#include "ElasticBall.h"
int _tmain(int argc, _TCHAR* argv[])
{
system("cls");
cout<<"OpenGL练习 StageA: 二维图形和鼠标事件"<<endl;
cout<<"1,单摆"<<endl;
cout<<"2,旋转正方形"<<endl;
cout<<"3,简单鼠标绘图器"<<endl;
cout<<"4,弹性碰撞球"<<endl;
cout<<"输入选项:";
int c;
cin>>c;
switch(c)
{
case 1:
Simple_Pendulum(argc,argv);
break;
case 2:
Rotat_Block(argc,argv);
break;
case 3:
Simple_Paint(argc,argv);
break;
case 4:
Elastic_Ball(argc,argv);
break;
}
return 0;
}
===预编译头文件 stdafx.h =====
#pragma once
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
// TODO: 在此处引用程序需要的其他头文件
#include <windows.h>
#include <gl/GL.h>
#include <gl/GLU.h>
#include <gl/glut.h>
#include <math.h>
#include <stdlib.h>
#include <iostream>
#include <vector>
using namespace std;
本帖最后由 Rainyboy 于 2011-5-3 20:49 编辑
====单摆演示动画,头文件:Simple_Pendulum.h=======#include "stdafx.h"
class struct_SP_Global
{
public:
struct_SP_Global()
{
theta = 0;
theta_inc =1.0;
amplitude = 10.0;
DEG_TO_RAD = 0.017453;
}
public:
GLsizei ww;
GLsizei hh;
GLfloat theta;
GLfloat theta_inc;
GLfloat amplitude;
GLfloat DEG_TO_RAD;
};
void SP_userReshape(GLsizei w,GLsizei h);
void SP_display();
void SP_init();
void SP_myidle();
int Simple_Pendulum(int argc, _TCHAR* argv[]);
====单摆演示动画,代码文件:Simple_Pendulum.cpp======
#include "stdafx.h"
#include "Simple_Pendulum.h"
struct_SP_Global SP_Global;
void SP_userReshape(GLsizei w,GLsizei h)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-(GLdouble)w/2,(GLdouble)w/2,-(GLdouble)h/2,(GLdouble)h/2);
glMatrixMode(GL_MODELVIEW);
glViewport(0,0,w,h);
SP_Global.ww=w;
SP_Global.hh=h;
}
void SP_display()
{
glClear(GL_COLOR_BUFFER_BIT);
GLfloat startLoc = {0,SP_Global.hh/2};
GLfloat Length = SP_Global.hh*9/10;
GLfloat Angle = SP_Global.amplitude*SP_Global.DEG_TO_RAD*sin(2*SP_Global.DEG_TO_RAD*SP_Global.theta);
GLfloat endLoc = {startLoc+Length*sin(Angle),startLoc-Length*cos(Angle)};
GLfloat EdgeLoc ={0.0,0.0};
//画摆线
glBegin(GL_LINES);
{
glColor3f(1.0,1.0,1.0);
glVertex2fv(startLoc);
glVertex2fv(endLoc);
}
glEnd();
//画圆:以多边形边界逼近
glBegin(GL_LINE_LOOP);
{
glColor3f(1.0,1.0,1.0);
for(int i=0;i<20;++i)
{
GLfloat da = 360/20;
EdgeLoc = endLoc + 20*cos(i*SP_Global.DEG_TO_RAD*da);
EdgeLoc = endLoc + 20*sin(i*SP_Global.DEG_TO_RAD*da);
glVertex2fv(EdgeLoc);;
}
}
glEnd();
//抗锯齿
glLineWidth(2);
glEnable(GL_LINE_SMOOTH|GL_POINT_SMOOTH);
glutSwapBuffers();
}
void SP_init()
{
glClearColor(0.0,0.0,0.0,0.0);
glColor3f(1.0,1.0,1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-1.0,1.0,-1.0,1.0);
}
void SP_myidle()
{
SP_Global.theta += SP_Global.theta_inc;
if(SP_Global.theta > 360.0)
{
SP_Global.theta -=360.0;
}
glutPostRedisplay();
}
int Simple_Pendulum(int argc, _TCHAR* argv[])
{
glutInit(& argc,argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
glutInitWindowSize(150,400);
glutInitWindowPosition(0,0);
glutCreateWindow("Simple Pendulum");
//设置回调函数
glutDisplayFunc(SP_display);
glutReshapeFunc(SP_userReshape);
glutIdleFunc(SP_myidle);
//进入主消息循环
SP_init();
glutMainLoop();
return 0;
}
====旋转正方形:头文件Rotat_Block.h============#include "stdafx.h"
class struct_RB_Global
{
public:
struct_RB_Global()
{
theta=0.0;
DEG_TO_RAD=0.017453;
theta_inc =2.0;
}
public:
GLsizei ww,hh;
GLfloat theta;
GLfloat DEG_TO_RAD;
GLfloat theta_inc;
};
void RB_userReshape(GLsizei w,GLsizei h);
void RB_display();
void RB_init();
void RB_myidle();
void RB_mykey(unsigned char key,int x,int y);
int Rotat_Block(int argc, _TCHAR* argv[]);
====旋转正方形:代码文件Rotat_Block.cpp============
#include "stdafx.h"
#include "Rotat_Block.h"
struct_RB_Global RB_Global;
void RB_userReshape(GLsizei w,GLsizei h)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-(GLdouble)w/2,(GLdouble)w/2,-(GLdouble)h/2,(GLdouble)h/2);
glMatrixMode(GL_MODELVIEW);
glViewport(0,0,w,h);
RB_Global.ww=w;
RB_Global.hh=h;
}
void RB_display()
{
glClear(GL_COLOR_BUFFER_BIT);
GLsizei lw = RB_Global.ww>RB_Global.hh?RB_Global.hh:RB_Global.ww;
lw = lw/2;
GLfloat ALPHA = RB_Global.DEG_TO_RAD*RB_Global.theta;
glBegin(GL_POLYGON);
{
glColor3f(0.0,1.0,0.0);
glVertex2f(lw * sin(ALPHA),lw * cos(ALPHA));
glColor3f(1.0,0.0,0.0);
glVertex2f(-lw * cos(ALPHA),lw * sin(ALPHA));
glColor3f(0.0,0.0,1.0);
glVertex2f(-lw * sin(ALPHA),-lw * cos(ALPHA));
glColor3f(0.0,1.0,0.0);
glVertex2f(lw * cos(ALPHA),-lw * sin(ALPHA));
}
glEnd();
glutSwapBuffers();
}
void RB_init()
{
glClearColor(0.0,0.0,0.0,0.0);
glColor3f(1.0,1.0,1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-1.0,1.0,-1.0,1.0);
}
void RB_myidle()
{
RB_Global.theta += RB_Global.theta_inc;
if(RB_Global.theta > 360.0)
{
RB_Global.theta -=360.0;
}
glutPostRedisplay();
}
void RB_mykey(unsigned char key,int x,int y)
{
printf("%d,%d\n",x,y);
if (key=='R'||key=='r')
{
RB_Global.theta_inc *= -1;
}
else if(key=='S'||key=='s')
{
glutIdleFunc(NULL);
}
else if(key=='G'||key=='g')
{
glutIdleFunc(RB_myidle);
}
glutPostRedisplay();
}
int Rotat_Block(int argc, _TCHAR* argv[])
{
glutInit(& argc,argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
glutInitWindowSize(500,500);
glutInitWindowPosition(0,0);
glutCreateWindow("Rotat Block");
//设置回调函数
glutDisplayFunc(RB_display);
glutReshapeFunc(RB_userReshape);
glutIdleFunc(RB_myidle);
glutKeyboardFunc(RB_mykey);
//进入主消息循环
RB_init();
//
cout<<"R :反转选装方向"<<endl;
cout<<"S :停止旋转"<<endl;
cout<<"G :重新开始旋转"<<endl;
//
glutMainLoop();
return 0;
}
====简单绘图器,头文件SimplePaint.h===============#include "stdafx.h"
#define PT_FIRST_CLICK 0
#define PT_SENCOND_CLICK 1
#define PT_NEVER_CLICK 2
#define ST_LINE 10
#define ST_BLOCK 11
#define ST_CIRCLE 12
struct PicItem
{
GLint x_1,x_2,y_1,y_2;
int PaintTag;
int StyleTag;
};
typedef vector<PicItem> PicItem_vec;
class struct_SPAINT_Global
{
public:
struct_SPAINT_Global()
{
PaintTag = PT_NEVER_CLICK;
StyleTag = ST_CIRCLE;
DEG_TO_RAD = 0.017453;
}
public:
GLfloat DEG_TO_RAD;
GLsizei ww,hh;
GLint x_1,x_2,y_1,y_2;
int PaintTag;
int StyleTag;
PicItem_vec PicItemHist;
};
void PlotItem(int x_1,int y_1,int x_2,int y_2,int PaintTag,int StyleTag);
void SPAINT_userReshape(GLsizei w,GLsizei h);
void SPAINT_display();
void SPAINT_init();
void SPAINT_mykey(unsigned char key,int x,int y);
void SPAINT_mymouse(int button, int state, int x,int y);
int Simple_Paint(int argc, _TCHAR* argv[]);
void SPAINT_myPasstiveMotion(int x,int y);
====简单绘图器,代码文件SimplePaint.cpp==============
#include "stdafx.h"
#include "SimplePaint.h"
struct_SPAINT_Global SPAINT_Global;
void SPAINT_userReshape(GLsizei w,GLsizei h)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-(GLdouble)w/2,(GLdouble)w/2,-(GLdouble)h/2,(GLdouble)h/2);
glMatrixMode(GL_MODELVIEW);
glViewport(0,0,w,h);
SPAINT_Global.ww=w;
SPAINT_Global.hh=h;
}
void SPAINT_display()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0.0,0.0,0.0);
//绘制已有的图形
for(int i=0;i<SPAINT_Global.PicItemHist.size();++i)
{
PlotItem(
SPAINT_Global.PicItemHist.x_1,
SPAINT_Global.PicItemHist.y_1,
SPAINT_Global.PicItemHist.x_2,
SPAINT_Global.PicItemHist.y_2,
SPAINT_Global.PicItemHist.PaintTag,
SPAINT_Global.PicItemHist.StyleTag
);
}
glColor3f(1.0,0.0,0.0);
//绘制试探的图形
PlotItem(
SPAINT_Global.x_1,
SPAINT_Global.y_1,
SPAINT_Global.x_2,
SPAINT_Global.y_2,
PT_SENCOND_CLICK,
SPAINT_Global.StyleTag
);
//抗锯齿
glLineWidth(1.5);
glPolygonMode(GL_FRONT,GL_LINE);
glPolygonMode(GL_BACK,GL_LINE);
glEnable(GL_LINE_SMOOTH|GL_POINT_SMOOTH);
glutSwapBuffers();
}
void PlotItem(int x_1,int y_1,int x_2,int y_2,int PaintTag,int StyleTag)
{
GLfloat da;
GLfloat R =(x_1 - x_2)*(x_1 - x_2) + (y_1 - y_2)*(y_1 - y_2);
R = pow((float)R,(float)0.5)/2;
switch(PaintTag)
{
case PT_FIRST_CLICK:
case PT_NEVER_CLICK:
return;
case PT_SENCOND_CLICK:
switch(StyleTag)
{
case ST_BLOCK:
glBegin(GL_POLYGON);
{
glVertex2i(x_1,y_1);
glVertex2i(x_1,y_2);
glVertex2i(x_2,y_2);
glVertex2i(x_2,y_1);
}
glEnd();
break;
case ST_LINE:
glBegin(GL_LINES);
{
glVertex2i(x_1,y_1);
glVertex2i(x_2,y_2);
}
glEnd();
break;
case ST_CIRCLE:
glBegin(GL_LINE_LOOP);
{
for(int i=0;i<40;++i)
{
da= 360/40;
glVertex2f((x_1+x_2)/2 + R*cos(i*SPAINT_Global.DEG_TO_RAD*da),
(y_1+y_2)/2 + R*sin(i*SPAINT_Global.DEG_TO_RAD*da));
}
}
glEnd();
break;
}
}
}
void SPAINT_init()
{
glClearColor(1.0,1.0,1.0,1.0);
glColor3f(1.0,1.0,1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-1.0,1.0,-1.0,1.0);
}
void SPAINT_mykey(unsigned char key,int x,int y)
{
if (key=='L'||key=='l')
SPAINT_Global.StyleTag = ST_LINE;
else if(key=='B'||key=='b')
SPAINT_Global.StyleTag = ST_BLOCK;
else if(key=='C'||key=='c')
SPAINT_Global.StyleTag = ST_CIRCLE;
}
void SPAINT_mymouse(int button, int state, int x,int y)
{
if(state == GLUT_DOWN && button == GLUT_LEFT_BUTTON)
{
if(SPAINT_Global.PaintTag == PT_FIRST_CLICK || SPAINT_Global.PaintTag == PT_NEVER_CLICK)
{
SPAINT_Global.x_2 = x - SPAINT_Global.ww/2;
SPAINT_Global.y_2 = SPAINT_Global.hh/2 - y;
SPAINT_Global.PaintTag = PT_SENCOND_CLICK;
}
else if(SPAINT_Global.PaintTag == PT_SENCOND_CLICK)
{
SPAINT_Global.x_1 = x - SPAINT_Global.ww/2;
SPAINT_Global.y_1 = SPAINT_Global.hh/2 - y;
PicItem tPI;
tPI.x_1 = SPAINT_Global.x_1;
tPI.x_2 = SPAINT_Global.x_2;
tPI.y_1 = SPAINT_Global.y_1;
tPI.y_2 = SPAINT_Global.y_2;
tPI.PaintTag = SPAINT_Global.PaintTag;
tPI.StyleTag = SPAINT_Global.StyleTag;
SPAINT_Global.PicItemHist.push_back(tPI);
SPAINT_Global.PaintTag = PT_FIRST_CLICK;
}
}
glutPostRedisplay();
}
void SPAINT_myPasstiveMotion(int x,int y)
{
if(SPAINT_Global.PaintTag == PT_FIRST_CLICK || SPAINT_Global.PaintTag == PT_NEVER_CLICK)
return;
SPAINT_Global.x_1 = x - SPAINT_Global.ww/2;
SPAINT_Global.y_1 = SPAINT_Global.hh/2 - y;
glutPostRedisplay();
}
int Simple_Paint(int argc, _TCHAR* argv[])
{
glutInit(& argc,argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
glutInitWindowSize(500,500);
glutInitWindowPosition(0,0);
glutCreateWindow("Simple");
//设置回调函数
glutDisplayFunc(SPAINT_display);
glutReshapeFunc(SPAINT_userReshape);
glutKeyboardFunc(SPAINT_mykey);
glutMouseFunc(SPAINT_mymouse);
glutPassiveMotionFunc(SPAINT_myPasstiveMotion);
//
cout<<"C : 画圆环"<<endl;
cout<<"L : 画直线"<<endl;
cout<<"B : 画矩形"<<endl;
//
//进入主消息循环
SPAINT_init();
glutMainLoop();
return 0;
}
=====弹性小球演示动画,头文件 ElasticBall.h================#include "stdafx.h"
class struct_EB_Global
{
public:
struct_EB_Global()
{
R = 40.0;
DEG_TO_RAD = 0.017453;
CenterLoc = 0;
CenterLoc = 0;
Velocity=1.4;
Velocity=2.7;
Step = 1.0;
}
public:
GLsizei ww;
GLsizei hh;
GLfloat R;
GLfloat DEG_TO_RAD;
GLint CenterLoc;
GLfloat Velocity;
GLfloat Step;
};
void EB_userReshape(GLsizei w,GLsizei h);
void EB_display();
void EB_init();
void EB_myidle();
int Elastic_Ball(int argc, _TCHAR* argv[]);
=====弹性小球演示动画,代码文件 ElasticBall.cpp===============
#include "stdafx.h"
#include "ElasticBall.h"
struct_EB_Global EB_Global;
void EB_userReshape(GLsizei w,GLsizei h)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-(GLdouble)w/2,(GLdouble)w/2,-(GLdouble)h/2,(GLdouble)h/2);
glMatrixMode(GL_MODELVIEW);
glViewport(0,0,w,h);
EB_Global.ww=w;
EB_Global.hh=h;
}
void EB_display()
{
glClear(GL_COLOR_BUFFER_BIT);
//画圆:以多边形边界逼近
GLfloat EdgeLoc;
glBegin(GL_LINE_LOOP);
{
glColor3f(1.0,1.0,1.0);
for(int i=0;i<20;++i)
{
GLfloat da = 360/20;
EdgeLoc = EB_Global.CenterLoc + EB_Global.R*cos(i*EB_Global.DEG_TO_RAD*da);
EdgeLoc = EB_Global.CenterLoc + EB_Global.R*sin(i*EB_Global.DEG_TO_RAD*da);
glVertex2fv(EdgeLoc);
}
}
glEnd();
//抗锯齿
glLineWidth(2);
glEnable(GL_LINE_SMOOTH|GL_POINT_SMOOTH);
glutSwapBuffers();
}
void EB_init()
{
glClearColor(0.0,0.0,0.0,0.0);
glColor3f(1.0,1.0,1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-1.0,1.0,-1.0,1.0);
}
void EB_myidle()
{
EB_Global.CenterLoc+=EB_Global.Velocity*EB_Global.Step;
if(abs(EB_Global.CenterLoc) + EB_Global.R >EB_Global.hh/2)
{
EB_Global.Velocity *= -1;
}
EB_Global.CenterLoc+=EB_Global.Velocity*EB_Global.Step;
if(abs(EB_Global.CenterLoc) + EB_Global.R >EB_Global.ww/2)
{
EB_Global.Velocity *= -1;
}
glutPostRedisplay();
}
int Elastic_Ball(int argc, _TCHAR* argv[])
{
glutInit(& argc,argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
glutInitWindowSize(500,500);
glutInitWindowPosition(0,0);
glutCreateWindow("Simple Pendulum");
//设置回调函数
glutDisplayFunc(EB_display);
glutReshapeFunc(EB_userReshape);
glutIdleFunc(EB_myidle);
//进入主消息循环
EB_init();
glutMainLoop();
return 0;
}
院长,猛男!程序运行了下,感觉不错,多谢分享哈! 回复 6 # meiyongyuandeze 的帖子
哪里,过奖了……远未触及OpenGL的精髓……路还长啊,呵呵 恩……我想问下……我编写OpenGL代码时,主函数如果是 _tmain(int argc, _TCHAR* argv[])
会报错,只可以在int main(int argc, char **argv) 或int main(int argc, char *argv[])……这是什么原因呢
回复 8 # hityrj 的帖子
哦,可能是由于UNICODE兼容方面的问题吧,你看看这个
http://baike.baidu.com/view/3478231.htm 采用Java 3d来做也不错,用它做个输电塔振型动画。 回复 10 # impulse 的帖子
嗯嗯,做动画的方式还是很多的,达到目的就行 学习了! 学习了~~~~~~~~~~
页:
[1]