Skip to content

计算机科学入门

这台 1960 年的 PDP-1 ,是一个早期 图形计算机 的好例子,你可以看到左边是柜子大小的 电脑 ,中间是 电传打字机 ,右边是一个圆形的 屏幕 ,注意它们是分开的,因为当时文本任务和图形任务是分开的。

image-20231023130128097

事实上,早期的屏幕无法显示清晰的文字,而打印到纸上有更高的对比度和分辨率。

早期屏幕的典型用途是 跟踪 程序的运行情况,比如 寄存器的值 ,如果用打印机一遍又一遍打印出来没有意义,不仅费纸而且慢。

另一方面,屏幕 更新很快 ,对临时值简直完美,但屏幕很少用于输出计算结果,结果一般都打印到纸上,或其它更永久的东西上。

但屏幕超有用,到1960年代,人们开始用屏幕做很多酷炫的事情。

image-20231023130336709

阴极射线管

几十年间出现了很多显示技术,但最早最有影响力的是 阴极射线管(CRT),原理是把电子发射到 有磷光体涂层的屏幕上,当电子撞击涂层时会发光几分之一秒,由于电子是带电粒子,路径可以用磁场控制。

image-20231023130422045

屏幕内用板子或线圈把电子引导到想要的位置,上下左右都行。

既然可以这样控制,有 2 种方法绘制图形。

  1. 引导 电子束 描绘出形状,这叫 矢量扫描 (Vector Scanning),因为发光只持续一小会儿,如果重复得 足够快 ,可以得到清晰的图像。
image-20231023130454293
  1. 按固定路径,一行行来,从上向下,从左到右,不断重复,只在特定的点打开电子束,以此绘制图形,这叫 光栅扫描 (Raster Scanning),用这种方法,可以用很多小线段绘制形状,甚至文字。
image-20231023130529516

液晶显示屏

最后,因为显示技术的发展,我们终于可以在屏幕上显示清晰的点,叫 像素 (pixels)。

image-20231023130556460

液晶显示器 ,简称 LCD ,和以前的技术相当不同,但 LCD 也用 光栅扫描 ,每秒更新多次像素里红绿蓝的颜色。

有趣的是,很多早期计算机不用像素,不是技术做不到,而是因为像素占 太多内存

200 像素 × 200 像素的图像,有 40,000 个像素,哪怕每个像素只用一个 bit 表示代表黑色或白色,连灰度都没有,会占 40,000 bit 内存 ,比 PDP-1 全部内存的一半还多。

所以计算机科学家和工程师,得想一些技巧来渲染图形等内存发展到足够用。

早期计算机不存大量像素值而是存 符号 ,80 x 25 个符号最典型,总共 2000 个字符。

image-20231023130640262

如果每个字符用 8 位表示,比如用 ASCII ,总共才 16000 位,这种大小更合理。

字符生成器

为此,计算机需要额外硬件来从内存读取字符,转换成光栅图形,这样才能显示到屏幕上,这个硬件叫 字符生成器 ,基本算是第一代显卡。

它内部有一小块 只读存储器 ,简称 ROM,存着每个字符的图形,叫 点阵图案 (dot matrix pattern)。

如果图形卡看到一个 8 位二进制,发现是字母 K ,那么会把字母 K 的点阵图案, 光栅扫描 显示到屏幕的适当位置。

屏幕缓冲区

为了显示,字符生成器 会访问内存中一块 特殊区域 ,这块区域专为图形保留,叫 屏幕缓冲区 (screen buffer),程序想显示文字时,修改这块区域里的值就行。

这个方案用的内存少得多,但也意味着,只能画字符到屏幕上,即使有这样限制,人们用 ASCII 艺术发挥了很多创意!

也有人用字符模仿图形界面,用下划线和加号来画盒子,线,和其他简单形状。

但字符集实在太小,做不了什么复杂的事,因此对 ASCII 进行了各种扩展,加新字符,比如下图的 IBM CP437 字符集,用于 DOS。

image-20231023130843175

某些系统上,可以用额外的 bit 定义字体颜色和背景颜色做出这样的 DOS 界面,这界面只用了刚刚提到的字符集。

image-20231023130917070

字符生成器 是一种省内存的技巧,但没办法绘制任意形状,绘制任意形状很重要,因为电路设计,建筑平面图,地图,好多东西都不是文字!

矢量模式画图

为了绘制任意形状,同时不吃掉所有内存,计算机科学家用 CRT 上的 矢量模式 (vector mode)。

概念非常简单:所有东西都由线组成

没有文字这回事,如果要显示文字,就用线条画出来,只有线条,没有别的。

假设一个 笛卡尔平面(直角坐标系),200 个单位宽,100 个单位高,原点 (0,0) 在左上角。

我们可以画形状,用如下矢量命令,这些命令来自 Vectrex ,一个早期 矢量显示系统

首先,reset ,这个命令会清空屏幕。

把电子枪的绘图点移动到坐标 (0,0),并把线的亮度设为 0。

MOVE_TO 50 50 ,把绘图点移动到坐标 (50,50) 。

INTENSITY 100 ,把强度设为 100 。

现在亮度提高了,移动到 (100,50) 然后 (60,75) 然后 (50,50) 。

最后把强度设回 0 。

这样就画出了一个三角形。

这些命令占 160 bit ,比存一个庞大的像素矩阵更好,就像之前的 字符生成器 ,把内存里的字符转成图形一样,这些矢量指令也存在内存中,通过 矢量图形卡 画到屏幕上。

