红宝书系列读书笔记(六)

使用Canvas绘图

基本用法
要使用<canvas>元素,必须先设置其width和height,指定可以绘图的区域大小。
要在这块画布(canvas)上绘图吗,需要取得绘图上下文,是通过getContext(),然后传入上下文的名字。
传入“2d”,就可以取得2D上下文对象。

1
<canvas id="drawing" width="200" height="200">您的浏览器不支持canvas元素</canvas>

1
2
3
4
5
var drawing = document.getElementById("drawing");
//确定浏览器支持<canvas>元素
if(drawing.getContext){
    var context = drawing.getContext("2d");
}

使用toDataURL()方法,可以导出在<canvas>元素上绘制的图像。这个方法接受一个参数,即图像的MIME类型格式,
而且适用于创建图像的任何上下文。

1
2
3
4
5
6
7
8
9
10
var drawing = document.getElementById("drawing");
//确定浏览器支持<canvas>元素
if(drawing.getContext){
    //取得图像的数据URI
    var imgURI = drawing.toDataURL("image/png");
    //显示图像
    var image = document.createElement("img");
    image.src = imgURI;
    document.body.appendChild(image);
}

2D上下文
1.填充和描边
填充,就是用指定的样式(颜色、渐变、或图像)填充图形,取决于fillStyle属性;
描边,就是只在图形的边缘画线,取决于strokeStyle属性。
fillStyle和strokeStyle属性的值可以是字符串、渐变对象或模式对象,它们的默认值都是“#000000”。

1
2
3
4
5
6
var drawing = document.getElementById("drawing");
if(drawing.getContext){
    var context = drawing.getContext("2d");
    context.strokeStyle = "red";
    context.fiilStyle = "#0000ff";
}

2.绘制矩形
矩形是唯一一种可以直接在2D上下午中绘制的形状。
与矩形有关的方法包括:fillRect()、strokeRect()和clearRect()。
这三个方法都接收4个参数:矩形的x坐标、矩形的y坐标、矩形宽度和矩形高度。这些参数的单位都是像素。
首先,fillRect()方法会在画布上绘制的矩形会填充指定的颜色。填充的颜色通过fillStyle属性指定。

1
2
3
4
5
6
7
8
9
10
11
var drawing = document.getElementById("drawing");
if(drawing.getContext){
    var context = drawing.getContext("2d");
    //绘制红色矩形
    context.fillStyle = "#ff0000";
    context.fillRect(10,10,50,50);
    //绘制半透明的蓝色矩形
    context.fillStyle = "rgba(0,0,255,0.5)";
    context.fillRect(30,30,50,50);
}

strokeRect()方法在画布上绘制的是矩形边框,边框颜色由strokeStyle属性指定。
描边线条的跨度由lineWidth属性控制,该属性的值可以是任意整数。另外,通过lineCap属性可以控制线条末端的形状是平头、圆头还是方头(“butt”,“round”,“square”),通过lineJoin属性可以控制线条相交的方式是圆交、斜交还是斜接(“round”,“bevel”,“miter”);

clearRect()方法用于清除画布上的矩形区域,区域大小由该方法中传入的参数决定。
本质上,这个方法可以绘制上下文中的某一矩形区域变透明。

1
2
3
4
5
6
7
8
9
10
11
12
13
var drawing = document.getElementById("drawing");
if(drawing.getContext){
    var context = drawing.getContext("2d");
    // 绘制红色矩形
    context.fillStyle = "#ff0000";
    context.fillRect(10, 10, 50, 50);
    // 绘制半透明的蓝色矩形
    context.fillStyle = "rgba(0, 0, 255, 0.5)";
    context.fillRect(30, 30, 50, 50);
    // 在两个矩形重叠的地方清除一个小矩形
    context.clearRect(40, 40, 10, 10);
}

