OpenGL学习进程(4)第二课:绘制图形
本节是OpenGL学习的第二个课时,下面介绍如何用点和线来绘制图形:
(1)用点的坐标来绘制矩形:
#include <GL/glut.h> void display(void)
{
// clear all pixels
glClear(GL_COLOR_BUFFER_BIT); // draw yellow polygon (rectangle) with corners at
glColor3f(1.0, 1.0, 0.0);
glBegin(GL_POLYGON); //绘制开始前必须调用glBegin以通知绘制图形的类型,比如还可以绘制点,线等。
glVertex3f(0.20, 0.20, 0.0);
glVertex3f(0.80, 0.20, 0.0);
glVertex3f(0.80, 0.80, 0.0);
glVertex3f(0.20, 0.80, 0.0);
glEnd(); //结束之后则要调用glEnd函数 glFlush();
} void init(void)
{
// select clearing color: blue
glClearColor(0.0, 1.0, 0.0, 0.0); // initialize viewing values
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
} int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(, );
glutInitWindowPosition(, );
glutCreateWindow("polyon");
init();
glutDisplayFunc(display);
glutMainLoop();
return ;
}
代码解释:
1)glClear(GLbitfield mask)
glClear sets the bitplane area of the window to values previously selected by glClearColor, glClearDepth, and glClearStencil. Multiple color buffers can be cleared simultaneously by selecting more than one buffer at a time using glDrawBuffer.
The pixel ownership test, the scissor test, dithering, and the buffer writemasks affect the operation of glClear. The scissor box bounds the cleared region. Alpha function, blend function, logical operation, stenciling, texture mapping, and depth-buffering are ignored by glClear.
glClear takes a single argument that is the bitwise OR of several values indicating which buffer is to be cleared.The values are as follows:
GL_COLOR_BUFFER_BIT Indicates the buffers currently enabled for color writing.
GL_DEPTH_BUFFER_BIT Indicates the depth buffer.
GL_STENCIL_BUFFER_BIT Indicates the stencil buffer.
The value to which each buffer is cleared depends on the setting of the clear value for that buffer.
2)glClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
glClearColor specifies the red, green, blue, and alpha values used by glClear to clear the color buffers. Values specified by glClearColor are clamped to the range [0,1].
3)glMatrixMode(GLenum mode)
学习OpenGL时,对矩阵的操作是核心。glMatrixMode告诉我们这个当前矩阵是什么矩阵。
4)glColor3f()
对颜色进行设定。OpenGl绘制图形形状时,并不绘制颜色,而是在绘制形状之前指定好颜色
5)glLoadIdentity()
恢复初始坐标系,重置当前指定的矩阵为单位矩阵。
6)glOrtho(left, right, bottom, top, near, far)
glOrtho(投影变换函数)创建一个正交平行的视景体,一般用于"物体不会因为离屏幕的远近而产生大小的变换"的情况。
OpenGL中有两个比较重要的投影变换函数,glViewport和glOrtho。
(2)演示投影变换函数对画出图形位置的影响:
1).示例1:
#include <GL/glut.h> void display(void)
{
glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0, 1.0, 0.0);
glBegin(GL_POLYGON);
glVertex3f(0.20, 0.20, 0.0);
glVertex3f(0.80, 0.20, 0.0);
glVertex3f(0.80, 0.80, 0.0);
glVertex3f(0.20, 0.80, 0.0);
glEnd(); glFlush();
} void init(void)
{
glClearColor(0.0, 1.0, 0.0, 0.0); glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
} int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(, );
glutInitWindowPosition(, );
glutCreateWindow("polyon");
init();
glutDisplayFunc(display);
glutMainLoop();
return ;
}
2).示例2:
#include <GL/glut.h> void display(void)
{
glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0, 1.0, 0.0);
glBegin(GL_POLYGON);
glVertex3f(-0.80, 0.80, 0.0);
glVertex3f(-0.80, -0.80, 0.0);
glVertex3f(0.80, -0.80, 0.0);
glVertex3f(0.80, 0.80, 0.0);
glEnd(); glFlush();
} void init(void)
{
glClearColor(0.0, 1.0, 0.0, 0.0); glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
} int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(, );
glutInitWindowPosition(, );
glutCreateWindow("polyon");
init();
glutDisplayFunc(display);
glutMainLoop();
return ;
}
3)结论:
代码中红色标志了他们的对应关系。
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0)函数实际上让当前窗体显示的区域对应到一个笛卡尔坐标系xy平面的矩形上(仅2D,所以只看前4个参数),原点是窗体显示区域的中心。
在第一个例子中的点仅存在于第一象限,因此虽然窗体包含有4个坐标系,它仅仅在第一个区域显示图形。在第二个例子中,4个点存在4个象限中,因此显示的矩形横跨4个象限。
而在开始的例子中,窗体的显示区域仅仅对应了第一象限。
(3)详细介绍:
1).在openGL中编程,经常用到glColor3f()函数进行颜色设定,现对参数与颜色的对应关系整理如下:
glColor3f(0.0, 0.0, 0.0); --> 黑色
glColor3f(1.0, 0.0, 0.0); --> 红色
glColor3f(0.0, 1.0, 0.0); --> 绿色
glColor3f(0.0, 0.0, 1.0); --> 蓝色
glColor3f(1.0, 1.0, 0.0); --> 黄色
glColor3f(1.0, 0.0, 1.0); --> 品红色
glColor3f(0.0, 1.0, 1.0); --> 青色
glColor3f(1.0, 1.0, 1.0); --> 白色
2).void glMatrixMode(GLenum mode)
mode告诉计算机将什么矩阵设置为当前矩阵,可选值有: GL_MODELVIEW、GL_PROJECTION、GL_TEXTURE。
GL_MODELVIEW: 应用这个参数后,表示接下来的矩阵操作都是针对模型视景矩阵堆栈 。 直到下一次调用这个函数并更改参数为止。
GL_PROJECTION:应用这个参数后,表示接下来的矩阵操作都是针对投影矩阵堆栈 。 直到下一次调用这个函数并更改参数为止。
GL_TEXTURE : 应用这个参数后,表示接下来的矩阵操作都是针对纹理矩阵堆栈 。 直到下一次调用这个函数并更改参数为止。
由于对不同的矩阵有不同的操作,置了当前的矩阵后,我们接下来所调用的所有openGL库函数的功能必须确定是针对我们设定的这个当前矩阵的,不能张冠李戴。
glMatrixMode(GL_MODELVIEW );//设置当前矩阵为模型视景矩阵
gluPerspective(45.0f,(GLfloat)cx/(GLfloat)cy,0.1f,100.0f);//对图像进行透视投影,以将三维物体显示在二维平面上
这样调用是错误的,结果将没有图像显示。这是因为,我们设置了当前矩阵为模型视景矩阵,而gluPerspective()是要对投影矩阵进行操作,那么计算机就会把模型矩阵当做投影矩阵,来与 gluPerspective()指定的矩阵进行乘法运算,最终就会导致错误。
3).void glLoadIdentity(void)(http://blog.sina.com.cn/s/blog_957b9fdb0100zez9.html)
glLoadIdentity是非常简单的恢复初始坐标系的手段,用一个4×4的单位矩阵来替换当前矩阵。
当您调用glLoadIdentity()之后,您实际上将当前点移到了屏幕中心:类似于一个复位操作
.X坐标轴从左至右,Y坐标轴从下至上,Z坐标轴从里至外。
.OpenGL屏幕中心的坐标值是X和Y轴上的0.0f点。
.中心左面的坐标值是负值,右面是正值。移向屏幕顶端是正值,移向屏幕底端是负值。移入屏幕深处是负值,移出屏幕则是正值。
由于某些原因可能使得当前矩阵中的元素有一些不确定的值,这将导致程序对图形对象进行几何变形时得到一个非预期的结果。因此有必要将当前矩阵初始成一个单位矩阵,即对图形对象不做任何变换。这就是为什么在调用过glMatrixMode()命令后,总是要调用该命令的原因。
用单位矩阵替换当前矩阵并不改变当前矩阵模式。
4).glOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far)
创建一个平行视景体(就是一个长方体空间区域,也相当于对立体空间进行3D裁剪)。这种投影意味着离观察者较远的对象看上去不会变小(与透视投影相反)。实际上这个函数的操作是创建一个正射投影矩阵,并且用这个矩阵乘以当前矩阵。
六个参数, 前两个是x轴最小坐标和最大坐标,中间两个是y轴,最后两个是z轴值。其中近裁剪平面是一个矩形,矩形左下角点三维空间坐标是(left,bottom,-near),右上角点是(right,top,-near);远裁剪平面也是一个矩形,左下角点空间坐标是(left,bottom,-far),右上角点是(right,top,-far)。
注意,所有的near和far值同时为正或同时为负, 值不能相同。如果没有其他变换,正射投影的方向平行于Z轴,且视点朝向Z负轴。这意味着物体在视点前面时far和near都为负值,物体在视点后面时far和near都为正值。只有在视景体里的物体才能显示出来。如果最后两个值是(0,0),也就是near和far值相同了,视景体深度没有了,整个视景体都被压成个平面了,就会显示不正确。
5).glBegin()和glEnd()
绘制图像的开始或结束的标志。
它们之间可以执行的函数:
glVertex*() 设置顶点坐标
glColor*() 设置当前颜色
glIndex*() 设置当前颜色表
glNormal*() 设置法向坐标
glCoord*() 产生坐标
glCallList(),glCallLists() 执行显示列表
glTexCoord*() 设置纹理坐标
glEdgeFlag*() 控制边界绘制
glMaterial*() 设置材质
可以绘制的图形的类型:
GL_POINTS 单个顶点集
GL_LINES 多组双顶点线段
GL_POLYGON 单个简单填充凸多边形
GL_TRAINGLES 多组独立填充三角形
GL_QUADS 多组独立填充四边形
GL_LINE_STRIP 不闭合折线
GL_LINE_LOOP 闭合折线
GL_TRAINGLE_STRIP 线型连续填充三角形串
GL_TRAINGLE_FAN 扇形连续填充三角形串
GL_QUAD_STRIP 连续填充四边形串
6)3D编程的基础知识:
1、 渲染:对一个三维物体进行几何描述,并且把它转换为屏幕上的一幅图像,这个过程就叫渲染。
、 纹理贴图:通过一副图像向一个多边形提供额外细节的技巧称为纹理贴图。我们所提供的图像称为纹理,纹理中每个单独的元素称为纹理单元(或纹理像素,texel)。
、 过滤(filtering):在一个物体的表面上拉伸或压缩纹理单元(纹理像素)的过程称为过滤。
、 混合(blending):指屏幕上颜色或物体的组合。混合可以用于多种目的,如制作透明效果、反射效果等。
、 裁剪区域:窗口(即屏幕)是以像素为单位进行度量的。裁剪区域指的是占据窗口的笛卡尔坐标空间中的区域。也可以解释为填充窗口的笛卡尔坐标空间中的区域。注意,裁剪区域使用的是笛卡尔坐标系统。
、 视口:因为裁剪区域的宽度和高度很少正好与窗口的宽度和高度(以像素为单位)相匹配,所以需要把坐标系统从逻辑笛卡尔坐标空间映射到物理屏幕像素坐标空间。视口就是窗口中用于绘制裁剪区域的客户区域。这里,要注意窗口与视口的区别,视口在窗口中指定,我们可以使用视口来缩小或者放大窗口中的图像。//类似4所说的东西
7. 管线:它用于描述一种过程,该过程可能涉及两个或更多个独特的阶段或步骤。
8、 OpenGL命令缓冲区:当应用程序进行OpenGL API函数调用时,这些命令被放置在一个命令缓冲区中。最终,这个缓冲区中会填满API 调用命令、顶点数据、纹理数据之类的东西。当缓冲区被刷新时,命令和数据就会被传递给管线的下一个阶段。
9、 变换和光照(T&L):这是一个数学计算密集型的阶段。在变换阶段,描述物体几何形状的顶点被重新计算(经历多次不同坐标空间的变换),以确定这个物体的位置和朝向。同时进行的光照计算阶段(世界坐标空间中)将确定每个顶点该具有的颜色和亮度。
10、 光栅化:该阶段根据几何图形、颜色和纹理数据实际创建彩色图像。然后,图像被放入到帧缓冲区之中。
11、 帧缓冲区:即图形显示设备的内存。图像放入到帧缓冲区意味着将会在屏幕上显示(刷新帧缓冲区时)。
(4)绘制不同图形的实例:
#include <GL/glut.h>
#include <math.h>
const int n = ;
const GLfloat R = 0.40f;
const GLfloat Pi = 3.1415926536f;
const GLfloat factor = 0.1f; void paint(void)
{ //在下半部分画一个正弦图像,上半部分画一个圆和一个五角形
glClear(GL_COLOR_BUFFER_BIT); //1.圆形
int i;
glColor3f(1.0,0.0,0.0);//红色的圆
glBegin(GL_POLYGON);//有顶点就必须要有glBegin() glEnd();
for(i=; i<n; ++i)
glVertex2f(R*cos(*Pi/n*i)-0.50f, R*sin(*Pi/n*i)+0.5f);//将圆形的中点向左上方平移
glEnd();
glFlush(); //2.五角形
glColor3f(0.0f,0.0f,0.0f);//黑色的五角形
GLfloat a = / ( - * cos( * Pi / ));
GLfloat bx = a * cos( * Pi / );
GLfloat by = a * sin( * Pi / );
GLfloat cy = -a * cos( * Pi / );
GLfloat
PointA[] = { +0.50, a+0.50 },
PointB[] = { bx+0.5, by+0.50 },
PointC[] = { 0.25+0.50, cy+0.50 },
PointD[] = { -0.25+0.50, cy+0.50 },
PointE[] = { -bx+0.50, by+0.50 }; //将整体向右上方平移
// 按照A->C->E->B->D->A的顺序,将五角星画出
glBegin(GL_LINE_LOOP);//闭合折线
glVertex2fv(PointA);
glVertex2fv(PointC);
glVertex2fv(PointE);
glVertex2fv(PointB);
glVertex2fv(PointD);
glEnd();
glFlush(); //3.正弦图像:
//黑色的正弦图像
GLfloat x;
glBegin(GL_LINE_STRIP);
for(x=-1.0f/factor; x<1.0f/factor; x+=0.01f)
{
glVertex2f(x*factor, sin(x)*factor-0.50);
}
glEnd();
glFlush(); //4.分割线:
glColor3f(0.5f,0.5f,0.0f);//黄色的分割线
glBegin(GL_LINES);
glVertex2f(-1.0f, 0.0f);
glVertex2f(1.0f, 0.0f); // 以上两个点可以画x轴
glVertex2f(0.0f, 0.0f);
glVertex2f(0.0f, 1.0f); // 以上两个点可以画y轴
glEnd();
glFlush();
} void init(void)
{
glClearColor(0.0,1.0,1.0,0.0);//设背景为青色
glMatrixMode(GL_PROJECTION);//创建投影矩阵堆栈
glLoadIdentity();//将当前矩阵设为单位矩阵,恢复初始坐标系
gluOrtho2D(-1.0f,1.0f,-1.0f,1.0f);//窗口左上角坐标(-1,1),右下角坐标(1,-1);
} int main(int argc,char *argv[])
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutInitWindowSize(,);
glutInitWindowPosition(3, 1);
glutCreateWindow("圆形五角形和正弦图像");
init();
glutDisplayFunc(paint);
glutMainLoop();
return ;
}
OpenGL学习进程(4)第二课:绘制图形的更多相关文章
- OpenGL学习进程(8)第六课:点、边和图形(三)绘制图形
本节是OpenGL学习的第六个课时,下面介绍OpenGL图形的相关知识: (1)多边形的概念: 多边形是由多条线段首尾相连而形成的闭合区域.OpenGL规定,一个多边形必须是一个“凸多边形”. ...
- OpenGL学习进程(10)第七课:四边形绘制与动画基础
本节是OpenGL学习的第七个课时,下面以四边形为例介绍绘制OpenGL动画的相关知识: (1)绘制几种不同的四边形: 1)四边形(GL_QUADS) OpenGL的GL_QUADS图 ...
- OpenGL学习进程(11)第八课:颜色绘制的详解
本节是OpenGL学习的第八个课时,下面将详细介绍OpenGL的颜色模式,颜色混合以及抗锯齿. (1)颜色模式: OpenGL支持两种颜色模式:一种是RGBA,一种是颜色索引模式. R ...
- OpenGL学习进程(7)第五课:点、边和图形(二)边
本节是OpenGL学习的第五个课时,下面介绍OpenGL边的相关知识: (1)边的概念: 数学上的直线没有宽度,但OpenGL的直线则是有宽度的.同时,OpenGL的直线必须是有限长度,而不是像数学概 ...
- OpenGL学习进程(6)第四课:点、边和图形(一)点
本节是OpenGL学习的第四个课时,下面介绍OpenGL点的相关知识: (1)点的概念: 数学上的点,只有位置,没有大小.但在计算机中,无论计算精度如何提高,始终不能表示一个无穷小的点 ...
- OpenGL学习进程(12)第九课:矩阵乘法实现3D变换
本节是OpenGL学习的第九个课时,下面将详细介绍OpenGL的多种3D变换和如何操作矩阵堆栈. (1)3D变换: OpenGL中绘制3D世界的空间变换包括:模型变换.视图变换.投影变换和视口 ...
- OpenGL学习进程(5)第三课:视口与裁剪区域
本节是OpenGL学习的第三个课时,下面介绍如何运用显示窗体的视口和裁剪区域: (1)知识点引入: 1)问题现象: 当在窗体中绘制图形后,拉伸窗体图形形状会发生变化: #include ...
- OpenGL学习进程(3)第一课:初始化窗体
本节是OpenGL学习的第一个课时,下面介绍如何初始化一个窗体: (1)显示一个有蓝色背景的窗体: #include <GL/glut.h> #include <st ...
- OpenGL学习进程(9)在3D空间的绘制实例
本节将演示在3D空间中绘制图形的几个简单实例: (1)在3D空间内绘制圆锥体: #include <GL/glut.h> #include <math.h> # ...
随机推荐
- Ubuntu vsftp复制文件到远端时错误,Permission denied
Ubuntu 下复制文件到远端时错误,Permission denied 失败原因如下: (1)vsftp默认配置不允许上传文件 解决办法:修改配置文件 vi /etc/vsftpd.conf. 将& ...
- 关于Python的Object继承
今天在Coding的使用,使用了python的单例模式,发现了一个很有趣的问题. class x(object): __se = None a = None def __new__(cls): if ...
- Android开发学习秘籍笔记(十九)
吼.花了2天最后做出了一个类似于蓝牙串口助手功能的小程序,事实上也是实习公司的要求---有一个蓝牙无线扫描枪,要求终端能够通过蓝牙连接到该设备,而且蓝牙无线扫描枪扫描二维码或者条形码的时候能够将二维码 ...
- cpu故障定位 top strace pstack
一次服务器CPU占用率高的定位分析 推荐 背景:通过性能监控发现上线服务器cpu某核占用率已经达到了100%,而且是由我们的某个核心服务导致的.幸亏由于我们的服务进程由多个相同worker(线程) ...
- 这是一篇markdown测试博客
欢迎使用Markdown编辑器写博客 本Markdown编辑器使用StackEdit修改而来,用它写博客,将会带来全新的体验哦: Markdown和扩展Markdown简洁的语法 代码块高亮 图片链接 ...
- php 远程调用redis
<?php $redis_conf = array ( "active_code"=>array( "host" => "14.29 ...
- Python urllib的urlretrieve()函数解析 (显示下载进度)
#!/usr/bin/python #encoding:utf-8 import urllib import os def Schedule(a,b,c): ''''' a:已经下载的数据块 b:数据 ...
- iOS - 逆向 - Objective-C代码混淆 -confuse.sh文件写法
class-dump可以很方便的导出程序头文件,不仅让攻击者了解了程序结构方便逆向,还让着急赶进度时写出的欠完善的程序给同行留下笑柄. 所以,我们迫切的希望混淆自己的代码. 混淆的常规思路 混淆分许多 ...
- 【BZOJ3073】[Pa2011]Journeys 线段树+堆优化Dijkstra
[BZOJ3073][Pa2011]Journeys Description Seter建造了一个很大的星球,他准备建造N个国家和无数双向道路.N个国家很快建造好了,用1..N编号,但是他发现道路实在 ...
- VS2010程序崩溃- APPCRASH
使用VS2010打开某个项目出现错误,程序崩溃:还不是全部的项目:开始以为是那个项目本身有什么问题,查了很久发现不是这样的 程序崩溃提示 问题签名: 问题事件名称: APPCRASH 应用程序名: d ...