第四章 输出图元

4.1坐标系统

  1. 坐标范围:描述对象x,y,z坐标的最大值最小值和一些其它信息
  2. 坐标范围也称为对象的包围盒
  3. 整个显示的简单流程:将场景信息传送给观察函数->观察函数识别可见面->将对象映射到射频监视器上来显示对象

4.1.1屏幕坐标

  1. 屏幕坐标一般以左上角为原点
  2. 视频监视器上的位置使用与帧缓存中的像素位置相对应的整数屏幕坐标进行描述(涉及到一个转换)
  3. 使用软件操作可以改变屏幕坐标的参考系统(例如以左下角为笛卡尔坐标系的原点)

4.1.2绝对和相对坐标描述 1.我们开始所谈论的坐标都是绝对坐标,也就是在坐标系统中的实际值 2.那什么是相对坐标呢?例如,位置(3,8)是刚刚程序引用的位置,那么相对坐标(2,-1)和绝对坐标(5,7)相对应(即两坐标相减)

4.2 OpenGL中指定二维直接坐标系统 1.gluOrth2D(xMin,xMax,yMin,yMax)这个函数是做什么的呢?首先这个函数会确定一个投影矩阵,这个正交投影矩阵的作用是确定显示的范围如下图所示:

正交投影矩阵.png 2.这里给的是世界坐标系统的绝对坐标

4.3 OpenGL画点函数

1.画点的函数为glVertex&(&表示有后缀码)这些后缀码用来知名空间维数,坐标值变量类型和向量形式坐标描述 2.OpenGL中的坐标位置有可能是二维三维或四维,这里的四维代表齐次坐标描述,其中的第四个参数是笛卡尔坐标的比例因子,此外在opengl中用四维坐标表示顶点,那么实际上的二维坐标表示就是(x,y,0,1) 3.同时我们需要指出坐标数值描述使用的数据类型,那么第二个后缀就可以达到这个效果,例如glVertex4f point(100.0,100.0.0,1),如果使用矩阵形式表达就需要这样做int point[] = {0,1},glVertex4iv point(point);

4.4 OpenGL画线函数

1.画线函数如下

glBegin(GL_LINE);
    glVertex2i(p1);
    glVertex2i(p2);
    glVertex2i(p3);
    glVertex2i(p4);
    glVertex2i(p5);
glEnd();

2.需要注意几点

1.当使用GL_LINE的时候生成的图像会按照两个的顺序生成直线,也就是直线a(p1,p2) 直线b(p3,p4)p5点会被忽略
2.当使用GL_LINE_STRIPE会获得折线,也就是点会按照顺序连接
3.当使用GL_LIE_LOOP的时候,会获得闭合曲线

4.5 OpenGL曲线函数

1.我们可以使用折线来近似的表示曲线、

4.6 填充区图元、

1.除了点和线之外,另外一种有用的描述图案组成部分的结构是使用某种颜色或图案进行填充的区域、 2.一般来说多数库函数要求填充区域为多边形,另外多数曲面可以用多边形面片来逼近

4.7.1 多边形分类

1.如果多边形内部的角都小于180°,那么这个多边形是凸多边形、 2.如果多边形内部的角都大于180°,那么这个多边形都是凹多边形

4.7.3 分割凹多边形、 1.首先我们怎么判断一个多边形是凹多边形还是凸多边形,这就涉及到向量的叉积。 2.AXB=|A|*|B|sinα,那么这里也能知道了,当角度>180的时候,叉积为负数。 3.切割的时候就沿着第一条叉积为负的线延伸到与多边形的第一个交点,那么我们就分割成功了。 4.还有一种旋转的方法,按顺序将点Kn放到原点,再将Kn+1放到x轴上,如果Kn+2在x轴下方,那么为凹多边形,切割的方式就是按x轴切割

4.7.4 将凸多边形分割成三角形集 1.连续三个点划分为一个三角形,然后将中间的点从顶点数据集中去除,一直到只剩下三个点,如下图所示

凹多边形分割为三角形.png 2.操作如下,第一个三角形abc会将b点去除,第二个三角形cde会将d点去除,最后剩下的三个点ace构成最后一个三角形,那么这就拆分完成了

4.7.5 内-外测试 1.判断区域是否在多边形内部?第一个方法就是奇偶规则,规则如下,在这个区域内做射线到区域外,如果交点为偶数则在多边形外部,如果交点为奇数,则在多边形内部。 2.第二种方法,非零环绕数规则,如下图演示:

非零环绕数规则.png 可以看到我们发出一条射线从p点,首先一第一条边相交的顺序是逆时针,那么环绕数+1,与第二条边相交是顺时针,那么环绕数-1,最后环绕数为0,这个时候就确定了,p所在的区域为外部,如果环绕数不为零,那么区域就在多边形内部

4.7.6 多边形表

多边形表.png

顶点表             边表         面片表

V1:X1,Y1,Z1;      E1:V1,V2     S1:E1,E2,E3
V2:X2,Y2,Z2;      E2:V2,V3     S2:E3,E4,E5,E6
V3:X3,Y3,Z3;      E3:V3,V1
V4:X4,Y4,Z4;      E4:V3,V4
V5:X5,Y5,Z5;      E5:V4,V5
                  E6:V5,V1

