1.Working with Image Data
+①
var drawing=document.getElementById('drawing');
//确定浏览器支持<canvas>元素
if(drawing.getContext){
var context=drawing.getContext('2d'),
//获取文档中第一张图像
image=document.images[0],
imageData,data,i,len,average,
red,green,blue,alpha;
//绘制原始图像,起始坐标(0,0)
context.drawImage(image,0,0);
//获取图像数据,起始坐标(0,0),大小(宽度+高度)
imageData=context.getImageData(0,0,image.width,image.height);
//图像数据的data属性是一个数组,保存着图像中每一个像素的数据---r,g,b,alpha
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);
}
2.Compositing(合成)
+①globalAlpha属性
var drawing=document.getElementById('drawing');
if(drawing.getContext){
var context=drawing.getContext('2d');
context.fillStyle='#f00';
context.fillRect(10,10,50,50);
//修改全局透明度
context.globalAlpha=0.3;
context.fillStyle='rgba(0,0,255,0.8)';//alpha:0.8被全局透明度覆盖
context.fillRect(30,30,50,50);
//重置全局透明度
context.globalAlpha=0.8;
context.fillStyle='#f8a303';
context.fillRect(50,50,50,50);
}
@*8+②globalCompositeOperation属性
var drawing=document.getElementById('drawing');
if(drawing.getContext){
var context=drawing.getContext('2d');
//1
context.fillStyle='#f00';
context.fillRect(10,10,50,50);
context.fillStyle='rgba(0,0,255,0.5)';
context.fillRect(30,30,50,50);
//2
context.fillStyle='#f00';//source
context.fillRect(100,10,50,50);
//后绘制的图形---source || 先绘制的图形----destination
context.globalCompositeOperation='source-over';
context.fillStyle='rgba(0,0,255,0.5)';
context.fillRect(120,30,50,50);
/*
//3
context.fillStyle='#f00';//source
context.fillRect(200,10,50,50);
context.globalCompositeOperation='source-in';
context.fillStyle='rgba(0,0,255,0.5)';
context.fillRect(220,30,50,50);
*/
/*
//4
context.fillStyle='#f00';//source
context.fillRect(300,10,50,50);
context.globalCompositeOperation='source-out';
context.fillStyle='rgba(0,0,255,0.5)';
context.fillRect(320,30,50,50);
*/
/*
//5
context.fillStyle='#f00';//source
context.fillRect(400,10,50,50);
context.globalCompositeOperation='source-atop';
context.fillStyle='rgba(0,0,255,0.5)';
context.fillRect(420,30,50,50);
*/
//6
context.fillStyle='#f00';//source
context.fillRect(10,100,50,50);
context.globalCompositeOperation='destination-over';
context.fillStyle='rgba(0,0,255,0.5)';
context.fillRect(30,120,50,50);
/*
//7
context.fillStyle='#f00';//source
context.fillRect(100,100,50,50);
context.globalCompositeOperation='destination-in';
context.fillStyle='rgba(0,0,255,0.5)';
context.fillRect(120,120,50,50);
*/
/*
//8
context.fillStyle='#f00';//source
context.fillRect(200,100,50,50);
context.globalCompositeOperation='destination-out';
context.fillStyle='rgba(0,0,255,0.5)';
context.fillRect(220,120,50,50);
*/
/*
//9
context.fillStyle='#f00';//source
context.fillRect(300,100,50,50);
context.globalCompositeOperation='destination-atop';
context.fillStyle='rgba(0,0,255,0.5)';
context.fillRect(320,120,50,50);
*/
//10
context.fillStyle='#f00';//source
context.fillRect(400,100,50,50);
context.globalCompositeOperation='destination-lighter';//source图形与destination图形重叠部分的值相加,使该部分变得更亮
context.fillStyle='rgba(0,0,255,0.5)';
context.fillRect(420,120,50,50);
/*
//11
context.fillStyle='#f00';//source
context.fillRect(500,100,50,50);
context.globalCompositeOperation='copy';//只有source图形
context.fillStyle='rgba(0,0,255,0.5)';
context.fillRect(520,120,50,50);
*/
//12
context.fillStyle='#f00';//source
context.fillRect(10,200,50,50);
context.globalCompositeOperation='xor';//source图形与destination图形重叠部分进行"异或"操作。
context.fillStyle='rgba(0,0,255,0.5)';
context.fillRect(30,220,50,50);
}
source-over[standard]
souce-in
source-out
source-atop
destination-in
destination-out
destination-atop
xor
3.Typed Arrays
+①Views
//在内存中分配20B
var buffer=new ArrayBuffer(20);
var bytes=buffer.byteLength;
//基于整个数组缓冲器创建一个新视图
var view=new DataView(buffer);
//创建一个开始于字节9的新视图
var view=new DataView(buffer,9);
//创建一个从字节9开始到字节18的视图[9+10-1=18]--10是一段字节长度
var view=new DataView(buffer,9,10);
//实例化后,DataView对象会把字节偏移量和字节长度分别保存在byteOffset和byteLength属性中
alert(view.byteOffset);
alert(view.byteLength);
②小端(littleEndian):把数据的最低有效位保存在低内存地址中。
③类型化视图,也成类型化数组,因此它们除了元素必须是某种特定的数据类型外,与常规数组一样。继承自DataView。
+④能够指定缓冲器中可用的字节段,意味着能在同一个缓冲器中保存着不同类型的数值。
//使用缓冲器的一部分保存8位整数,另一部分保存16位整数
var int8s=new Int8Array(buffer,0,10);
var uint16s=new Uint16Array(buffer,11,10);
+⑤每个视图构造函数都有一个名为BYTES_PER_ELEMENT的属性,表示类型化数组的每个元素需要多少字节。
//需要10B
var int8s=new Int8Array(buffer,0,10*Int8Array.BYTES_PER_ELEMENT);
//在int8s之后再来5*2B=10B
var uint16s=new Uint16Array(buffer,int8s.byteOffset+int8s.byteLength,
5*Uint16Array.BYTES_PER_ELEMENT);
+⑥创建类型化视图还可以不同首先创建ArrayBuffer对象,只要传入希望数组保存的元素数,相应的构造函数就可以自动创建一个包含足够字节数的ArrayBuffer对象。
//创建一个数组保存10个8位整数(10B)
var int8s=new Int8Array(10);
//等价于
var buffer=new ArrayBuffer(20);
var int8s=new Int8Array(buffer,0,10);//0--byteOffset || 10---byteLength
//another one--创建一个数组保存着8个16位整数(16B)
var int16s=new int16Array(8);
//创建一个数组保存着5个8位整数(5B)
var int8s=new Int8Array([1,2,3,4,5]);
var uint16s=new Uint16Array(10);
uint16s[0]=65589;
console.log(uint16s[0]);//53---65589-2^16
+⑦类型化视图(数组)还有一个方法:subarray()—基于底层数组缓冲器的子集创建一个新视图。
var uint16s=new Uint16Array(10);
var sub=uint16s.subarray(2,5);//sub也是Uint16Array的一个实例
4.WebGL:Graphics Library
+①可以为getContext()传递第二个参数,该参数为WebGL上下文设置一些选项。这个参数本身是一个对象,可以包含如下属性:
a)alpha:值为true,表示为上下文创建一个Alpha通道缓冲区;默认值为true。
b)depth:值为true,表示可以使用16位深缓冲区;默认值为true。
c)stencil:值为true,表示可以使用8位模板缓冲区;默认值为false。
d)antialias:值为true,表示将使用默认机制执行抗锯齿操作;默认值为true。
e)premultipledAlpha:值为true,表示绘图缓冲区有预乘Alpha值;默认值为true。
f)preserveDrawingBuffer:值为true,表示在绘图完成后保留绘图缓冲区;默认值为false。【影响性能】
var drawing=document.getElementById('drawing');
if(drawing.getContext){
var gl=drawing.getContext('experimental-webgl',{alpha : false});
if(gl){
//using WebGL
}
}
//保险起见,将其封装到一个try-catch块中
var drawing=document.getElementById('drawing');
if(drawing.getContext){
try{
gl=drawing.getContext('experimental-webgl');
}catch(ex){
//do nothing
}
if(gl){
//using WebGL
}else{
alert('WebGL context could not be created.');
}
}
+②Error
var errorCode=gl.getError();
while(errorCode){
console.log('Error occurred: ' + errorCode);
errorCode=gl.getError();
}
③Shader(着色器):是使用GLSL(OpenGL Shading Language)OpenGL着色语言写的。
a)顶点着色器:将3D顶点转换为需要渲染的2D点。
b)片段(像素)着色器:用于精确计算要绘制的每个像素的颜色。
+④Creating Shader Programs:GLSL cannot be natively understood by a browser,so you must have a string of GLSL ready for compilation(编译) and linking(链接) into a shader program.For ease of use,shaders are typically included in a page using
/*
1.编写着色器(获得GLSL字符串),嵌入<script>元素,通过text属性提取。
2.创建着色器对象,将GLSL字符串传递给该对象,并编译该对象。
3.创建着色器程序,将对象链接到该程序,最后通知WebGL使用该程序。
*/
//【1】
<script type="x-webgl/x-vertex-shader" id='vertexShader'>//顶点着色器
attribute vec2 aVectexPosition; //关键字|数组(包含2个元素)|变量名
void main(){
gl_Position = vec4(aVectexPosition,0,0 , 1.0);
}
</script>
<script type="x=webgl/x-fragment-shader" id='fragmentShader'>//片段着色器
uniform vec4 uColor;
void main(){
gl_FragColor = uColor;
}
</script>
//通过text属性提取出<script>元素中的内容
var vertexGlsl=document.getElementById('vertexShader').text,
fragmentGlsl=document.getElementById('fragmentShader').text;
//【2】创建两个着色器,分别保存在vertexShader和fragmentShader中
var vertexShader = gl.createShader(gl.VERTEX_SHADER);//着色器类型:gl.VERTEX_SHADER || gl.FRAGMENT_SHADER
gl.shaderSource(vertexShader,vertexGlsl);//字符串传递
gl.compileShader(vertexShader);//编译着色器
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader,fragmentGlsl);
gl.compileShader(fragmentShader);
//【3】将两个对象链接到着色程序中
var program=gl.createProgram();//创建程序
//调用attachShader()方法包含了两个着色器
gl.attachShader(program,vertexShader);
gl.attachShader(program,fragmentShader);
//调动gl.linkProgram()方法把两个着色器封装到变量program中
gl.linkProgram(program);
//通过gl.useProgram()方法通知WebGL使用这个程序
gl.useProgram(program);
+⑤为着色器传入值
//Attribute变量
var aVectexPosition=gl.getAttribLocation(program,'aVectexPosition');
gl.enableVertexAttribArray(aVectexPosition);
gl.vertextAttribPointer(aVectexPosition,itemSize,gl.FLOAT,false,0,0);
//Uniform变量
var uColor=gl.getUniformLocation(program,'uColor');
gl.uniform4fv(uColor,[0,0,0,1]);
+⑥调试着色器和程序
//用于检测编译状态
if(!gl.getShaderParameter(vertexShader,gl.COMPILE_STATUS)){
alert(gl.getShaderInfoLog(vertexShader));//错误消息是一个表示问题所在的字符串
}
//用于检测执行状态
if(!gl.getProgramParameter(program,gl.LINK_STATUS)){
akert(gl.getProgramInfoLog(program));
}