从零开始构建计算机系统——二维图形库(直线)

来源:互联网 发布:wp8软件下载 编辑:程序博客网 时间:2024/06/16 18:50

一、显示原理

通常显示屏的的图像显示都是通过一个一个的像素点来实现的,也就是说将一幅图像切割成非常小的一个立方块,如下图所示,要在显示屏上显示一个字母“A”,首先将字母的笔画路径切割成一个小块,并以黑色显示。



对于液晶屏来说,就是通过控制电场实现液晶的偏转,从而使光线不能通过,因此显示就为黑色。对于彩色屏幕来说,就是在这之上多加了RGB滤光片,并以三个RGB小方块合并成为一个彩色像素点。通过调整RGB各通道上的明亮程度(也就是控制液晶偏转程度)来合成最终的彩色。对于三维图形的绘制来说,主要是通过色彩的明暗程度来实现三维视觉效果,基本流程是:计算顶点并缓存到内存中,进行顶点着色,进行片元着色,这里的片源就是最小的彩色图元,也是实现三维视觉效果的关键。

上图中左边叫做“Bitmap”位图,右边叫做“Vector”矢量图,矢量图的优点在于图像放大之后依然非常清晰,它保存的是图片的路径,缺点在于绘制过程的计算量比较大。位图中保存的是平面中的各像素点,在绘制过程中直接就可以输出给屏幕显示,也就是说和屏幕上的一个个点阵是对应起来的,因此计算量基本上没有。当然在图片放大缩小的过程中,需要对图像进行重新采样和计算,矢量图形可直接根据路径进行计算。下图展示的是位图和矢量图在放大的后区别:

我们经常听到“显存”这个词语,其实就是显示卡内存的简称。下面我们就说说显示屏和内存的关系。显示屏工作需要显示卡来进行驱动,显示屏上一个个像素点都是由相应的逻辑门来控制,采用行扫描和列扫描的方式可以减少控制像素点的逻辑控制线,由于人眼有视觉暂留的特点,因此只要扫描频率足够高(一般大于50Hz),基本上就不出扫描过程中产生的像素点显示中断,对于人来说看到的就像一幅静止的画面。下图展示的就是电脑显示器的刷新频率设置界面。

在内存中记录了与显示屏的行列栅格对应的像素点数值,如下图所示:

这部分数据可以记录在CPU的内存中,也可以记录在显示卡的内存(显存)中,显示卡在显示的时候直接从内存中获取像素点数据,然后控制屏幕进行扫描,处理流程如下图所示:

下图展示的是一个屏幕的像素栅格模型,一般的屏幕的坐标以左上角为原点,竖直向下为Y轴正方向,从上到下依次为:0,1,2,3,……,反方向为负值;水平向右为X正方向,从左到右依次为:0,1,2,3,……,反方向为负值。

基本的绘图函数包括:

①绘制点:DrawPixel(x, y)

②绘制直线:DrawLine(x1, y1, x2, y2)

③绘制圆:DrawCircle(x, y, r)

④绘制矩形:DrawRectangle(x1, y1, x2, y2)

⑤绘制三角形:DrawTriangle(x1, y1, x2, y2, x3, y3)

下图展示的是一个使用基本绘图函数完成的“咖啡杯”的绘制,通过此例我们也可以看出显示屏的基本绘图原理:

二、绘制点

点的绘制非常简单,我们只需要给出点的位置坐标(x,y)。

 

DrawPixel(x,y)

 

该函数中封装了控制显示屏显示的一连串指令的细节。显示卡通常会提供绘制像素点的命令接口。

三、绘制线

观察上图,我们可以猜想到,想要绘制一条直线,可以通过画点来实现。那么问题来了:应该在哪儿画点?从图中我们可以看到,计算机绘制的直线不是一条绝对意义上的直线,它是用无数个像素点堆砌起来的一条直线。我们可以假设从左(x1, y1)至右(x2, y2)画一条直线,以横轴X为准,每增加一个单位dx,确定纵轴Y的增加值dy。其抽象模型如下:

从图中,我们可以得知:

起点:(x1, y1),终点:(x2, y2)

斜率:dy / dx = (y2- y1)  /  (x2 - x1)

假设第i个点与起点(x1, y1)的水平方向的距离ai,垂直距离为bi,那么第i个点的坐标可表示为:(x1+ai, y1 + bi)

我们的绘制流程如下:

①初始化:即当 i=0 时,(ai, bi)= (a0, b0) = (0, 0)

②判断是否到达终点:x1+ai ≦ x2 并且y1+bi ≦ y2。如果到达终点,跳到步骤⑤。

③绘制点:DrawPixel(x1+ai,y1 + bi)

④计算(ai, bi):这块是重点

跳到步骤②

⑤结束绘制。

线段的绘制重点在于步骤4,在高级绘制算法中,要根据视觉特性进行颜色灰度、明亮程度的计算,呈现给用户更加真实的视觉效果。对于一般的黑白屏来说,我们就只是简单的计算而已。草图如下:


如上图所示,当绘制第i个点时,主要是判断

ai+1 = ai + 1

            或者

bi+1 = bi + 1

判断主要根据上一次绘制点的情况

如果ai / bi  > dy / dx ,ai+1 = ai + 1;

否则ai / bi dy / dx ,bi+1 = bi + 1。

目前来说,我们线的绘制问题算是初步解决了。但是有个性能问题,当我们绘制工作量变得庞大时,ai、bi和ai/ bi的计算就变得复杂。那么我们如何优化呢?

ai / bi > dy / dx,转化为:ai * dy < bi* dx

定义diff = ai * dy - bi * dx,那么

当ai / bi > dy / dx 时,ai * dy < bi * dx,ai * dy - bi * dx < 0,即diff < 0。

那么,我们的步骤④计算过程优化为:

当diffi < 0,

          ai+1 = ai+ 1,diffi+1 = diffi + dx。

否则,

          bi+1 = bi+ 1,diffi+1 = diffi – dy。









阅读全文
0 0
原创粉丝点击