3.绘制路径
要绘制路径,首先必须调用beginPath()方法,表示要开始绘制新路径。然后通过下列方法来实际地绘制路径:
arc(x, y, radius, startAngle, endAngle, counterclockwise):以(x,y)为圆心绘制一条弧线,弧线半径为radius,
起始和结束角度(用弧度表示)分别为startAngle和endAngle。最后一个参数表示startAngle和endAngle是否按逆时针计算,
值为false表示按顺时针方向计算。
arcTo(x1, y1, x2, y2, radius):从上一点开始绘制一条弧线,到(x2,y2)为止,并且以给定的半径radius穿过(x1,y1)。
bezierCurveTo(c1x, c1y, c2x, c2y, x, y):从上一点开始绘制一条曲线,到(x,y)为止,并且以(c1x,c1y)和(c2x,c2y)为控制点。
lineTo(x, y):从上一点开始绘制一条直线,到(x,y)为止。
moveTo(x, y):将绘图游标移动到(x,y),不画线。
quadraticCurveTo(cx, cy, x, y):从上一点开始绘制一条二次曲线,到(x,y)为止,并且以(cx,cy)作为控制点。
rect(x, y, width, height):从点(x,y)开始绘制一个矩形,宽度和高度分别由width和height指定。这个方法绘制的是矩形路径,而不是strokeRect()和fillRect()所绘制的独立的形状。

如果想绘制一条连接到路径起点的线条,可以调用closePath().
如果你想用fillStyle填充它,可以调用fill()方法。另外,还可以调用stroke()方法对路径描边,描边使用的是strokeStyle。
还可以调用clip()在路径上创建一个剪切区域。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//绘制一个不带数字的时钟表盘
var drawing = document.getElementById("drawing");
if(drawing.getContext){
var context = drawing.getContext("2d");
//开始绘制路径
context.beginPath();
//绘制外圆
context.arc(100,100,99,0,2*Math.PI,false);
//绘制内圆
context.moveTo(194,100);
context.arc(100,100,94,0,2*Math.PI,false);
//绘制分针
context.moveTo(100,100);
context.lineTo(100,15);
//绘制时针
context.moveTo(100,100);
context.lineTo(35,100);
//描边路径
context.stroke();
}

在路径使用频繁时,使用isPointInPath()方法判断路径被关闭之前画布某一点是否位于路径上,接收两个参数:x坐标和y坐标。

绘制文本
绘制文本主要有两个方法:fillText()和strokeText()。
这两个方法都可以接收4个参数:要绘制的文本字符串、x坐标、y坐标和可选的最大像素宽度。
这两个方法都以下列3个属性为基础:
font:表示文本样式、大小及字体,用CSS中指定字体的格式来指定。
textAlign:表示文本对齐方式。可能的值有“start”、“end”、“left”、“right”和“center”,建议使用“start”和“end”,更稳定。
textBaseline:表示文本的基线。
可能的值有”top“、”hanging“、”middle“、”alphabetic“、”ideographic“和”bottom“。

1
2
3
4
context.font = "bold 14px Arial";
context.textAlign = "center";
context.textBaseline = "middle";
context.fillText("12",100,20);

2D上下文提供了辅助确定文本大小的方法measureText()。这个方法接收一个参数,即要绘制的文本;返回一个TextMetrics对象。返回的对象目前只有一个width属性。
measureText()方法利用font、textAlign和textBaseline的当前值计算指定文本的大小。

1
2
3
4
5
6
7
8
var fontSize = 100;
context.font = fontSize +"px Arial";
while(context.measureText("Hello world!").width > 140){
fontSize--;
    context.font = fontSize + "px Arial";
}
context.fillText("Hello world!",10,10);
context.fillText("Font size is " +fontSize +"px",10,50);

变换
通过上下文的变换,可以把处理后的图像绘制到画布上。
通过以下方法来修改变换矩阵:
rotate(angle):围绕原点旋转图像angle弧度。

旋转角度,以弧度计。
如需将角度转换为弧度,请使用 degreesMath.PI/180 公式进行计算。
举例:如需旋转 5 度,可规定下面的公式:5
Math.PI/180。
context.rotate(5*Math.PI/180);

