OpenGL学习进程(6)第四课:点、边和图形(一)点
本节是OpenGL学习的第四个课时,下面介绍OpenGL点的相关知识:
(1)点的概念:
数学上的点,只有位置,没有大小。但在计算机中,无论计算精度如何提高,始终不能表示一个无穷小的点。一般情况下,OpenGL中的点将被画成单个的像素,虽然它可能足够小,但并不会是无穷小。同一像素上,OpenGL可以绘制许多坐标只有稍微不同的点,但该像素的具体颜色将取决于OpenGL的实现。
点是OpenGL中绘制一切的基础。
(2)如何绘制点:
1)OpenGL为点的绘制提供了一系列函数:
glVertex2d
glVertex2f
glVertex3f
glVertex3fv
//数字表示参数的个数,字母表示参数的类型:
s:表示16位整数(OpenGL中将这个类型定义为GLshort),
i:表示32位整数(OpenGL中将这个类型定义为GLint和GLsizei),
f:表示32位浮点数(OpenGL中将这个类型定义为GLfloat和GLclampf),
d:表示64位浮点数(OpenGL中将这个类型定义为GLdouble和GLclampd)。
v:表示传递的几个参数将使用指针的方式。
//OpenGL的很多函数都是采用这样的形式,一个相同的前缀再加上参数说明标记。同时用glVertex*来表示这一系列函数。
上面这些函数虽然函数名和参数都不相同,但功能都类似:
//下面5段代码是等效的:
(一)glVertex2i(, );
(二)glVertex2f(1.0f, 3.0f);
(三)glVertex3f(1.0f, 3.0f, 0.0f);
(四)glVertex4f(1.0f, 3.0f, 0.0f, 1.0f);
(五)GLfloat VertexArr3[] = {1.0f, 3.0f, 0.0f};glVertex3fv(VertexArr3);
2)绘制不同大小的点:
点的大小默认为1个像素,也可以用glPointSize()函数改变:
#include <GL/glut.h>
#pragma comment( linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"") void paint(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(,,,);
glViewport(, , , ); glViewport(, , , );
glPointSize(10.0f); glColor3f(,,);
glBegin(GL_POINTS);
glVertex2f(0.0f,0.0f);
glEnd(); glViewport(, , , );
glPointSize(20.0f); glColor3f(, , );
glBegin(GL_POINTS);
glVertex2f(0.0f, 0.0f);
glEnd(); glViewport(, , , );
glPointSize(30.0f); glColor3f(, , );
glBegin(GL_POINTS);
glVertex2f(0.0f, 0.0f);
glEnd(); glViewport(, , , );
glPointSize(40.0f); glColor3f(, , );
glBegin(GL_POINTS);
glVertex2f(0.0f, 0.0f);
glEnd(); glFlush();
} int main(int argc,char ** argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutInitWindowSize(,);
glutInitWindowPosition(,);
glutCreateWindow("绘制不同大小的点");
glutDisplayFunc(paint);
glutMainLoop();
return ;
}
需要注意的点:
1:给所画图形指定颜色,用glColor3b()不能达到效果,要用glColor3f();
2.glVertex(float x,float y)中x,y为百分比。范围均为(-1,1)表示当前区域位置。(0,0)表示中点,(1,1)表示右上角。
3.glViewport()函数的后两个参数表示区域的宽度和高度,不代表坐标值。
4.在画图完毕不要忘了glFlush();
(3)3D空间中点的动态绘制及动态查看:
#include <GL/glut.h>
#include <math.h>
#pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"") #define GL_PI 3.1416f
// 定义旋转角度,在按键控制中使用
static GLfloat xRot = 0.0f;
static GLfloat yRot = 0.0f; // 设置渲染状态
void SetupRC()
{
glClearColor(0.4f, 0.4f, 0.4f, 1.0f);
glColor3f(0.0f, 1.0f, 1.0f);
} // 绘制场景(显示回调函数)
void RenderScene()
{
//存储坐标和角度
GLfloat x, y, z, angle;
glClear(GL_COLOR_BUFFER_BIT); // 保存矩阵状态并旋转
glPushMatrix();
glRotatef(xRot, 1.0f, 0.0f, 0.0f);//绕x轴旋转
glRotatef(yRot, 0.0f, 1.0f, 0.0f);//绕y轴旋转
// 开始绘制顶点图元
glBegin(GL_POINTS);
// 设置Z轴的起始位置
z = -50.0f;
for (angle = 0.0f; angle <= (2.0f * GL_PI * 3.0f); angle += 0.1f) {
//计算X、Y坐标
x = 50.0f * sin(angle);//相当于在xy平面画正弦图像,并且在z轴上有纵深变化。
y = 50.0f * cos(angle);
//指定顶点位置
glVertex3f(x, y, z);
//对Z坐标值稍作修改,在下一个顶点使用
z += 0.5f;
}
glEnd();
// 恢复矩阵状态
glPopMatrix();
// 刷新绘图命令,此时所有未执行的OpenGL命令被执行
glutSwapBuffers();
} // 当窗口大小改变时由GLUT函数库调用
void ChangeSize(GLsizei w, GLsizei h)
{
// 范围
GLfloat nRange = 100.0f;
// 纵横比
GLfloat aspectRatio;
// 防止被0所除
if ( == h){
h = ;
}
// 根据窗口大小设置视口
glViewport(, , w, h);
// 选择投影矩阵,并重置坐标系统
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// 计算窗口的纵横比(像素比)
aspectRatio = (GLfloat)w / (GLfloat)h;
// 定义裁剪区域(根据窗口的纵横比,并使用正投影)
if (w <= h) {//宽 < 高
glOrtho(-nRange, nRange, -nRange / aspectRatio, nRange / aspectRatio, -nRange, nRange);
}
else {//宽 > 高
glOrtho(-nRange * aspectRatio, nRange *aspectRatio, -nRange, nRange, -nRange, nRange);
}
// 选择模型视图矩阵,并重置坐标系统
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
} // 按键响应函数
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();
} int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(, );
glutCreateWindow("3D空间中点的绘制与查看");
// 设置显示回调函数
glutDisplayFunc(RenderScene);
// 设置当窗口的大小发生变化时的回调函数
glutReshapeFunc(ChangeSize);
// 设置按键响应函数(特殊键)
glutSpecialFunc(SpecialKeys);
// 设置渲染状态
SetupRC();
// 启动GLUT框架的运行,一经调用便不再返回,直到程序终止
glutMainLoop(); return ;
}
1)代码解释:
1.void glutSpecialFunc(void (*func)(int key, int x, int y));
glutSpecialFunc sets the special keyboard callback for the current window.The special keyboard callback is triggered when keyboard function or directional keys are pressed. The key callback parameter is a GLUT_KEY_* constant for the special key pressed. The x and y callback parameters indicate the mouse in window relative coordinates when the key was pressed. When a new window is created, no special callback is initially registered and special key strokes in the window are ignored. Passing NULL to glutSpecialFunc disables the generation of special callbacks.
During a special callback, glutGetModifiers may be called to determine the state of modifier keys when the keystroke generating the callback occurred. An implementation should do its best to provide ways to generate all the GLUT_KEY_* special keys.
The available GLUT_KEY_* values are:
GLUT_KEY_F1:F1 function key.
GLUT_KEY_F2:F2 function key.
......
GLUT_KEY_F12:F12 function key.
GLUT_KEY_LEFT:Left directional key.
GLUT_KEY_UP:Up directional key.
GLUT_KEY_RIGHT:Right directional key.
GLUT_KEY_DOWN:Down directional key.
GLUT_KEY_PAGE_UP:Page up directional key.
GLUT_KEY_PAGE_DOWN:Page down directional key.
GLUT_KEY_HOME:Home directional key.
GLUT_KEY_END:End directional key.
GLUT_KEY_INSERT:Inset directional key.
Note that the escape, backspace, and delete keys are generated as an ASCII character.
设置当前窗口的特定键的回调函数。x,y:当按下键时鼠标的坐标,相对于窗口左上角,以像素为单位。
注意:ESC,回车和delete键由ASCII码产生,即可以用glutKeyboardFunc()处理. 当在键盘上敲击上述按键时调用该函数.注意与glutKeyboardFunc()的区别。
2.自定义键盘监听函数(注册)
一个经常的用法是当按下ESCAPE键时退出应用程序。
注意,我们提到过,glutMainLoop函数产生的是一个永无止境的循环。唯一的跳出循环的方法就是调用系统exit函数。这就是我们函数要做的,当按下ESCAPE键调用exit函数终止应用程序(同时要记住在源代码包含头文件stdlib.h)。下面就是这个函数的代码:
void processNormalKeys(unsigned char key,int x,int y)
{
if(key==)
Exit();
}
我们还可以控制特殊键的按键消息:
//当在绘图中动态指定绘图颜色时:
void processSpecialKeys(int key, int x, int y) {
switch(key) {
case GLUT_KEY_F1 :
red = 1.0;
green = 0.0;
blue = 0.0; break;
case GLUT_KEY_F2 :
red = 0.0;
green = 1.0;
blue = 0.0; break;
case GLUT_KEY_F3 :
red = 0.0;
green = 0.0;
blue = 1.0; break;
}
}
3.glPushMatrix()、glPopMatrix()
相当于栈里的入栈和出栈。glPushMatrix其实就是把当前状态做一个副本放入堆栈之中;glPopMatrix()从栈中取出一个副本,恢复成副本的状态。
glLoadIdentity();
glTranslatef(,,);//向右移动(1,0,0)
glPushMatrix();//保存当前位置
glTranslatef(,,);//现在是(1,1,0)了
glPopMatrix();//这样,现在又回到(1,0,0)了
4.void glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z)
模型变换函数中的旋转。angle表示旋转的角度(注意单位不是弧度),(x,y,z)表示转轴。
glRotatef(45.0, 0.0, 0.0, 1.0);//表示模型沿着(0,0,1)这个轴旋转45°。
5.glFlush和glutSwapBuffers[void glFlush(void void);void glutSwapBuffers(void)]
glFlush 是强制马上输出命令执行的结果,而不是存储在缓冲区中,继续等待其他OpenGL命令。
当执行双缓冲交换的时候,使用glutSwapBuffers。但是在有 glutSwapBuffers 的情况下,不需要 glFlush 就可以达到同样的效果,因为我们执行双缓冲交换的时候,就隐形的执行了一次刷新操作。
6.void glutPostRedisplay(void)与Void glutIdleFunc(void(*f)(void))
glutIdleFunc()空闲回调函数标识了这样一个函数:当事件队列中没有事件需要处理时(即事件队列为空时),它才有机会得到执行。
这两个函数经常这样用:
glutIdleFunc(myidle);
void myidle()
{
glutPostRedisplay();
}
glutPostRedisplay标记当前窗口需要重新绘制。通过glutMainLoop下一次循环时,窗口显示将被回调以重新显示窗口的正常面板。多次调用glutPostRedisplay,在下一个显示回调只产生单一的重新显示回调。
2)相关知识:
1.双缓冲技术:
glutSwapBuffers函数是OpenGL中GLUT工具包中用于实现双缓冲技术的一个重要函数。该函数的功能是交换两个缓冲区指针。当我们进行复杂的绘图操作时,画面便可能有明显的闪烁。解决这个问题的关键在于使绘制的东西同时出现在屏幕上。
双缓冲技术,是指使用两个缓冲区: 前台缓冲和后台缓冲。前台缓冲即我们看到的屏幕,后台缓冲则在内存当中,对我们来说是不可见的。每次的所有绘图操作都在后台缓冲中进行,当绘制完成时, 把绘制的最终结果复制到屏幕上,这样,我们看到所有GDI元素同时出现在屏幕上,从而解决了频繁刷新导致的画面闪烁问题。
在OpenGL中实现双缓冲技术的一种简单方法:
.在调用glutInitDisplayMode函数时, 开启GLUT_DOUBLE,即glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);。这里将我们惯用的GLUT_SINGLE替换为GLUT_DOUBLE,意为要使用双缓冲而非单缓冲。
. 调用glutDisplayFunc(display)注册回调函数时, 在回调函数中所有绘制操作完成后调用glutSwapBuffers()交换两个缓冲区指针。
. 调用glutIdleFunc注册一个空闲时绘制操作函数, 注册的这个函数再调用display函数。
2.单一的重新显示回调:
glutPostRedisplay()所执行的功能类似于直接调用显示回调函数display(),但该函数允许实现在对何时真正需要调用显示回调函数而作出决策时,变得更加“智能化”。
在GLUT遍历整个事件循环时,必然会检索到许多要求窗口重绘的事件。如果每次都去直接调用显示回调函数,窗口必然会被多次绘制。而使用glutPostRedisplay()之后,就使得在遍历消息队列的整个过程中,只对窗口重绘一次。
(4)绘制正弦线上的点:并改变点的大小:
#include <GL/glut.h>
#include <math.h>
#pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"") #define GL_PI 3.1416f
const GLfloat factor = 0.1f; void SetupRC(void)
{
glClearColor(0.5f, 0.5f, 0.5f, 0.5f);
}
void paint(void)
{
GLfloat x;
glColor3f(1.0f, 1.0f, 1.0f);
glPointSize(4.0f);//应在glBegin之前
glBegin(GL_POINTS);
for (x = -; x<; x += 0.1)
{
glVertex2f(x*factor, sin(x)*factor*);
}
glEnd();
glColor3f(1.0f, 0.0f, 0.0f);
glBegin(GL_LINES);
glVertex2f(-1.0f, 0.0f);
glVertex2f(1.0f, 0.0f);
glVertex2f(0.0f, -1.0f);
glVertex2f(0.0f, 1.0f);
glEnd();
glFlush();
} int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);//当没有键盘监听时不需要用双缓冲模式
glutInitWindowSize(, );
glutCreateWindow("正弦点图");
glutDisplayFunc(paint);
SetupRC();
glutMainLoop(); return ;
}
OpenGL学习进程(6)第四课:点、边和图形(一)点的更多相关文章
- OpenGL学习之路(四)
1 引子 上次读书笔记主要是学习了应用三维坐标变换矩阵对二维的图形进行变换,并附带介绍了GLSL语言的编译.链接相关的知识,之后介绍了GLSL中变量的修饰符,着重介绍了uniform修饰符,来向着色器 ...
- OpenGL学习进程(11)第八课:颜色绘制的详解
本节是OpenGL学习的第八个课时,下面将详细介绍OpenGL的颜色模式,颜色混合以及抗锯齿. (1)颜色模式: OpenGL支持两种颜色模式:一种是RGBA,一种是颜色索引模式. R ...
- OpenGL学习进程(10)第七课:四边形绘制与动画基础
本节是OpenGL学习的第七个课时,下面以四边形为例介绍绘制OpenGL动画的相关知识: (1)绘制几种不同的四边形: 1)四边形(GL_QUADS) OpenGL的GL_QUADS图 ...
- 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学习进程(8)第六课:点、边和图形(三)绘制图形
本节是OpenGL学习的第六个课时,下面介绍OpenGL图形的相关知识: (1)多边形的概念: 多边形是由多条线段首尾相连而形成的闭合区域.OpenGL规定,一个多边形必须是一个“凸多边形”. ...
- OpenGL学习进程(7)第五课:点、边和图形(二)边
本节是OpenGL学习的第五个课时,下面介绍OpenGL边的相关知识: (1)边的概念: 数学上的直线没有宽度,但OpenGL的直线则是有宽度的.同时,OpenGL的直线必须是有限长度,而不是像数学概 ...
- OpenGL学习进程(4)第二课:绘制图形
本节是OpenGL学习的第二个课时,下面介绍如何用点和线来绘制图形: (1)用点的坐标来绘制矩形: #include <GL/glut.h> void display(void) ...
随机推荐
- MySQL同步状态双Yes的假象及 seconds_behind_master的含义
MySQL同步状态双Yes的假象及seconds_behind_master的含义 近期由于特殊原因有一台主库宕机了一个小时没有处理,说起来这是个挺不好啥意思的事情,但是由于这个事情反而发现个比较 ...
- 【Mac系统 + Python + Django】之开发一个发布会系统【Django模型(三)】
上一部分给大家介绍Django的视图. 接下来继续来了解Django框架,来看第三部分,此部分是对数据库的操作. 目录: 一.设计系统表 二.admin后台管理 三.基本数据访问(SQLite数据库) ...
- repaint和reflow的相关知识
一个页面由两部分组成: DOM:描述该页面的结构 render渲染:描述 DOM 节点 (nodes) 在页面上如何呈现 repaint重绘: 当 DOM 元素的属性发生变化 (如 color) 时, ...
- bat脚本批处理打war打包
@echo =========================================== @echo 描述:打包脚本 @echo 作者:霍建国 @echo 日期:2018-03-13 @ec ...
- java 获取网页指定内容
import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.HttpURLConnection; ...
- xxxxxxclub系统模块分类
不是分析整个程序执行的过程. 分析程序在设计的时候模块怎样分类 针对的是应用程序,name 类的装载:1. Spring配置 基于接口调用hsf 3. 一个页面相应的java类 Spring的xml文 ...
- Android无线测试之—UiAutomator UiDevice API介绍七
截图与等待空闲 一.截图和等待空闲相关知识: 1)图片缩放比例:例如图片从100像素缩小到50像素 2)图片质量:是指图片大小,质量越高图片越大,质量越低图片越小 3)File类:指的是一个文件或者一 ...
- Java之美[从菜鸟到高手演变]之字符串
一.String 1.String简介 初始化: 一般由String声明的字符串,长度是不可变的,这也是它与StringBuffer和StringBuilder最直观的一个区别.一般初始化方式:Str ...
- EasyNVR摄像机无插件直播按需RTSP拉流播放流程详解
1.背景需求 有许多客户现场,有许多设备但是不需要一直向设备端取视频流,因为在用户不观看的情况下,还在获取视频资源,一方面大大的浪费了网络带宽资源,一方面对设备服务器要求也较高,用户成本就要提高,这是 ...
- Java的四种引用,强弱软虚,用到的场景
众所周知,java中是JVM负责内存的分配和回收,这是它的优点(使用方便,程序不用再像使用c那样操心内存),但同时也是它的缺点(不够灵活).为了解决内存操作不灵活这个问题,可以采用软引用等方法. 在J ...