/* 在OpenGL中实现双缓冲技术的一种简单方法:
1. 在调用glutInitDisplayMode函数时, 开启GLUT_DOUBLE,即glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);。这里将我们惯用的
GLUT_SINGLE替换为GLUT_DOUBLE,意为要使用双缓冲而非单缓冲。
2. 调用glutDisplayFunc(display)注册回调函数时, 在回调函数中所有绘制操作完成后调用glutSwapBuffers()交换两个缓冲区指针。
3. 调用glutIdleFunc注册一个空闲时绘制操作函数, 注册的这个函数再间接调用display函数。
*/
以下是下是2种实现2维的日地月旋转关系,直接计算要画的点的位置,非矩阵实现
///////////////////////////////直接计算实现/////////////////////////////
#include "glut.h"
#include <math.h>
int t=0; // 地球绕太阳轨道变化的角度值
void init (void)
{
glClearColor(0.0,0.0,0.0,1.0);
glMatrixMode(GL_PROJECTION);
gluOrtho2D(0.0,400.0,0.0,400.0);
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0,0.0,0.0);
}
void drawcircle(double x,double y,double r)
{
for (int i=0;i<=20;i++)
{
double delta = 3.1415926*2.0/20.0;
glBegin(GL_POLYGON);
glVertex2f(x, y);
glVertex2f(x+r*cos(delta*i),y+r*sin(delta*i));
glVertex2f(x+r*cos(delta*(i+1)),y+r*sin(delta*(i+1)));
glEnd();
}
}
void idlefunc(void)
{
t++;
glutPostRedisplay(); // 引起重绘
}
void func_display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glColor3f(1.0,0.0,0.0);
drawcircle(200,200,20); // 太阳的圆心在(200,200)半径大小为20
double r1=100;
double r2=40;
int xx,yy; // 这里算出地球的圆心位置,它的半径大小是15,绕太阳转的轨道半径为r1=100
xx=200+r1*cos((3.1415926*2.0/360.0)*(t%360)); // idlefunc 里让t++ ,t是角度,cos的括号里算出弧度而已
yy=200+r1*sin((3.1415926*2.0/360.0)*(t%360));
glColor3f(0.0,0.5,1.0);
drawcircle(xx,yy,15);
int xxx,yyy; // 这里算出月亮的圆心位置,它的半径大小是5,绕地球转的轨道半径为r2=40
xxx=xx+r2*cos((3.1415926*2.0/360.0)*(12*t%360));// idlefunc 里让t++ ,t是角度,cos的括号里算出弧度而已
yyy=yy+r2*sin((3.1415926*2.0/360.0)*(12*t%360)); // 12 是指月亮角度速度是地球的12倍
glColor3f(1.0,1.0,1.0);
drawcircle(xxx,yyy,5);
glFlush();
glutSwapBuffers();
}
void main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
glutInitWindowPosition(100,100);
glutInitWindowSize(800,800);
glutCreateWindow("circle");
init();
glutDisplayFunc(func_display);
glutIdleFunc(idlefunc);
glutMainLoop();
}
////////////////////////////////////////////////矩阵实现/////////////////////////////////////////
#include "glut.h"
#include <math.h>
int t=0; // 地球饶太阳轨道变化的角度值
void init (void)
{
glClearColor(0.0,0.0,0.0,1.0);
glMatrixMode(GL_PROJECTION);
gluOrtho2D(0.0,400.0,0.0,400.0);
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0,0.0,0.0);
}
void drawcircle(double x,double y,double r) // 日 地 月 都靠这个画出来 这个和矩阵无关的,其实opengl 有自带的画圆形的函数,不需要自己定义
{
for (int i=0;i<=20;i++)
{
double delta = 3.1415926*2.0/20.0;
glBegin(GL_POLYGON); // 其实这边画了个特别窄小的三角形而已,循环后即一个填充后的圆了
glVertex2f(x, y);
glVertex2f(x+r*cos(delta*i),y+r*sin(delta*i));
glVertex2f(x+r*cos(delta*(i+1)),y+r*sin(delta*(i+1)));
glEnd();
}
}
void idlefunc(void)
{
t+=1;
glutPostRedisplay(); //投递一个重绘窗口的操作
}
void display_func(void)
{
double r1=100; // 轨道转动半径1
double r2=40; // 轨道转动半径2
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
// glLoadIdentity():该函数的功能是重置当前指定的矩阵为单位矩阵。
glLoadIdentity();
//-------------日--------------
glTranslatef(200,200,0);
glPushMatrix();
glColor3f(1.0,0.0,0.0);
drawcircle(0,0,20);
//-------------地---------------
glPopMatrix();
glRotatef(t%360,0,0,1); // 因为是2维的,所以是饶z轴旋转的t%360 的角度 idlefunc里对t++
glTranslatef(r1,0,0);
glPushMatrix();
glColor3f(0.0,0.5,1.0);
drawcircle(0,0,15);
//-------------月----------------
glPopMatrix();
glRotatef((t*12)%360,0,0,1); // 月亮的角度t变化速度是地球角度t变化的12倍
glTranslatef(r2,0,0);
glColor3f(1.0,1.0,1.0);
drawcircle(0,0,5);
glFlush();
glutSwapBuffers();
}
void main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
glutInitWindowPosition(100,100);
glutInitWindowSize(800,800);
glutCreateWindow("circle");
init();
glutDisplayFunc(display_func); // 假如要重绘时调用display_func这个函数进行具体绘画响应
glutIdleFunc(idlefunc); // 空闲时调用idlefunc这个函数
glutMainLoop();
}
opengl中图形绘制后,往往需要一系列的变换来达到用户的目的,而这种变换实现的原理是又通过矩阵进行操作的。opengl中的变换一般包括视图变换、模型变换、投影变换等,在每次变换后,opengl将会呈现一种新的状态(这也就是我们为什么会成其为状态机)。
对于矩阵的实现的方式一开始一直很疑惑,矩阵最终操作的是的确是模型视图中每个点没错,但是glRotatef((t*12)%360,0,0,1);
glTranslatef(r2,0,0);这种操作改变的不是点,而是当前矩阵,然而当前矩阵也有很多种。
在opengl场景中一般存在多种矩阵变换操作,而控制这些操作的命令主要用到
glMatrixMode(GLenum mode);
作用:用于指定用哪个矩阵作为当前矩阵,mode用于指定哪一种矩阵栈是其后矩阵操作的目标。mode可取:
GL_MODELVIEW: 把其后的矩阵操作施加于造型视图矩阵栈。(默认)
GL_PROJECTION: 把其后的矩阵操作施加于投影矩阵栈。
GL_TEXTURE: 把其后的矩阵操作施加于纹理矩阵栈。
更多请看http://blog.youkuaiyun.com/hlj184/article/details/8107940的解释,不过他的图画的似乎不是栈了。
于是按我的理解,画出图为如下所示:
可以看到每次平移旋转等操作改变的是栈顶位置的矩阵,矩阵先调用的后执行变换。
2个运行速度差不多相同,看不出区别: