一.3D空间中的点
#include <gl/glut.h>
#include <math.h>
#define GL_PI 3.1415f
static GLfloat xRot = 0.0f;
static GLfloat yRot = 0.0f;
void RenderScene(void)
{
GLfloat x, y, z, angle; // 存储坐标和角度
// 用当前颜色清除窗口
glClear(GL_COLOR_BUFFER_BIT);
// 保存矩阵状态并进行旋转
glPushMatrix();
glRotatef(xRot, 1.0f, 0.0f, 0.0f);
glRotatef(yRot, 0.0f, 1.0f, 0.0f);
// 对所有剩余的点只调用一次
glBegin(GL_POINTS);
z = -50.0f;
for(angle = 0.0f; angle <= (2.0*GL_PI)*3.0f; angle += 0.1f)
{
x = 50.0f*sin(angle);
y = 50.0f*cos(angle);
// 指定点并稍稍变化Z值
glVertex3f(x, y, z);
z += 0.5f;
}
glEnd();
// 恢复变换
glPopMatrix();
// 刷新绘图命令
glutSwapBuffers();
}
// 在渲染环境下进行初始化工作
void SetupRC()
{
// 黑色背景
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// 绘图颜色为绿色
glColor3f(0.0f, 1.0f, 0.0f);
}
// 键盘箭头键控制旋转图形
void SpecialKeys(int key, int x, int y)
{
if(key == GLUT_KEY_UP)
xRot-= 5.0f;
if(key == GLUT_KEY_DOWN)
xRot += 5.0f;
if(key == GLUT_KEY_LEFT)
yRot -= 5.0f;
if(key == GLUT_KEY_RIGHT)
yRot += 5.0f;
if(key > 356.0f)
xRot = 0.0f;
if(key < -1.0f)
xRot = 355.0f;
if(key > 356.0f)
yRot = 0.0f;
if(key < -1.0f)
yRot = 355.0f;
// 刷新窗口
glutPostRedisplay();
}
// 修改可视区域的视口,当窗口改变时被调用
void ChangeSize(int w, int h)
{
GLfloat nRange = 100.0f;
// 防止被0除
if(h == 0)
h = 1;
// 将视口设置为窗口尺寸
glViewport(0, 0, w, h);
// 重置投影矩阵堆栈
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//建立裁剪区(左,右,下,上,近,远)
if (w <= h)
glOrtho (-nRange, nRange, -nRange*h/w, nRange*h/w, -nRange, nRange);
else
glOrtho (-nRange*w/h, nRange*w/h, -nRange, nRange, -nRange, nRange);
// 重置模型视图矩阵堆栈
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void main()
{
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutCreateWindow("Points Example");
glutReshapeFunc(ChangeSize);
glutSpecialFunc(SpecialKeys);
glutDisplayFunc(RenderScene);
SetupRC();
glutMainLoop();
}
运行结果:
初始为一个由点组成的圆,这是因为从Z轴直接正面观察这张图。
通过键盘键上下左右键旋转这张图形:
设置3D画布
// 修改可视区域的视口,当窗口改变时被调用
void ChangeSize(int w, int h)
{
GLfloat nRange = 100.0f;
// 防止被0除
if(h == 0)
h = 1;
// 将视口设置为窗口尺寸
glViewport(0, 0, w, h);
// 重置投影矩阵堆栈
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//建立裁剪区(左,右,下,上,近,远)
if (w <= h)
glOrtho (-nRange, nRange, -nRange*h/w, nRange*h/w, -nRange, nRange);
else
glOrtho (-nRange*w/h, nRange*w/h, -nRange, nRange, -nRange, nRange);
// 重置模型视图矩阵堆栈
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
如图为一个简单的可视区域,这个可视区域包围的区域就是一个笛卡尔坐标空间。在所有的3个轴(X,Y和Z)中,它们的范围都是从-100至+100,这个区域就是三维画布,可以用OpenGL命令和函数在上面进行绘图。
3D空间中的点:顶点
glVertex3f(50.0f,50.0f,0.0f)
这行代码就描绘了一个X轴上为50个单位,Y轴上为50个单位,Z轴上为0个单位的三维空间中的点。
接受2个参数的glVertex2f函数,则只指定X与Y的值,而默认Z坐标为0.0。
接受4个参数的glVertex4f函数,使用第四个坐标值W用来表示缩放度(一般默认为1.0)。
图元
图元是一组顶点的集合,她们构成了在屏幕上所绘制的形状,如图所示,OpenGL共有10种图元,从空间中的一个点到任意数量边的闭合多边形。
绘制图元的方式是使用glBegin命令告诉OpenGL开始对一组顶点进行解释,把它作为一个特定的图元,然后调用glEnd命令结束组成这个图元的列表。
// 绘制点
glBegin(GL_POINTS); // 选择点作为图元
glVertex3f(0.0f,0.0f,0.0f); // 指定点
glVertex3f(0.0f,0.0f,0.0f) ;
glEnd( ); // 完成绘点
设置点的大小
当我们绘制一个点时,在默认情况下点的大小是一个像素,我们可以通过glPointSize
函数修改点的大小。该函数接受一个参数,它用于指定被绘点的近似直径(以像素计),但是点的大小是存在限制的。可以通过以下代码实现:
GLfloat sizes[2]; // 存储受支持的点的大小范围
GLfloat step; // 存储受支持的点的大小增量
// 获得受支持的点的大小范围以及增量大小
glGetFloatv(GL_POINT_SIZE_RANGE,sizes);
glGetFloatv(GL_POINT_SIZE_GRANULARITY,&step);
其中sizes数组将包含两个元素,分别表示glPointSize的最小和最大有效值,step表示点大小范围之内最小允许的步进值。
二. 3D空间中的线
#include <gl/glut.h>
#include <math.h>
// 为PI的值定义一个常量
#define GL_PI 3.1415f
static GLfloat xRot = 0.0f;
static GLfloat yRot = 0.0f;
// Called to draw scene
void RenderScene(void)
{
GLfloat x,y,z,angle; // Storeage for coordinates and angles
// Clear the window with current clearing color
glClear(GL_COLOR_BUFFER_BIT);
// Save matrix state and do the rotation
glPushMatrix();
glRotatef(xRot, 1.0f, 0.0f, 0.0f);
glRotatef(yRot, 0.0f, 1.0f, 0.0f);
// Call only once for all remaining points
glBegin(GL_LINES);
z = 0.0f;
for(angle = 0.0f; angle <= GL_PI; angle += (GL_PI / 20.0f))
{
// Top half of the circle
x = 50.0f*sin(angle);
y = 50.0f*cos(angle);
glVertex3f(x, y, z);
// Bottom half of the circle
x = 50.0f*sin(angle+GL_PI);
y = 50.0f*cos(angle+GL_PI);
glVertex3f(x, y, z);
}
// Done drawing points
glEnd();
// Restore transformations
glPopMatrix();
// Flush drawing commands
glutSwapBuffers();
}
// This function does any needed initialization on the
// rendering context.
void SetupRC()
{
// Black background
glClearColor(0.0f, 0.0f, 0.0f, 1.0f );
// Set drawing color to green
glColor3f(0.0f, 1.0f, 0.0f);
}
///////////////////////////////////////////////////////////
// Respond to arrow keys
void SpecialKeys(int key, int x, int y)
{
if(key == GLUT_KEY_UP)
xRot-= 5.0f;
if(key == GLUT_KEY_DOWN)
xRot += 5.0f;
if(key == GLUT_KEY_LEFT)
yRot -= 5.0f;
if(key == GLUT_KEY_RIGHT)
yRot += 5.0f;
if(key > 356.0f)
xRot = 0.0f;
if(key < -1.0f)
xRot = 355.0f;
if(key > 356.0f)
yRot = 0.0f;
if(key < -1.0f)
yRot = 355.0f;
// Refresh the Window
glutPostRedisplay();
}
///////////////////////////////////////////////////////////
// Window has changed size, recalculate projection
void ChangeSize(int w, int h)
{
GLfloat nRange = 100.0f;
// Prevent a divide by zero
if(h == 0)
h = 1;
// Set Viewport to window dimensions
glViewport(0, 0, w, h);
// Reset coordinate system
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Establish clipping volume (left, right, bottom, top, near, far)
if (w <= h)
glOrtho (-nRange, nRange, -nRange*h/w, nRange*h/w, -nRange, nRange);
else
glOrtho (-nRange*w/h, nRange*w/h, -nRange, nRange, -nRange, nRange);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
///////////////////////////////////////////////////////////
// Main Program Entry Point
void main()
{
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(800,600);
glutCreateWindow("Lines Example");
glutReshapeFunc(ChangeSize);
glutSpecialFunc(SpecialKeys);
glutDisplayFunc(RenderScene);
SetupRC();
glutMainLoop();
}
运行结果:
绘制直线
选择绘制直线的图元GL_LINES,指定两个顶点,在它们之间绘制一条直线。
glBegin(GL_LINES); // 选择线作为图元
glVertex3f(0.0f,0.0f,0.0f); // 指定点
glVertex3f(50.0f,50.0f,50.0f) ;
glEnd( ); // 完成绘线
注意,这里用两个顶点指定了一个图元,每两个指定的顶点用于绘制一条直线。如果指定奇数个顶点,那么最后一个顶点会被忽略。
线带与线环
GL_LINE_STRIP:线带,它允许指定一个顶点列表,并绘制一条经过所有这些顶点的连续的线。
GL_LINE_LOOP:线环,它与线带非常类似,会在顶点列表的最后一个顶点和第一个顶点之间也绘制一条直线。因此会形成一个闭合的图形。