scale(scaleX,scaleY):缩放图像,在x方向乘以scaleX,在y方向乘以scaleY。scaleX和scaleY的默认值都是1.0。
translate(x,y):都是将坐标原点移动到(x,y)。执行这个变换之后,坐标(0,0)会变成之前由(x,y)表示的点。
transform(m1_1, m1_2, m2_1, m2_2, dx, dy):直接修改变换矩阵,方式是乘以如下矩阵。

m1_1 m1_2 dx
m2_1 m2_2 dy
0 0 1

setTransform(m1_1, m1_2, m2_1, m2_2, dx, dy):将变换矩阵重置为默认状态,然后再调用transform()。
还由两个方法可以跟踪上下文的状态变化,如果你知道将来还要返回某组属性与变换的组合,可以调用save()方法;
等想要回到之前保存的设置时,可以调用restore()方法,在保存设置的栈结构中向前返回一级,恢复之前的状态。
连续调用save()可以把更多设置保存到栈结构中,之后再连续调用restore()则可以一级一级返回。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
context.fillStyle = "#ff0000";
context.save();
context.fillStyle = "#00ff00";
context.translate(100,100);
context.save();
context.fillStyle = "#0000ff";
context.fillRect(0,0,100,200);    //从点(100,100)开始绘制蓝色矩形
context.restore();
context.fillRect(10,10,100,200);    //从点(110,110)开始绘制绿色矩形
context.restore();
context.fillRect(0,0,100,200);    //从点(0,0)开始绘制红色矩形

需要注意的是,save()方法保存的只是对绘图上下文的设置和变换,不会保存绘图上下文的内容。

绘制图像
2D上下文内置了对图像的支持,通过drawImage()方法可以将一副图像绘制到画布上。
该方法有三种参数组合:

1
2
3
4
5
6
7
8
var image = document.images[0];
//传入HTML<img>元素,以及绘制该图像的起点的x和y坐标。
context.drawImage(image, 10, 10);
//要想改变图像大小,可以再多传入两个参数:目标宽度和目标高度
context.drawImage(image, 50, 10, 20, 30);
//把图像中的某个区域绘制到上下文中,传入9个参数:要绘制的图像、源图像的x坐标、源图像的y坐标、源图像的宽度、
//源图像的高度、目标图像的x坐标、目标图像的y坐标、目标图像的宽度、目标图像的高度。
context.drawImage(image, 0, 10, 50, 50, 0, 100, 40, 60);

阴影
2D上下文会根据以下几个属性的值,自动为形状或路径绘制出阴影:
shadowColor:用CSS颜色格式表示的阴影颜色,默认为黑色。
shadowOffsetX:形状或路径x轴方向的阴影偏移量,默认为0。
shadowOffsetY:形状或路径y轴方向的阴影偏移量,默认为0。
shadowBlur:模糊的像素数,默认为0,即不模糊。

1
2
3
4
5
6
7
8
9
10
11
12
13
var drawing = document.getElementById("drawing");
var context = drawing.getContext("2d");
//设置阴影
context.shadowOffsetX = 5;
context.shadowOffsetY = 5;
context.shadowBlur = 4;
context.shadowColor = "rgba(0,0,0,0.5)";
//绘制红色矩形
context.fillStyle = "#ff0000";
context.fillRect(10, 10, 50, 50);
//绘制蓝色矩形
context.fillStyle = "rgba(0,0,255,1)";
context.fillRect(30, 30, 50, 50);

渐变
渐变由CanvasGradient实例表示,能够通过2D上下文来创建和修改。
要创建一个新的线性渐变,可以调用createLinearGradient()方法。
这个方法接收4个参数:起点的x坐标、起点的y坐标、终点的x坐标、终点的y坐标。
调用这个方法后,它就会创建一个指定大小的渐变,并返回CanvasGradient对象的实例。
创建了渐变对象后,下一步就是使用addColorStop()方法来指定色标。
这个方法接收两个参数:色标位置和CSS颜色值。色标位置是一个0(开始的颜色)到1(结束的颜色)之间的数字。

