第1章 图形系统和模型
概述
计算机图形学,即研究如何利用计算机表示、生成、处理和显示图像,其中涵盖了所需的硬件、软件和应用等。
一切皆是像素
计算机图形学的研究对象一图形 。
图形是从客观世界物体中抽象出来的带有颜色及形状信息的图和 形。
图形的构成要素:
1、几何要素:点、线、面、体等描述对象的轮廓、形状。
2、非几何要素:描述对象的颜色、材质等。
图形的表示方法:
1、点阵法:枚举出图形中所有点(简称图像)。
2、参数法:由图形的形状参数(简称图形)。
图形与图像
1、图像:狭义上又称为点阵图或位图图像。
1)图像是指整个显示平面以二维矩阵表示,矩阵的每一点称为一个像素,由像素点所取亮度或颜色值不同所构成的二维画面。
2)特点:
文件所占的空间大;
位图放大到一定的倍数后会产生锯齿;
位图图像在表现色彩、色调方面的效果比矢量图更加优越。
2、 图形:狭义上又称为矢量图形或参数图形。
1)按照数学方法定义的线条和曲线组成,含有几何属性或者说更强调场景的几何表示,是由场景的几何模型和景物的物理属性共同组成的。
2)特点:
文件小;
可采取高分辨印刷;
图形可以无限缩放。
基本图形系统
1、输入设备
2、中央处理单元(CPU)
3、图形处理单元(GPU)
4、存储器
5、帧缓存
6、输出设备
像素和帧缓存
在基于光栅的现代图形系统中,输出设备上看到的图像是一个由图形系统产生的图形元素组成的阵列,图形元素也叫像素,像素阵列也称为光栅(raster)。每一个像素对应于图像中的一个位置,或者一块小区域。这些像素都保存在一个称为帧缓存(framebuffer)的储存区域中。帧缓存是图形系统的核心元素。
分辨率(resolution):帧缓存中像素的数目,决定了从图像中可以分辨出多少细节。
帧缓存的深度/精度:表示每个像素所用的比特数,决定了诸如给定系统中可以表示多少种颜色之类的性质。(深度为n比特的帧缓存,允许2n2^n2n种颜色)
帧缓存使用浮点格式存储颜色值。
CPU与GPU
CPU:
获取由应用程序生成的图元(如线、圆、多边形)的属性,并为帧缓存中的像素赋值,以最佳地表示这些图元。
GPU:
专门用来完成图形处理功能,具有高度的并行性。GPU可以在系统的主板或者图形卡中。帧缓存可以被GPU访问,而且它通常与GPU位于同一块电路板上。
CPU是建模器,GPU是绘制器。
光栅化/扫描转换:
从几何实体到帧缓存中像素的颜色和位置的转换
应用程序接口
三维API
WebGL程序通过顶点列表来定义图元。
//WebGL在JavaScript中指定三个顶点的方法
var vertices=[ ];
vertices[0]=[0.0,0.0,0.0];//顶点A
vertices[1]=[0.0,1.0,0.0];//顶点B
vertices[2]=[0.0,0.0,1.0];//顶点C
//或者使用push函数
vertices.push([0.0,0.0,0.0]);
线框图: 绘制的图像中只显示出了各个部分的轮廓,只能看到表面的边线,在边线之间没有实体部分。
WebGL程序
三要素
HTML: 用于描述网页,导入各种工具,包括Shader工具
JavaScript: 程序实现核心代码,实现图形绘制
OpenGL ES: 提供底层OpenGL驱动,实现硬件支持
代码运行
所有的代码均可运行于各种主流浏览器,包括Chrome, FireFox, Safari, Edge等
核心代码以JavaScript写成,在浏览器中本地运行,具有良好的跨平台、跨系统性
Lab1 WebGL画一个三角形
HTML代码
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title>Triangle</title>
<!-- 顶点着色器,传送顶点的位置信息-->
<script id="vertex-shader" type="x-shader/x-vertex">
//vec4是向量类型,相当于一个具有四个float元素的C++数组类
//四维向量vPosition存储了输入着色器的顶点的位置,在着色器的初始化部分,通过一个关键词attribute来说明vPosition存储的值是着色器的输入数据,该数据来着应用程序。
attribute vec4 vPosition;
void main(){//入口
//内置状态变量gl_Position(无需声明),是每个顶点着色器必须输出的状态变量,该变量会将经过顶点着色器处理后的顶点位置传送到GPU的光栅化模块中。
gl_Position=vPosition;
}
</script>
<!-- 每次执行顶点着色器都会输出一个顶点,该顶点再经过图元组装模块和裁剪模块的处理后到达光栅化模块。-->
<!-- 光栅化模块输出位于视见体内部的每个图元的片元。每个片元都会被片元着色器处理,每次执行片元着色器时必须至少输出每个片元的颜色,除非这个片元在着色器中被标记为丢弃 -->
<!-- 片元着色器 -->
<script id="fragment-shader" type="x-shader/x-vertex">
//浮点变量的精度设置为mediump,可以保证着色器能够在所有支持WebGL的设备上运行
precision mediump float;
void main(){
//内置变量,为每个片元指定一个四维的RGBA颜色
gl_FragColor=vec4(1.0,0.0,0.0,1.0);
}
</script>
<!-- 相关的JS库 -->
<!-- 包含创建WebGL canvas对象所需要的实用工具 -->
<script type="text/javascript" src="./js/common/webgl-utils.js"></script>
<!-- 包含读取、编译和链接着色器的代码-->
<script type="text/javascript" src="./js/common/initShaders.js"></script>
<!-- 包含基本的矩阵和向量操作-->
<script type="text/javascript" src="./js/common/gl-matrix-min.js"></script>
<!-- 绘制三角形的JS代码 -->
<script type="text/javascript" src="./js/triangle.js"></script>
</head>
<body>
<canvas id="triangle-canvas" style="border:none;" width="500" height="500"></canvas>
</html>
JS代码
"use strict";
var gl;
var points;
//初始化函数
//onload事件
window.onload=function init(){
//HTML文件中指定了一个期望大小的canvas并为其指派标识符“triangle-canvas”。
//如果浏览器支持webGL,WebGLUtils.js文件中的函数返回一个WebGL上下文(context)
//WebGL上下文是一个JavaScript对象,该对象包含所有的WebGL参数及函数。
//创建WebGL上下文
var canvas=document.getElementById("triangle-canvas");
gl=WebGLUtils.setupWebGL(canvas);
//此后,gl对象中的WebGL函数,通过gl.前缀调用
if(!gl){
alert("WebGL isn't available");
}
//指定三个顶点(二维)
var vertices=[
-1.0, -1.0,
0.0, 1.0,
1.0, -1.0,
]
// Configure WebGL
//设置视口大小
gl.viewport( 0, 0, canvas.width, canvas.height );
//设置背景颜色
gl.clearColor( 1.0,1.0, 1.0, 1.0 );
// Load shaders and initialize attribute buffers
//将着色器链接到程序对象中,加载着色器并初始化属性缓存区
//initShaders()函数(initShaders.js文件中)的返回值为程序对象,后面两个参数是在HTML文件中指定的标识符
var program = initShaders( gl, "vertex-shader", "fragment-shader" );
//使用着色器
gl.useProgram(program);
// Load the data into the GPU 创建一个缓存对象,向GPU发送数据
//创建缓冲区并返回一个标识符bufferId(当前缓冲区)
var bufferId = gl.createBuffer();
//说明缓存对象保存的类型
//参数gl.ARRAY_BUFFER说明缓冲区的数据是顶点属性数据,而不是数据的索引
gl.bindBuffer( gl.ARRAY_BUFFER, bufferId );
//写入坐标数据,把数据发送给GPU缓存
//gl.bufferData()的最后一个参数说明应用程序使用数据的方式。
//gl.STATIC_DRAW:数据从CPU到GPU只需要发送一次,并且在GPU中也只需绘制一次
gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( vertices ), gl.STATIC_DRAW );
// Associate external shader variables with data buffer
//获取到顶点着色器中的属性变量
var vPosition = gl.getAttribLocation( program, "vPosition" );
//描述顶点数组中的数据形式,第2个参数和第3个参数说明vertices数组的每个元素都包含两个浮点数。
//第4个参数说明我们不需要将数据归一化至(0.0,1.0)这个范围,第5个参数说明数组中的值是连续的
//最后一个参数说明缓冲区中数据的起始位置
gl.vertexAttribPointer( vPosition, 2, gl.FLOAT, false,0, 0 );
//开启着色器中的顶点属性
gl.enableVertexAttribArray( vPosition );
render();
}
function render(){
//清除帧缓存
gl.clear(gl.COLOR_BUFFER_BIT);
//绘制位于GPU中的点数据
//从第1个点开始的3个数据会被绘制出来
//第一个参数gl.TRIANGLES,告诉GPU以三角形作为图元类型绘制离散的点,
gl.drawArrays(gl.TRIANGLES,0,3);
}
课后习题答案
第2章 图形学编程
Sierpinski镂垫
编写二维图形应用程序
如何表示点?
将一个三维空间中的点表示为一个三元组P=(x,y,z)或者一个列矩阵。
顶点:空间中的一个位置。可以利用顶点来定义图形系统可识别的基本几何图元。
点:最简答的基本图元,一般由一个顶点来定义。
(两个顶点可以用来定义线段,三个顶点可以定义一个三角形或者一个圆等)