代码思路
本节的目标:创建一个可以旋转的颜色渐变的三棱锥
主函数
主函数的思路还是一样的,进行基本的配置,调用渲染函数和循环函数
int main(int argc, char* argv[])
{
glutInit(&argc, argv); //初始化
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); //设置显示模式为RGBA模式和双缓冲模式
glutInitWindowPosition(200, 200); //设置窗口位置
glutInitWindowSize(WIDTH, HEIGHT); //设置窗口大小,此处为400*400
glutCreateWindow("OpenGL 窗口"); //设置显示窗口名称
glutDisplayFunc(&myDisplay); //调用主渲染函数
glutIdleFunc(&myIdle); //调用自动执行函数
glutMainLoop(); //设置主循环
return 0;
}
渲染函数
基本上思路就是分别绘制出三棱锥的四个顶点,然后逐步给顶点设置相应的颜色,绘制完成之后读取当前的角度,并旋转操作,交换深度测试缓冲区数据。
void myDisplay(void)
{
static int list = 0;
if( list == 0 )
{
GLfloat
PointA[] = { 0.5f, -sqrt(6.0f)/12, -sqrt(3.0f)/6}, //分别在xyz[-1.0,1.0]的范围上计算四个点的绝对坐标
PointB[] = {-0.5f, -sqrt(6.0f)/12, -sqrt(3.0f)/6},
PointC[] = { 0.0f, -sqrt(6.0f)/12, sqrt(3.0f)/3},
PointD[] = { 0.0f, sqrt(6.0f)/4, 0 };
GLfloat
ColorR[] = {1, 0, 0}, //设置RGB颜色
ColorG[] = {0, 1, 0},
ColorB[] = {0, 0, 1},
ColorY[] = {1, 1, 0}; //最后这个是黄色
list = glGenLists(1); //创建批量处理
glNewList(list, GL_COMPILE);
glBegin(GL_TRIANGLES); //根据三个顶点逐步绘制出四面体的四个三角面,所以这里是“GL_TRIANGLES”
// 平面ABC
ColoredVertex(ColorR, PointA); //给不同的顶点设置不同的颜色
ColoredVertex(ColorG, PointB);
ColoredVertex(ColorB, PointC);
// 平面ACD
ColoredVertex(ColorR, PointA);
ColoredVertex(ColorB, PointC);
ColoredVertex(ColorY, PointD);
// 平面CBD
ColoredVertex(ColorB, PointC);
ColoredVertex(ColorG, PointB);
ColoredVertex(ColorY, PointD);
// 平面BAD
ColoredVertex(ColorG, PointB);
ColoredVertex(ColorR, PointA);
ColoredVertex(ColorY, PointD);
glEnd();
glEndList(); //设置列表完毕
glEnable(GL_DEPTH_TEST); //开启深度测试
}
// 已经创建了显示列表,在每次绘制正四面体时将调用它
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //清空缓存区
glPushMatrix(); //缓存进栈
glRotatef(angle, 1, 0.5, 0); //旋转
glCallList(list);
glPopMatrix(); //缓存出栈
glutSwapBuffers(); //交换缓冲区
}
这里粗略介绍一下glPushMatrix()和glPopMatrix(),
glPushMatrix、glPopMatrix操作事实上就相当于栈里的入栈和出栈。
比如你当前的坐标系原点在你电脑屏幕的左上方。如今你调用glPushMatrix,然后再调用一堆平移、旋转代码等等,然后再绘图。那些平移和旋转都是基于左上角为原点进行变化的。并且都会改变坐标的位置,经过了这些变化后,你的坐标肯定不再左上角了。
那假设想恢复怎么办呢?这时就调用glPopMatrix从栈里取出一个“状态”了,这个状态就是你调用glPushMatrix之前的那个状态。就如非常多opengl的书上所讲:调用glPushMatrix事实上就是把当前状态做一个副本放入堆栈之中。
当你做了一些移动或旋转等变换后,使用glPushMatrix();
OpenGL 会把这个变换后的位置和角度保存起来。
然后你再随便做第二次移动或旋转变换,再用glPopMatrix();
OpenGL 就把刚刚保存的那个位置和角度恢复。
具体可以参考这篇文章
自动执行函数
void myIdle(void)
{
++angle; //旋转角度自增
if( angle >= 360.0f ) //旋转角度循环
angle = 0.0f;
myDisplay(); //每次角度改变调用渲染函数
}
完整代码
#include <gl/glut.h>
#define WIDTH 400
#define HEIGHT 400
#include <math.h>
#define ColoredVertex(c, v) do{ glColor3fv(c); glVertex3fv(v); }while(0)
GLfloat angle = 0.0f;
void myDisplay(void)
{
static int list = 0;
if( list == 0 )
{
GLfloat
PointA[] = { 0.5f, -sqrt(6.0f)/12, -sqrt(3.0f)/6},
PointB[] = {-0.5f, -sqrt(6.0f)/12, -sqrt(3.0f)/6},
PointC[] = { 0.0f, -sqrt(6.0f)/12, sqrt(3.0f)/3},
PointD[] = { 0.0f, sqrt(6.0f)/4, 0};
GLfloat
ColorR[] = {1, 0, 0},
ColorG[] = {0, 1, 0},
ColorB[] = {0, 0, 1},
ColorY[] = {1, 1, 0};
list = glGenLists(1);
glNewList(list, GL_COMPILE);
glBegin(GL_TRIANGLES);
// 平面ABC
ColoredVertex(ColorR, PointA);
ColoredVertex(ColorG, PointB);
ColoredVertex(ColorB, PointC);
// 平面ACD
ColoredVertex(ColorR, PointA);
ColoredVertex(ColorB, PointC);
ColoredVertex(ColorY, PointD);
// 平面CBD
ColoredVertex(ColorB, PointC);
ColoredVertex(ColorG, PointB);
ColoredVertex(ColorY, PointD);
// 平面BAD
ColoredVertex(ColorG, PointB);
ColoredVertex(ColorR, PointA);
ColoredVertex(ColorY, PointD);
glEnd();
glEndList();
glEnable(GL_DEPTH_TEST);
}
// 已经创建了显示列表,在每次绘制正四面体时将调用它
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glRotatef(angle, 1, 0.5, 0);
glCallList(list);
glPopMatrix();
glutSwapBuffers();
}
void myIdle(void)
{
++angle;
if( angle >= 360.0f )
angle = 0.0f;
myDisplay();
}
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
glutInitWindowPosition(200, 200);
glutInitWindowSize(WIDTH, HEIGHT);
glutCreateWindow("OpenGL 窗口");
glutDisplayFunc(&myDisplay);
glutIdleFunc(&myIdle);
glutMainLoop();
return 0;
}
效果展示
读者也可以根据自己的需要修改代码,这里设置好顶点的颜色之后,一个面内的颜色是自动渐变的。
(如有错误请及时联系我修改,谢谢!)