4.7.8 前向面与后向面 1.向着对象内部的面称为后向面,外部可见或朝外的一面称为外向面 2.这种说法只对三维空间生效也就是Ax+By+Cz+D=0 3.如果Ax+By+Cz+D<0 那么这个点在内部,如果Ax+By+Cz+D>0,那么在外部 4.多边形表面的空间方向可以用其所在平面的法向量表示,举个例子x-1=0平面,法向量为(1,0,0), 5.怎么计算平面的A,B,C,D参数呢?首先取平面的两个向量叉积获得法向量,那么就获得了A,B,C,对于D,用法向量点积平面上任意一个点为-D,也就是N·P=-D

4.8 OpenGl多边形填充区函数 1.有更方便的函数来描述多边形,比如glRect&(&填充后缀)

int leftTop[]={50,250};
int rightBottom[]={200,100};
glRectiv rect(rightBottom,leftTop);

2.类型GL_TRIANGLES 按顺序取三个点生成三角形 GL_POLYGON生成单个填充凸边形,GL_STRIP生成相连的三角形,GL_TRIANGLE_FAN生成以第一个点为共同点的相连的三角形,当然对于四边形也是一样的,GL_QUADS按顺序取四个点生成四边形,GL_QUAD_STRIP生成相连的四边形。

3 OpenGL顶点数组

#include "glut.h"
#include <iostream>
//一个点三个int
typedef  int(Point)[3];
// 八个点
Point QUAD[8] = { {0,0,0},{0,1,0},{1,0,0},{1,1,0},{0,0,1},{0,1,1},{1,0,1},{1,1,1} };
GLubyte index[24] = { 6,2,3,7,5,1,0,4,7,3,1,5,4,0,2,6,2,0,1,3,7,5,4,6 };
void MyQuad() {
	glClear(GL_COLOR_BUFFER_BIT);
	glColor3f(1.0, 0.0, 0.0);
	glEnableClientState(GL_VERTEX_ARRAY);
	glVertexPointer(3, GL_INT, 0, QUAD);
	glDrawElements(GL_QUADS, 24, GL_UNSIGNED_BYTE, index);
	glBegin(GL_LINES);
	glVertex2i(50, 100);
	glVertex2i(50, 200);
	glEnd();
	glFlush();
	auto code = glGetError();
	if (code != GL_NO_ERROR) {
		std::cout << gluErrorString(code) << std::endl;
	}
}
void main(int argc, char* argv[]) {
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
	glutInitWindowPosition(0, 0);
	glutInitWindowSize(400, 400);
	glutCreateWindow("test");
	glClearColor(1.0, 1.0, 1.0, 0.0);
	glMatrixMode(GL_PROJECTION);
	gluOrtho2D(-1, 1, -1, 1);
	glutDisplayFunc(MyQuad);
	glutMainLoop();
}

注意:正交投影矩阵针对的是世界坐标,而不是屏幕坐标。

4.10 像素阵列图元

注意:用于帧缓存 1.矩形的网格图案可以通过数字化一张图片或其他图形来获得,也可以使用图形程序来生成。列阵中每一颜色值映射到一个或多个屏幕像素位置 2.像素列阵的参数包括指向颜色矩阵的指针,矩阵的大小即将要影响的屏幕区域 3.实现像素矩阵的另一种方法是为矩阵中的每一个元素赋值为0或1,此时列阵简化为位图,也称为掩膜,它指出一个像素是否被赋予预定颜色

4.11.1 OpenGL位图函数

1.glbitmap(width,height,x0,y0,xoffset,yoffset,bitshape) 2.解释参数,width,height指出列阵bitshape的列数和行数,x0和y0指定矩形列阵的原点,原点指定为bitshape的左下角,bitshape每一元素赋值为1,表示对应像素用前面设定的颜色显示 3.当前光栅位置指帧缓存中应用图案的位置 4.xoffset和yoffset的值用作位图显示后更新帧缓存当前光栅位置的坐标位移 5.glRasterPos&(),这个函数指定当前光栅位置,&是个后缀,和glVertex一样,当前光栅位置在世界坐标中给出

4.11.2 OpenGl的像素图函数

注意:用于帧缓存 1.glDrawPixels(width,height,dataFormat,dataType,pixMap) 2.参数解析:width/height指出像素位图的列数和行数,dataFormat用一个OpenGL常量值,指定像素的颜色,dataType指定颜色的数据类型 3.由于opengl中有若干缓存,将某缓存选为glDrawPixels就可以将该位图送入缓存 4.OpenGL中有四个颜色缓存用于屏幕刷新,后面将详细考察

4.11.3 OpenGL光栅操作 1.术语光栅操作用于描述以某种方式处理一个像素列阵的任何功能。 2.将一个像素列阵的值从一个位置移动到另一个位置的光栅操作也称为像素值的块移动 3.可以使用glReadPixels(xmin,ymin,width,height,dataFormat,dataType,array)从指定缓存中选择一个矩形块的像素值 4.参数分析:xmin,ymin在屏幕坐标中选择,也是矩形的左下角,width/height指定矩形的长宽,dataFormat来选择缓存类型,例如GL_DEPTH_COMPONENT或GL_STENCIL_INDEX来选择深度缓存或模板缓存 5.使用glCopyPixles(xmin,ymin,width,height,piexlValues); 6.参数解析:块的左下角是屏幕坐标位置(xmin,ymin),width和height分别被指定为要复制的行数和列数,参数pixelValue被赋以GL_COLOR,GL_DEPTH或GL_STENCIL来指定要复制的数据种类,颜色值,深度值或模板值 7.可以使用glReadBuffer来选择源缓存,glDrawBuffer来选择目标缓存 8,这两个提供和接受复制的区域必须都在屏幕坐标内