1
2
3
4
5
6
var gradient = context.createLinearGradient(30,30,70,70);
gradient.addColorStop(0,"white");
gradient.addColorStop(1,"black");
//将fillStyle或strokeStyle设置为这个对象,从而使用渐变来绘制形状或描边
context.fillStyle = gradient ;
context.fillRect(30,30,50,50);

为了确保渐变与形状对齐,有时候可以考虑使用函数来确保坐标合适:

1
2
3
function createRectLinearGradient(context,x,y,width,height){
    return context.createLinearGradient(x, y, x+width, y+height);
}

创建径向渐变(或放射渐变),可以使用createRadialGradient()方法。这个方法接收6个参数,对应着两个圆的圆心和半径。前三个是起点圆的圆心(x和y)及半径,后三个是终点圆的圆心(x和y)及半径。
如果想从某个形状的中心点开始创建一个向外扩散的径向渐变效果,就要将两个圆定义为同心圆。

1
2
3
4
5
6
var gradient = context.createRadialGradient(55,55,10,55,55,30);
gradient.addColorStop(0,"white");
gradient.addColorStop(1,"black");
context.fillStyle = gradient ;
context.fillRect(30,30,50,50);

模式

模式其实就是重复的图像,可以用来填充或描边图形。
通过createPattern()方法来创建新模式,该方法接收两个参数:一个HTML<img>元素和一个表示如何重复图像的字符串。第二个参数值与CSS的background-repeat属性值相同:repeat、repeat-x、repeat-y、no-repeat。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var image = document.image[0];
pattern = context.createPattern(image,"repeat");
//绘制矩形
context.fillStyle = pattern;
context.fillRect(10,10,150,150);
需要注意的是模式对象的生成和赋值过程必须写到JavaScript的function中,否则可能会失效。
window.onload = function() {
var drawing = document.getElementById("drawing"); 
var context = drawing.getContext("2d");   
var img = new Image();
img.src = "http://imgsrc.baidu.com/forum/pic/item/e6b14bc2a4561b1fe4dd3b24.jpg"
var pattern = context.createPattern(img, 'repeat');
context.fillStyle = pattern;
context.fillRect(0, 0, canvas.width, canvas.height);
}

使用图像数据
通过getImageData()取得原始图像数据。这个方法接收四个参数:要取得其数据的画面区域的x和y坐标以及该区域的像素宽度和高度。
返回ImageData对象实例,每个ImageData对象都有三个属性:width、height和data。
data属性是一个数组,保存着图像中每一个像素的数据。在data数组中,每一个像素用4个元素来保存,分别表示红、绿、蓝和透明度值。

1
2
3
4
5
6
var imageData = context.getImageData(10,5,50,50);
var data = imageData.data;
red = data[0];
green = data[1];
blue = data[2];
alpha = data[3];

通过修改图像数据,可以像下面这样创建一个简单的灰阶过滤器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/*灰阶过滤器*/
var drawing = document.getElementById("drawing");
if(drawing.getContext){
var context = drawing.getContext("2d");
var image = document.images[0];
var imageData, data, i, len, average, red, green, blue, alpha;
//绘制原始图像
context.drawImage(image,0,0);
//取得图像数据
imageData = context.getImageData(0,0,image.width,image.height);
data = imageData.data;
for (i = 0,len = data.length; i < len; i += 4) {
red = data[i];
green = data[i+1];
blue = data[i+2];
alpha = data[i+3];
//求得rgb平均值
average = Math.floor((red+green+blue)/3);
//设置颜色值,透明度不变
data[i] = average;
data[i+1] = average;
data[i+2] = average;
}
imageData.data = data;
//将图像数据绘制到画布上
context.putImageData(imageData,0,0);
}