数百个命令可以按序存在屏幕缓冲区,画出复杂图形,全是线段组成的!

由于这些矢量都在内存中,程序可以更新这些值,让图形随时间变化 - 动画

最早的电子游戏之一,Spacewar 是 1962 年在 PDP-1 上用矢量图形制作的。它启发了许多后来的游戏,比如 爆破彗星 (Asteroids) ,甚至第一个商业街机游戏:太空大战 (Computer Space)。

image-20231023131159001

Sketchpad

1962 年是一个大里程碑,Sketchpad 诞生,一个交互式图形界面,用途是 计算机辅助设计 (CAD)。

它被广泛认为是第一个完整的图形程序,发明人 伊万·萨瑟兰 后来因此获得 图灵奖

为了与图形界面交互, Sketchpad 用了当时发明不久的输入设备 光笔 (light pen),就是一个有线连着电脑的触控笔。

image-20231023131256365

笔尖用光线传感器,可以检测到显示器刷新,通过判断刷新时间,电脑可以知道笔的位置,有了光笔和各种按钮,用户可以画线和其他简单形状。

image-20231023131318798

Sketchpad 可以让线条完美平行,长度相同,完美垂直90度,甚至动态缩放,这些在纸上很费力,在计算机上非常简单!

用户还可以保存设计结果,方便以后再次使用,甚至和其他人分享。

image-20231023131454140

你可以有一整个库,里面有电子元件和家具之类的,可以直接拖进来用。

从如今的角度来看好像很普通,但在1962年,计算机还是吃纸带的大怪兽,有柜子般大小,Sketchpad光笔 让人大开眼界,它们代表了人机交互方式的关键转折点。

电脑不再是关在门后,负责算数的机器了,可以当助手,帮人类做事。

位图显示

最早用真正像素的计算机和显示器出现于 1960 年代末,内存中的位(Bit) 对应屏幕上的像素,这叫 位图显示 (bitmapped displays)。

现在我们可以绘制任意图形了,你可以把图形想成一个巨大像素值矩阵。

就像之前,计算机把像素数据存在内存中一个特殊区域,叫 帧缓冲区 (frame buffer)。

早期时,这些数据存在内存里,后来存在高速视频内存里,简称 VRAM

VRAM 在显卡上,这样访问更快,如今就是这样做的。

在 8 位灰度屏幕上,我们可用的颜色范围是 0 强度(黑色),到 255 强度(白色),其实更像绿色或橙色,因为许多早期显示器不能显示白色。

image-20231023131556220

我们假设,这个视频在低分辨率的位图屏幕上,分辨率 60 x 35 像素。

如果我们想把 (10,10) 的像素设为白色,可以用这样的代码。

bash
	framebuffer[10][10] = 255
	framebuffer[10][10] = 255

如果想画一条线 假设从 (30,0) 到 (30,35) ,可以用这样一个循环,把整列像素变成白色。

bash
	FOR y = 0 TO 35
		framebuffer[30][y] = 255
	NEXT
	FOR y = 0 TO 35
		framebuffer[30][y] = 255
	NEXT

如果想画更复杂的图形,比如矩形,那么需要四个值。

  1. 起始点X坐标
  2. 起始点Y坐标
  3. 宽度
  4. 高度
bash
	x = 2
	y = 10
	width = 4
	height = 8
	color = 127
	x = 2
	y = 10
	width = 4
	height = 8
	color = 127

目前只试了白色,这次画矩形试下灰色,灰色介于0到255中间,所以我们用 127 (255/2=127.5) 。

然后用两个循环,一个套另一个,这样外部每跑一次,内部会循环多次,可以画一个矩形。

bash
	x = 2
	y = 10
	width = 4
	height = 8
	color = 127
	FOR i = x TO x + width
		FOR j = y TO y + height
			framebuffer[i][j] = color
		NEXT
	NEXT
	x = 2
	y = 10
	width = 4
	height = 8
	color = 127
	FOR i = x TO x + width
		FOR j = y TO y + height
			framebuffer[i][j] = color
		NEXT
	NEXT

计算机绘图时会用指定的颜色 127 ,我们来包装成 画矩形函数 ,就像这样:

bash
	FUNCTION drawRectanle(x,y,width,height,color)
		FOR i = x TO x + width
			FOR j = y TO y + height
				framebuffer[i][j] = color
			NEXT
		NEXT
	RETURN
	FUNCTION drawRectanle(x,y,width,height,color)
		FOR i = x TO x + width
			FOR j = y TO y + height
				framebuffer[i][j] = color
			NEXT
		NEXT
	RETURN

假设要在屏幕的另一边画第二个矩形,这次可能是黑色矩形,可以直接 调用 画矩形函数 ,超棒!

bash
	drawRectangle(54,4,4,8,0)
	drawRectangle(54,4,4,8,0)

就像之前说的其他方案,程序可以操纵 帧缓冲区 中的像素数据,实现 交互式 图形。

当然,程序员不会浪费时间从零写绘图函数,而是用预先写好的函数来做,画直线,曲线,图形,文字等、

位图的灵活性,为交互式开启了全新可能,但它的高昂成本持续了十几年。

1971 年,整个美国也只有大约 7 万个电传打字机和 7 万个终端,令人惊讶的是,只有大约 1000 台电脑有 交互式 图形屏幕。

Sketchpad太空大战 这样的先驱,推动了图形界面发展,帮助普及了计算机显示器,由此,图形界面的曙光初现。

用心去做高质量的编程学习内容网站,欢迎star ⭐让更多人发现!