效果较差:较于桌面开发API:Direct3D、OpenGL、UE、Unity。
开发成本:熟悉并掌握一定的数据知识,例如:线性代数。
硬件要求:开发及部署系统硬件要求较高,尤其GPU。
物理知识、{HTML、CSS、JavaScript、计算机图形学}、数学基础
网站:
课程:
书籍:
canvas的坐标系如下图,其中canvas坐标的单位都是“px”
WebGL坐标系如下图,WebGL使用的是正交右手坐标系,每个方向可使用的值的区间都是(-1,1),超出该矩形区间的图像不会绘制。这些值与Canvas的尺寸无关,无论Canvas的长宽比是多少,WebGL的区间值都是一致的。
渲染管线就像一条流水线,由一系列具有特定功能的数字电路单元组成,下一个功能单元处理上一个功能单元生成的数据,逐级处理数据。
顶点着色器和片元着色器是可编程的功能单元,拥有更大的自主性,还有光栅器、深度测试等不可编程的功能单元。
CPU会通过WebGL API和GPU通信,传递着色器程序和数据:
顶点缓冲区:形状的坐标信息。待加工的数据/数组,将这组数据给到程序,就可以进行处理。
uniform数据:shader里面的数据,把“顶点缓冲区”的数据传递给“顶点着色器”。
图元装配:这些顶点缓冲区用来干什么?做“方便面”。
光栅器:矢量的图形转换成像素图形。
片元着色器:把颜色/纹理加到光栅化后的像素上。
归属测试/模板测试、深度测试(3D):绘制前的测试。
(1)顶点着色器
GPU渲染管线上一个可以执行着色器语言的功能单元,具体执行的就是顶点着色器程序。
WebGL顶点着色器程序在JavaScript中以字符串的形式存在,通过编译处理后传递给顶点着色器执行。
总结:顶点着色器主要作用就是执行顶点着色器程序对顶点进行变换计算。例如顶点位置坐标进行旋转、平移等矩阵变换,变换后新的顶点坐标然后赋值给内置变量gl_Position,作为顶点着色器的输出,图元装配和光栅化环节的输入。
(2)图元装配
硬件上具体怎么回事不用思考,从程序的角度来看,就是绘制函数drawArrays()或drawElements()第一个参数绘制模式mode控制顶点如何装配为图元:
(3)光栅化
分解成一些小的像素。
片元着色器
片元着色器和顶点着色器一样是GPU渲染管线上一个可以执行着色器程序的功能单元。顶点着色器处理的是逐顶点处理顶点数据,片元着色器是逐片元处理片元数据。
通过给内置变量gl_fragColor赋值可以给每一个片元进行着色,值可以是一个确定的RGBA值,可以是一个和片元位置相关的值,也可以是插值后的顶点颜色。
除了给片元进行着色外,通过关键字discard还可以实现哪些片元可以被丢弃,被丢弃的片元不会出现在帧缓冲区,自然不会显示在canvas画布上。
蓝色:屏幕坐标系
绿色:canvas坐标系
最里面是:WebGL坐标系,坐标范围是(-1,1)
(1)drawArrays()
POINTS
LINES LINE_STRIP LINE_LOOP
TRIANGLES TRIANGLE_STRIP TRIANGLES_FAN
(2)drawElements()
好处:当大量数据时,顶点缓冲区数据量很大时,内存会受到限制。使用索引缓冲区,可以节省内存,重复利用点。
用法:需要创建一个索引缓冲区
TypeArray数组最大的作用:提升数组的性能。浏览器事先知道数组中的数据类型,故而处理起来更有效率。
JS中Array的内部实现是链表,可以动态增加减少元素,但是元素多时,性能会比较差。当访问某个元素时,需要通过链表一个一个地找下去。
类型化数组管理的是连续内存区域,知道了这块内存的起始位置,可以通过起始位置+N*偏移量(一次加法一次乘法操作)访问到第N个位置的元素。
类型化数组将实现拆分为缓冲和视图两部分。
单精度,也即float,一般在计算机中存储占用4字节,也32位,有效位数为7位;双精度(double)在计算机中存储占用8字节,64位,有效位数为16位。
单精度是这样的格式,1位符号,8位指数,23位小数。 双精度是1位符号,11位指数,52位小数。 含义:表明单精度和双精度精确的范围不一样,
get(index) 、set(index,value)、set(array,offset)、length、BYTES_PER_ELEMENT
createBuffer()方法会在GPU控制的显存上创建一个缓冲区用来存储顶点或顶点索引数据。通过deleteBuffer(buffer)表示:删除某个缓冲区,参数buffer表示顶点/顶点索引缓冲区的名字,也就是执行createBuffer()方法返回的对象变量名。
bindBuffer(target,buffer):target相同,也就是同类缓冲区在同一个时刻只能绑定一个,只有处于绑定状态才能传入数据。
bufferData(target,data,usage):把CPU控制的内存中类型数组传入GPU控制的线程顶点或顶点索引缓冲区。
vertexAttribPointer(location,size,type,normalized,stride,offset)
规定GPU从顶点缓冲区去读取数据的方式,很多时候为了提高顶点数据的传输读取效率,往往会把顶点位置、顶点颜色、顶点法向量、纹理坐标交叉定义在一个类型数组汇总,一次性传入顶点缓冲区中,CPU和GPU不需要多次通信,只需要执行一次bufferData()方法,这时候GPU为了使用顶点缓冲区的不同用于数据,就要按照一定规律读取。
可以在同一个WebGL程序中定义多个该方法,每个方法的参数location分别指向一个不同的顶点变量,然后控制其后面其他的参数。
enableVertexAttribArray(location)
顶点缓冲区和GPU渲染管线之间存在一个硬件单元可以决定GPU是否能读取顶点缓冲区中的顶点数据。关闭方法:disableVertexAttribArray(location),location是顶点着色器程序中顶点变量的索引位置。
createShader:创建着色器对象,参数是着色器类型,标记一个着色器程序会被GPU渲染管线上哪一个着色器执行,
shaderSource:绑定源。把字符串形式的顶点着色器代码、片元着色器代码分配给各自的着色器对象。
compileShader:编译着色器程序。参数指定着色器程序源码。
creatProgram:创建程序对象。程序对象的意义是为了实现CPU和GPU的通信,控制GPU着色器的工作状态,切换不同的着色器程序。
attachShader:绑定着色器对象到一个程序对象上,每个程序对象就关联了一组顶点着色器程序、片元着色器程序。第一个参数表示目标程序对象,第二个参数表示要绑定的着色器对象。
linkProgram:在执行useprogram方法之前,要先链接程序对象program的顶点和片元着色器程序,检查着色器程序的错误(检查顶点、片元着色器程序中同名varying变量是否一一对应;检查顶点着色器程序中是否给varying变量赋值顶点数据;硬件资源有限,要检测attribute\uniform\varying变量的数量是否超出限制范围)。通过链接测试后,才能通过useprogram方法把着色器程序传递给GPU,否则报错。
useProgram:同一时刻GPU只能配置一组顶点、片元着色器程序。当你定义了多个程序对象,分别关联了一组顶点、片元着色器程序,不会同时传递给GPU。在代码中uswProgram的特点是当再次调用方法useProgram,使用新的program程序对象作为新的参数,再次执行绘制函数的时候CPU会与GPU进行通信,给GPU传入新程序对象program对应的顶点、片元着色器程序,这时候就实现了GPU着色器程序的切换,每次切换都会耗费一定的硬件资源,可以简单的类比CPU线程的切换。一般复杂的场景都会编写多套着色器程序,放在文件中,供WebGL程序调用。
drawArrays/drawElements:
mode:gl.POINTS画单独的点;gl.LINE_STRIP画一条直线到下一个顶点;gl.LINE_LOOP绘制一条直线到下一个顶点,并将最后一个顶点返回到第一个顶点;gl.LINES在一对顶点之间画一条线;gl.TRIANGLE_STRIP画一个三角形;gl.TRIANGLE_FAN;gl.TRIANGLES为一组三个顶点绘制一个三角形。
count:渲染的元素数量
type:类型,gl.UNSIGNED_BYTE, gl.UNSIGNED_SHORT, gl.UNSIGNED_INT
offset:偏移量。
02-打印多个向量_哔哩哔哩_bilibili
类似只有一个.cpp,其中有一个main()函数,函数声明等。
WebGL顶点/片段着色器程序在JavaScript中以字符串的形式存在,通过编译处理后传递给顶点/片段着色器执行。
打印方法
(1)console.log
console.log()只能用在js语言中,GLSL ES语言并不支持。
(2)在canvas画布中获取像素数据
通过canvas.getContext()方法获取2d或webgl上下文对象的同时,也决定了canvas画布的命运。
像素中的rgba四个分量相当于片元着色器程序中的vec4的4个数值。
//像素容器
const pixel = new Uint8Array(4);
//抓取像素
webgl.readPixels(500 / 2, 500 / 2, 1, 1, webgl.RGBA, webgl.UNSIGNED_BYTE, pixel);
(3)案例一:画同心圆
var webgl;
//投影坐标系,顶点着色器内置的变量信息
var vertexString = `
void main(void){
gl_Position = vec4(0,0,0,1);
gl_PointSize = 500.0;//和canvasWidth一致
}
`;
var fragmentString = `
precision mediump float;
vec4 vf = vec4(1.0,200.0,3.0,4.0) + vec4(200.0,40.0,5.0,6.0);
void main(){
gl_FragColor = vf/255.0;
}
`;
//入口函数
function init() {
initWebgl();
initShader();
draw();
}
function initWebgl() {
let webglDiv = document.getElementById("webglCanvas");
webgl = webglDiv.getContext("webgl");
}
function initShader() {
//创建
let vsshader = webgl.createShader(webgl.VERTEX_SHADER);
let fsshader = webgl.createShader(webgl.FRAGMENT_SHADER);
//绑定着色器程序
webgl.shaderSource(vsshader, vertexString);
webgl.shaderSource(fsshader, fragmentString);
//编译着色器
webgl.compileShader(vsshader);
webgl.compileShader(fsshader);
//创建项目
let program = webgl.createProgram();
webgl.attachShader(program, vsshader);
webgl.attachShader(program, fsshader);
webgl.linkProgram(program);
webgl.useProgram(program);
webgl.program = program;
}
function draw() {
webgl.clearColor(0.0, 0.0, 0.0, 0.0);//冲刷颜色
webgl.clear(webgl.COLOR_BUFFER_BIT);
webgl.drawArrays(webgl.POINTS, 0, 1);//绘制
//像素容器
const pixel = new Uint8Array(4);
//抓取像素
webgl.readPixels(500 / 2, 500 / 2, 1, 1, webgl.RGBA, webgl.UNSIGNED_BYTE, pixel);
console.log(pixel);
}
运行结果:
(4)案例二:画4个正方形
着色器语言GLSL
(1)概述
(2)基本规范
(1)声明变量的方法
GLSL ES 是强类型语言,在声明变量时应指明变量类型,如:
float f = 1.0;
int i = 1;
bool b = true;
(2)变量命名规范
(3)变量的赋值
变量使用等号赋值,变量两侧的数据类型需要保持一致。
int i = 9; //√
int i = 9.0; //×
float f = 9; //×
float f = 9.0; //√
报错提示:
(4)变量的类型转换
float f = float(8);
(1)创建向量
GLSL ES支持2、3、4维向量,根据分量的数据类型,向量可以分为3类:
创建向量,GLSL ES提供了非常灵活的创建方式:
//创建单个向量
vec3 v3 = vec3(1.0,2.0,3.0);//(1.0,2.0,3.0)
vec2 v2 = vec2(v3);//(1.0,2.0)
vec4 v4 = vec4(1.0);//(1.0,1.0,1.0,1.0)
//将多个向量合在一起
vec4 v4b = vec4(v2,v4);//(1.0,2.0,1.0,1.0)
//注意,等号左右两侧的类型应该一致。
vec4 v4 = vec2(1.0);//×
(2)向量分量的访问
v4.x、v4.y、v4.z、v4.w //齐次坐标
v4.r、v4.g、v4.b、v4.a //色值
v4.s、v4.t、v4.p、v4.q //纹理坐标
vec4 v4 = vec4(1.0,2.0,3.0,4.0);
v4.xy //(1.0,2.0)
v4.yx //(2.0,1.0)
v4.xw //(1.0,4.0)
v4[0]、v4[1]、v4[2]、v4[3]
v4.x = 2.0;
v4[0] = 1.0
v4.xy = vec2(211.0,233.0);
(1)矩阵类型
GLSL ES 支持2、3、4维矩阵:
矩阵中的元素都是浮点型。
(2)矩阵的建立
GLSL ES中的矩阵是列主序的,在建立矩阵的时候,其参数结构有很多种。
vec4 v4_1 = vec4(1,2,3,4);
vec4 v4_2 = vec4(10,20,30,40);
vec4 v4_3 = vec4(101,201,301,401);
vec4 v4_4 = vec4(0,202,302,40);
mat4 mf = mat4(
v4_1,
v4_2,
v4_3,
v4_4);
mat4 mf2 = mat4(
v4_1,
v4_2,
1,2,3,4,
3,4,5,6);
//单位矩阵
mat4 mf3 = mat4(1);
//报错
mat4 mf4 = mat4(1.9,3.0);//报错
(3)矩阵的访问
vec4 v4_1 = vec4(1,2,3,4);
vec4 v4_2 = vec4(10,20,30,40);
vec4 v4_3 = vec4(101,201,301,401);
vec4 v4_4 = vec4(0,202,302,40);
mat4 mf = mat4(
v4_1,
v4_2,
v4_3,
v4_4);
//访问某行
mf(0);//1,2,3,4
//访问某个元素
mf[3][1];//202
//m[x]可以理解为一个向量,其内部的元素,可以像访问向量元素一样去访问。
mf[0].x;//1
(4)矩阵运算
矩阵可以与以下数据进行各种运算:
vec4 v4_1 = vec4(1,2,3,4);
vec4 v4_2 = vec4(10,20,30,40);
vec4 v4_3 = vec4(101,201,301,401);
vec4 v4_4 = vec4(0,202,302,40);
mat4 mf = mat4(
v4_1,
v4_2,
v4_3,
v4_4);
//与单个数字运算
mf += 1;//矩阵中的所有元素都加1
//矩阵和矩阵的运算
mat4 mf1 = mat4(
1,2,3,4,
5,6,7,8,
4,5,6,7,
7,8,9,0);
//矩阵加法:相同索引位置的元素相加
//矩阵减法:相同索引位置的元素相减
//矩阵除法:相同索引位置的元素相除
//矩阵乘法:点积运算 c[0][0] = a[0][0]*b[0][0] + a[0][1]*b[1][0] +a[0][2]*b[2][0]+a[0][3]*b[3][0]
类似于js里的构造函数,只是语法规则不一样。
(1)创建struct
struct Light{
vec4 color;
vec3 pos;
};
color 和 pos 既是结构体的属性,也是其形参。
(2)struct的实例化
Light l1 = Light (
vec4(3,4,5,6),
vec3(1,2,3)
);
上面的vec4()和vec3()数据是结构体的实参,分别对应color属性和pos属性。
(3)访问struct实例对象中的属性
gl_FragColor = l1.color/255.0;
GLSL ES中数组的特性:
在建立某个类型的数组时,在数据类型后面加[]即可,[]中要写数组的长度:
vec4 vs[2];
vs[0] = vec4(1,2,3,4);
vs[1] = vec4(5,6,7,8);
GLSL中的if判断判断和js里if写法一致。都有if、else if、else判断。注意:if语句写太多会降低着色器的执行速度,但GLSL中没有switch语句,要注意。
GLSL中的for循环和js类似:
var fragmentString = `
precision mediump float;
vec4 v4_1 = vec4(1,2,3,4);
vec4 v4_2 = vec4(10,20,30,40);
vec4 v4_3 = vec4(101,201,301,401);
vec4 v4_4 = vec4(0,202,302,40);
struct Light{
vec4 color;
vec3 pos;
};
void main(){
Light l1 = Light (
vec4(3,4,5,6),
vec3(1,2,3)
);
mat4 mf = mat4(v4_1,v4_2,v4_3,l1.color);
float dist = distance(gl_PointCoord,vec2(0.5,0.5));
for(int i = 0; i<4; i++)
{
float r1=0.125 * float(i);
float r2=r1 + 0.125;
if(dist>= r1 && dist < r2){
gl_FragColor=mf[i]/255.0;
break;
}else if (i==3){
discard;
}
}
} `;
每个像素赋值后需要break结束循环。
返回值类型 函数名(形参){
函数内容;
return 返回值;
}
float getNum(vec3 color){
return dot(color,vec3(0.2126,0.7162,0.0722));//点积运算
}
void getNum(in vec3 color){
color.x = 0.0;
}
void getNum(out vec3 color){
color.x = 0.0;
}
void getNum(const in vec3 color){
color.x = 0.0; // 报错,不可修改
}
GLSL ES中有许多内置方法。例如sin,cos,tan,atan等。
可以通过函数或{}建立块级作用域,块级作用域内建立的变量都是局部变量。局部变量只在块级作用域内有效。
在函数之外建立的变量就是全局变量。
在代码块内可以直接获取其父级定义域的变量。
变量不存在“变量提升” 现象,变量在使用时,需提前声明。
变量不能重复声明。
通过attribute、uniform、varying限定字声明的变量都是全局变量。
const可以声明常量,常量是只读的。
webgl提供了三种精度:
一般中精度用得比较多,因为高精度太耗性能,而且有时候片元着色器不支持。
mediump float size;
high vec4 position;
lowp vec4 color;
precision mediump float;
precision highp int;
着色器中,除了片元着色器的float数据没有默认精度,其他的数据都有默认精度。
因此在片元着色器中要提前声明好浮点类的精度。
着色器语言和C语言一样,通过一个表示特定数据类型的关键字声明一个变量,比如 int num,通过int 关键字声明一个整数型变量num,不过着色器语言还提供了三个关键字attribute、uniform和varying用来声明特定用途的变量。
attribute和uniform关键字目的:
为了javascript语言/C++语言可以通过相关的WebGL API把一些数据传递给着色器。
关键字(变量类型) | 数据传递 | 声明变量 |
attribute | javascript -> 顶点着色器 | 声明顶点数据变量 |
uniform | javascript -> 顶点、片元着色器 | 声明非顶点数据变量 |
varying | 顶点着色器 -> 片元着色器 | 声明需要差值计算的顶点变量 |
(1)attribute类型变量
attribute关键字通常用来声明与顶点数据相关的变量,比如顶点位置坐标数据、顶点颜色数据、顶点法向量数据等。
因为javascript没必要给片元着色器传递顶点数据,所以规定attribute
关键字只能在顶点着色器中声明变量使用。只要注意attribute
关键字声明顶点变量代码位于主函数main
之外就可以。
//attribute声明顶点位置变量
attribute vec4 position;
//attribute声明顶点颜色变量
attribute vec4 a_color;
//attribute声明顶点法向量
attribute bec4 normal;
//与顶点相关的浮点数
attribute float scale;
void main(){
gl_Position = vec4(position.x * scale, position.y, position.z, 1.0);
}
(2)uniform类型变量(非顶点类型)
uniform是为了javascript通过相关的WebGL API给着色器变量传递数据,比如传递一个光源的位置数据、一个光源的方向数据、一个光源的颜色数据、一个用于顶点变换的模型矩阵、一个用于顶点变换的视图矩阵。一般用在片元着色器中。
不过要注意如果是顶点相关的变量,比如顶点位置、顶点颜色等顶点数据相关变量不能使用关键字uniform去声明,主要是顶点的数据往往不是一个,通常有很多个顶点,而且这些顶点都要逐顶点执行main函数中的程序,所以为了声明顶点数据相关的变量,着色器语言规定了一个新的关键字attribute。
javascript可以给顶点着色器的变量传递数据,也可以给片元着色器的变量传递数据,也就是说uniform
关键字既可以在顶点着色器中使用,也可以在片元着色器中使用。只要注意uniform
关键字声明变量需要在主函数main
之前声明。
var fragmentString = '
precision mediump float;
uniform vec4 u_Color;
void main(){
gl_FragColor=u_Color;
}';
(3)varying类型变量
如果在顶点着色器中声明了一个顶点的颜色变量,如果想在片元着色器中获得顶点颜色插值计算以后的数据,需要同时在顶点着色器和片元着色中声明插值后的颜色数据。varying vec4 v_color。
顶点着色器
attribute vec4 a_color;//attribute声明的顶点颜色变量
varying vec4 v_color;//varying声明顶点颜色插值后的变量
void main(){
v_color = a_color;//顶点颜色插值计算
}
片元着色器
varying vec4 v_color;//接收顶点着色器中v_color数据
void main(){
gl_FragColor = v_color;//插值后颜色数据赋值给对应的片元
}
变量attribute,注意a_Position大小写敏感。
var vertexString = `
attribute vec4 a_Position;
void main(){
gl_Position = a_Position;
}
`;
着色器语言在GPU的着色器单元执行,javascript语言、C语言在CPU上执行。
普通变量,着色器语言和javascript语言一样需要先声明后使用,所谓内置变量就是不用声明可以直接赋值,主要是为了实现特定的功能。
内置变量 | 含义 | 值数据类型 |
gl_PointSize | 点渲染模式,方形点区域渲染像素大小 | float |
gl_Position | 顶点位置坐标 | vec4 |
gl_FragColor | 片元颜色值 | vec4 |
gl_FragCoord | 片元坐标,单位像素 | vec2 |
gl_PointCoord | 点渲染模式对应点像素坐标 | vec2 |
(1)点像素大小gl_PointSize
当WebGL执行绘制函数gl.drawArrays()
绘制模式是点模式gl.POINTS
的时候,顶点着色器语言main
函数中才会用到内置变量gl_PointSize
,使用内置变量gl_PointSize
主要是用来设置顶点渲染出来的方形点像素大小。
顶点着色器
void main(){
gl_PointSize = 20.0;//赋值像素大小,注意为浮点数
}
绘制代码
gl.drawArrays(gl.POINTS,0,点数量);//绘制函数绘制模式:点模式gl.POINTS
(2)顶点坐标gl_Position
gl_Position
内置变量主要和顶点相关,出现的位置是顶点着色器语言的main
函数中。gl_Position
内置变量表示最终传入片元着色器片元化要使用的顶点位置坐标。
void main() {
//顶点位置,位于坐标原点
gl_Position = vec4(0.0,0.0,0.0,1.0);
}
内置变量gl_Position
的值是四维向量vec4(x,y,z,1.0)
,前三个参数表示顶点的xyz坐标值,第四个参数是浮点数1.0
。
多个顶点的时候,内置变量gl_Position
对应的值是attribute
关键字声明的顶点位置坐标变量apos
,顶点位置坐标变量apos
变量对应了javascript代码中多个顶点位置数据。
如果你想完全理解内置变量gl_Position
,必须建立逐顶点
的概念,如果javascript语言中出现一个变量赋值,你可以理解为仅仅执行一次,但是对于着色器中不能直接这么理解,如果有多个顶点,你可以理解为每个顶点都要执行一遍顶点着色器主函数main
中的程序。
着色器源码
//矩阵变换
顶点数据传递
(3)片元颜色gl_FragColor
用来设置片元像素的颜色。内置变量gl_FragColor
的值是四维向量vec4(r,g,b,a)
,前三个参数表示片元像素颜色值RGB,第四个参数是片元像素透明度A,1.0
表示不透明,0.0
表示完全透明。
对于内置变量gl_FragColor
而言,需要建立逐片元
的概念。顶点经过片元着色器片元化以后,得到一个个片元/或者说像素点,然后通过内置变量gl_FragColor
给每一个片元设置颜色值,所有片元可以使用同一个颜色值,也可能不是同一个颜色值,可以通过特定算法计算或者纹理像素采样。
void main() {
gl_FragColor = vec4(gl_FragCoord.x/500.0*1.0,1.0,0.0,1.0);// 片元沿着x方向渐变
}
varying vec2 v_TexCoord;// 接收插值后的纹理坐标
uniform sampler2D u_Sampler;// 纹理图片像素数据
void main() {
gl_FragColor = texture2D(u_Sampler,v_TexCoord); // 采集纹素,逐片元赋值像素值
}
(4)片元坐标gl_FragCoord
内置变量gl_FragCoord表示WebGL在canvas画布上渲染的所有片元或者说像素的坐标,坐标原点是canvas画布的左上角,x轴水平向右,y竖直向下,gl_FragCoord坐标的单位是像素,gl_FragCoord的值是vec2(x,y),通过gl_FragCoord.x、gl_FragCoord.y方式可以分别访问片元坐标的纵横坐标。
(5)渲染点片元坐标gl_PointCoord
绘制函数gl.drawArrays()
绘制模式参数设置为点渲染模式gl.POINTS
,WebGL会把顶点渲染为一个方形区域。
一个顶点渲染为一个方形区域,每个方形区域可以以方向区域的左上角建立一个直角坐标系,然后使用内置变量gl_PointCoord描述每个方形区域中像素或者说片元的坐标,比如方形区域的左上角坐标是(0.0,0.0),每个方形区域几何中心坐标是(0.5,0.5),右下角坐标是(1.0,1.0)。
应用案例:片元着色器代码设置可以把默认渲染效果更改为圆形区域。
平移:
x = x + dx;
y = y + dy;
z = z;
旋转:
x = x * cosp - y * sinp;
y = x * sinp + y * cosp;
z = z;
缩放:
x = x * 2;
y = y * 2;
z = z;
代码示例:
//片段着色器程序
var vertexString = `
attribute vec3 a_position;
uniform float angle;
void main(void){
gl_Position = vec4(a_position.x*cos(angle) -a_position.y*sin(angle),a_position.x*sin(angle) + a_position.y*cos(angle),a_position.z,1.0);
gl_PointSize = 60.0;
}
`;
//angle的赋值
let uAngle = webgl.getUniformLocation(webgl.program, "angle");
let angle = 0 * Math.PI / 180;
webgl.uniform1f(uAngle, angle);
requestAnimationFrame:
window.requestAnimFrame = (function(){return
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback){window.setTimeout(callback,1000/60);} ;
})();
webgl旋转
(1)纹理理论
createTexture:创建纹理
bindTexture:绑定纹理,告诉WebGL把本地加载的纹理绑定到WebGL
texImage2D:加载纹理图像,配置属性信息
texParameteri:配置纹理参数,纹理要展示什么效果
activeTexture:激活纹理(选择哪个纹理进行显示)
bindTexture:绑定纹理
uniform1i:给纹理赋值
(2)单纹理绘制