需要注意的是,在本地测试时会报错,因为本地测试用的图片是文件夹内的,js跨域限制是不能获取非同一域名下的数据的,而本地的位置是没有域名的,所以浏览器都认为你是跨域,导致报错。

合成
还有两个会应用到2D上下文中所有绘制操作的属性:globalAlpha和globalCompositionOperation.
globalAlpha是一个介于0和1之间的值(包括0和1),用于指定所有绘制的透明度。默认值为0;
如果所有后续操作都要基于相同的透明度,就可以先把globalAlpha设置为适当的值,然后绘制,最后再设置为0。

1
2
3
4
5
6
7
8
9
10
//绘制红色矩形
context.fillStyle = "#ff0000";
context.fillRect(10,10,50,50);
//修改全局透明度
context.globalAlpha =0.5;
//绘制蓝色矩形
context.fillStyle="rgba(0,0,255,1)";
context.fillRect(30,30,50,50);
//重置全局透明度
context.globalAlpha = 0;

globalCompositionOperation表示后绘制的图形怎样与先绘制的图形结合。
有以下属性值(字符串):
source-over(默认值):后绘制的图形位于先绘制的图形上方。
source-in:后绘制的图形与先绘制的图形重叠部分可见,两者其他部分完全透明。
source-out:后绘制的图形与先绘制的图形重叠部分不可见,先绘制的图形完全透明。
source-atop:后绘制的图形与先绘制的图形重叠部分可见,先绘制的图形不受影响。
destination-over:后绘制的图形位于先绘制的图形下方,只有之前透明像素下的部分才可见。
destination-in:后绘制的图形位于先绘制的图形下方,两者不重叠的部分完全透明。
destination-out:后绘制的图形擦除与先绘制的图形重叠的部分。
destination-atop:后绘制的图形位于先绘制的图形下方,在两者不重叠的地方,先绘制的图形变透明。
lighter:后绘制的图形与先绘制的图形重叠部分的值相加,使该部分变亮。
copy:后绘制的图形完全替代与之重叠的先绘制图形。
xor:后绘制的图形与先绘制的图形重叠的部分执行“异或”操作。

WebGL

WebGL是针对Canvas的3D上下文。
类型化数组
WebGL涉及的复杂计算需要提前知道数值的精度,而标准的Javascript数值无法满足需求。为此,WebGL引入了类型化数组。
类型化数组也是数组,只不过其元素被设置为特定类型的值。
类型化数组的核心是一个名为ArrayBuffer(数组缓冲器类型)的类型。每个ArrayBuffer对象表示的只是内存中指定的字节数,但不会指定这些字节用于保存什么类型的数据。
通过ArrayBuffer能够为将来使用分配一定数量的字节。

1
2
var buffer = new ArrayBuffer(20);//在内存中分配20字节
var bytes = buffer.byteLength;    //通过buffer对象获取唯一的信息,字节数

1.视图
使用ArrayBuffer的一种特别的方式就是用它来创建数组缓冲器视图。
最常见的视图是DataView,通过它可以选择ArrayBuffer中一小段字节。

1
2
3
4
5
6
//基于整个缓冲器创建一个新视图
var view = new DataView(buffer);
//创建一个开始于字节9的新视图
var view = new DataView(buffer, 9);
//创建一个从字节9开始到字节18的新视图
var view = new DataView(buffer, 9, 10);

DataView对象会把字节偏移量以及字节长度信息分别保存在byteOffset和byteLength属性中。

2.类型化视图
类型化视图一般也被称为类型化数组。有以下几种:
Int8Array、Uint8Array、Int16Array、Uint16Array、Int32Array、Uint32Array、Float32Array、Float64Array.

如果为相应元素指定的字节数放不下相应的值,则实际保存的值是最大可能值的模。
类型化视图还有一个方法,subarray(),使用这个方法可以基于底层数组缓冲器的子集创建一个新视图。
这个方法接收两个参数:开始元素的索引和可选的结束元素的索引。返回的类型与调用该方法的视图类型相同。

WebGL上下文
在使用WebGL上下文时,务必先检测一下返回值。

1
<canvas id="drawing" width="200" height="200">您的浏览器不支持canvas元素</canvas>

1
2
3
4
5
6
7
var  drawing = document.getElementById("drawing");
if(drawing.getContext){
    var gl = drawing.getContext("experimental-webgl");
    if(gl){
        //使用WebGL
    }
}

一般都把WebGL上下文对象命名为gl。
通过给getContext()传递第二个参数,可以为WebGL上下文设置一些选项。这个参数本身是一个对象,有以下属性:
alpha:值为true,表示为上下文创建一个Alpha通道缓冲区;默认为true。
depth:值为true,表示可以使用16位深缓冲区;默认值为true。
stencil:值为true,表示可以使用8位模板缓冲区;默认值为false。
antialias:值为true,表示将使用默认机制执行抗锯齿操作;默认为true。
premultipliedAlpha:值为true,表示绘图缓冲区有预乘Alpha值;默认值为true。
preserveDrawingBuffer:值为true,表示在绘图完成后保留绘图缓冲区;默认值为false。

1
2
3
4
5
6
7
var  drawing = document.getElementById("drawing");
if(drawing.getContext){
    var gl = drawing.getContext("experimental-webgl",{alpha:false});
    if(gl){
        //使用WebGL
    }
}

如果getContext()无法创建WebGL上下文,有的浏览器会报错,为此,最好把调用封装到try-catch块中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var  drawing = document.getElementById("drawing"),
        gl;
if(drawing.getContext){
    try{
        gl = drawing.getContext("experimental-webgl");
    }catch(ex){
    
    }
    if(gl){
        //使用WebGL
    }else{
        alert("WebGL context could not be created.");
    }
}

1.常量
eg:gl.COLOR_BUFFER_BIT

2.方法命名
方法名的后缀包含参数个数(1到4)和接收的数据类型(f表示浮点数,i表示整数),而v代表接收数组
eg:
gl.uniform3i()接收3个整数。
gl.uniform4f()接收4个浮点数。
gl.uniform3iv()接收一个包含3个值的整数数组。

3.准备绘图
在实际操作WebGL上下文之前,一般都要使用某种实色清除<canvas>,为绘图做好准备。
首先必须使用clearColor()方法来指定要使用的颜色值,该方法接收4个参数:红、绿、蓝和透明度。
每个参数都必须是一个0到1之间的数值,表示每种分量在最终颜色中的强度。
eg:
gl.clearColor(0,0,0,1);
gl.clear(gl.COLOR_BUFFER_BIT);

4.视口与坐标
开始绘图之前,通常需要先定义WebGL视口(viewport)。
默认情况下,视口可以使用整个<canvas>区域。
要改变视口的大小,可以调用viewport()方法并传入4个参数:
(视口相对于<canvas>元素的)x坐标、y坐标、宽度和高度。

1
2
//调用<canvas>元素
gl.viewport(0,0,drawing.width,drawing.height);

视口坐标的原点在<canvas>元素的左下角,x轴和y轴的正方向分别是向右和向上。

另外,在视口内部的坐标系与定义视口的坐标系也不一样,在视口内部,坐标原点(0,0)是视口的中心点。
在视口内部绘图时使用视口外部坐标,结果可能会被视口剪切。

5.缓冲区
顶点信息保存在javascript的类型化数组中,使用之前必须转换到WebGL缓冲区。

1
2
3
4
5
6
7
8
var buffer =gl.createBuffer();    //创建缓冲区
gl.bindBuffer(gl.ARRAY_BUFFER,buffer);    //绑定到WebGL上下文
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array([0,0.5,1]),gl.STATIC_DRAW);
gl.bufferData()的最后一个参数用于指定使用缓冲区的方式:
gl.STATIC_DRAW:数据只加载一次,在多次绘图中使用。
gl.STREAM_DRAW:数据只加载一次,在几次绘图中使用。
gl.DYNAMIC_DRAW:数据动态改变,在多次绘图中使用。

使用gl.deleteBuffer()释放内存。

6.错误
WebGL操作一般不会抛出错误,为了知道是否有错误发生,必须在调用某个可能出错的方法后,手工调用gl.getError()。

7.着色器
WebGL中有两种着色器:顶点着色器和片段(或像素)着色器。
顶点着色器用于将3D顶点转换为需要渲染的2D点。
片段着色器用于准确计算要绘制的每个像素的颜色。
着色器是用GLSL语言编写的。

8.编写着色器

9.编写着色器程序

10.为着色器传入值

11.调试着色器和程序

12.绘图
WebGL只能绘制三种形状:点、线和三角
执行绘图操作要调用gl.drawArrays()或gl.drawElements()方法,前者用于数组缓冲区,后者用于元素数组缓冲区。
gl.drawArrays()或gl.drawElements()的第一个参数都是一个常量,表示要绘制的形状,常量取值如下:
gl.POINTS:将每个顶点当成一个点来绘制。
gl.LINES:将数组当成一系列顶点,在这些顶点间画线。每个顶点既是起点也是终点,因此数组中必须包含偶数个顶点。
gl.LINE_LOOP:将数组当成一系列顶点,在这些顶点间画线。最后一个顶点画到第一个顶点,形成一个形状的轮廓。
gl.LINE_STRIP:除了不花最后一个顶点与第一个顶点之间的线之外,其他与gl.LINE_LOOP相同。
gl.TRIANGLES:将数组当成一系列顶点,在这些顶点间画三角形。
gl.TRIANGLES_STRIP:除了前三个顶点之后的顶点当作第三个顶点与前两个顶点共同构成一个新三角形外,其他与gl.TRIANGLES相同。
gl.TRIANGLES_FAN:除了前三个顶点之后的顶点当作第三个顶点与前一个顶点及第一个顶点共同构成一个新三角形外,其他与gl.TRIANGLES相同。例如,数组中有A、B、C、D四个顶点,则第一个是三角形连接ABC,第二个三角形连接BCD。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//假设已经使用了着色器请处理视口
//定义三个顶点以及每个顶点的x 和y 坐标
var vertices = new Float32Array([0,1,1,-1,-1,-1]),
       buffer = gl.createBuffer(),
       vertexSetSize = 2,
       vertexSetCount = vertices.length/vertexSetSize,
       uColor,aVertexPosition;
//把数据放到缓冲区
gl.bindBuffer(gl.ARRAY_BUFFER,buffer);
gl.bufferData(gl.ARRAY_BUFFER,vertices,gl.STATIC_DRAW);
//为片段着色器传入颜色值
uColor = gl.getUniformLocation(program,"uColor");
gl.uniform4fv(uColor,[0,0,0,1]);
//为着色器传入顶点信息
aVertexPosition = gl.getAttribLocation(program,"aVertextPosition");
gl.enableVertexAttribArray(aVertexPosition);
gl.vertexAttribPointer(aVertexPosition,vertexSetSize,gl.FLOAT,false,0,0);
//绘制三角形
gl.drawArrays(gl.TRIANGLES,0,vertexSetCount);

13.纹理
WebGL的纹理可以使用DOM中的图像。
调用gl.createTexture()创建一个新纹理。

1
2
3
4
5
6
7
8
9
10
11
12
13
var image = new Image(),texture;
image.src="simple.gif";
iimage.onload = function(){
    texture = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D,texture);
    gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,true);
    
    gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,gl.RGBA,gl.UNSIGNED,image);
    gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.NEAREST);
    gl.textParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.NEAREST);    
    //清除当前纹理
    gl.bindTexture(gl.TEXTURE_2D,null);
};

14.读取像素
通过gl.readPixels()方法读取像素。

坚持原创技术分享,您的支持将鼓励我继续创作!