WebGL
可供参考的链接:
MDN:https://developer.mozilla.org/zh-CN/docs/Web/API/WebGL2RenderingContext
网站:https://webglfundamentals.org/webgl/lessons/zh_cn/
初步介绍
-
绘制流程:页面添加canvas元素 - 获取webgl对象 - 清空屏幕 - 设置好着色器等 - 绘制
-
页面添加canvas元素
<canvas id="canvas" width="400" height="400"></canvas>
-
获取webgl对象
var canvas = document.getElementById('canvas'), //绘制canvas webgl = canvas.getContext('webgl'); //获取webgl
-
清空屏幕
webgl.clearColor(0.043,0.5,0.2,1.0); //使用一种颜色清空之前的颜色 webgl.clear(webgl.COLOR_BUFFER_BIT); //使用clear填入进去
-
-
着色器
使用的是glsl es语言
-
顶点着色器(vertex shader)
是指二维或二维空间的一个点,比如二维或二维空间线与线之间的交叉点或端点
-
片元着色器(fragment shader)
可以将其理解为像素
-
着色器变量类型
attribute
:属性,传输与顶点相关的数据 - 顶点uniform
:全局变量,传输所有顶点都相同的数据 - 片元varying
:可变量,从顶点着色器向片元着色器传输数据 - 顶点向片元传输数据 -
着色器的设置
定义着色器字符串 - 创建着色器对象并绑定好对应的着色器字符串 - 创建着色器程序并添加前面创建的着色器对象 - 把着色起程序链接成一个完整的程序并使用它
-
定义着色器字符串
var vs_source = ` void main() { //vec4中表示内容的大小 只能是0-1的范围 是float类型 gl_Position = vec4(0.5, 0.0, 1.0, 1.0); //设置位置 gl_PointSize = 20.0; //设置尺寸 } `; //片元着色器 var fs_source = ` void main(){ gl_FragColor = vec4(0.78,0.0,1.0,1.0); } `;
-
创建着色器对象并绑定好对应的着色器字符串
//创建顶点着色器容器 var vertexShader = webgl.createShader(webgl.VERTEX_SHADER); //将着色器容器与资源绑定 webgl.shaderSource(vertexShader, vs_source); //编译顶点着色器 webgl.compileShader(vertexShader); //片元着色器的容器创建 绑定 编译 var fragmentShader = webgl.createShader(webgl.FRAGMENT_SHADER); webgl.shaderSource(fragmentShader, fs_source); webgl.compileShader(fragmentShader);
-
创建着色器程序并添加前面创建的着色器对象
//创建着色器程序 var glProgram = webgl.createProgram(); //添加到着色器程序中 webgl.attachShader(glProgram,vertexShader); webgl.attachShader(glProgram,fragmentShader);
-
把着色起程序链接成一个完整的程序并使用它
webgl.linkProgram(glProgram); webgl.useProgram(glProgram);
-
绘制
webgl.drawArrays(webgl.POINTS,0,1);
-
-
注意点:
-
关于着色器对象的定义有两种方式
在使用第二种方式进行定义时,要注意一句话的结尾 必须加上;
方式1: <script type="x-sharder/x-vertex" id="shader-vx"> void main() { //vec4中表示内容的大小 只能是0-1的范围 是float类型 gl_Position = vec4(0.5, 0.0, 1.0, 1.0); //设置位置 gl_PointSize = 20.0; //设置尺寸 } </script> <!-- 片元着色器 --> <script type="x-sharder/x-fragment" id="sharder-fs"> void main(){ //设置片元颜色 类似于rgba 最后为透明度 前面在webgl中也是从0-1 对应0-255 gl_FragColor = vec4(0.78,0.0,1.0,1.0); } </script> 方式2: var vs_source = ` attribute vec4 a_Position; attribute float a_PointSize; void main(){ gl_Position = a_Position; gl_PointSize = a_PointSize; } `; //片元着色器 var fs_source = ` void main(){ gl_FragColor = vec4(0.78,0.0,1.0,1.0); } `;
-
可以设置变量 来动态改变点的位置、大小
var vs_source = ` attribute vec4 a_Position; //声明一个变量 变量名可随便赋值 attribute float a_PointSize; //注意声明变量的类型 要与之后所传递值的类型对应 void main(){ gl_Position = a_Position; gl_PointSize = a_PointSize; } `; 在绘制点之前进行赋值 //获取attribute变量的存储位置,返回对应的地址信息 var aPosition = webgl.getAttribLocation(glProgram, 'a_Position'); /** * vertexAttrib 顶点属性 * f float类型 * 3 3个参数 代表位置信息 */ webgl.vertexAttrib3f(aPosition,0.5, 0.0, 1.0) //给变量赋值 var aPointSize = webgl.getAttribLocation(glProgram, 'a_PointSize'); webgl.vertexAttrib1f(aPointSize, 50.0); //类型为浮点型 相互对应 //5、绘制 /** * 第一个参数 表示你绘制的形状 gl.POINTS 绘制一个点 * 第二个参数 0 表示你从哪个位置开始绘制 * 第三个参数 1 表示到哪儿结束 */ webgl.drawArrays(webgl.POINTS,0,1);
-
关于动态改变点的位置 两种方式
方式1: var aPosition = webgl.getAttribLocation(glProgram, 'a_Position'); /** * vertexAttrib 顶点属性 * f float类型 * 3 3个参数 代表位置信息 */ webgl.vertexAttrib3f(aPosition,0.5, 0.0, 1.0) //给变量赋值 方式2: var aPosition = webgl.getAttribLocation(glProgram, 'a_Position'); //允许读取变量 var p = new Float32Array([0.5, 0.0, 1.0]); webgl.vertexAttrib3fv(aPosition,p); //赋值
-
-
绘制圆点
需要利用webgl中,glsl es语言
将绘制片元着色器时 超过半径为0.5的区域设置为与半径融合的颜色 则将其不显示
进而实现绘制圆点的要求
var fs_source = `
#ifdef GL_ES
precision mediump float;
#endif
void main(){
float d = distance(gl_PointCoord, vec2(0.5,0.5));
if(d<0.5){
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
}else{
discard;
}
}
`;
在片元着色器中使用变量 定义片元颜色
片元语言没有默认的浮点数精度修饰符。因此,对于浮点数,浮点数向量和矩阵变量声明,要么声明必须包含一个精度修饰符,要不默认的精度修饰符在之前已经被声明过了。
var fs_source = `
#ifdef GL_ES
precision mediump float; //必须包含这条语句
#endif
uniform vec4 u_FragColor;
void main(){
gl_FragColor = u_FragColor;
}
`
//允许读取变量
var uFragColor = webgl.getUniformLocation(glProgram, 'u_FragColor');
//赋值
webgl.uniform4f(uFragColor,1.0,0.5,0.5,1.0)
绘制多个圆 - 缓冲区
需要借用到缓冲区
-
定义各原点位置 在写入数据时传入缓冲区
var p = new Float32Array([ 0.0, 0.0, 0.8, 0.5, 0.0, 0.8, 0.5, 0.0, 0.4 ]);
-
创建缓冲区:WebGLRenderingContext.createBuffer()
var vertexBuffer = webgl.createBuffer();
-
绑定缓冲区,将缓冲区绑定到目标,在内存中申请一片区域:WebGLRenderingContext.bindBuffer()
/** * webgl.bindBuffer(target, buffer) * 第一个参数 指定缓冲区的目标类型 * 第二个参数 创建的缓冲区对象 */ webgl.bindBuffer(webgl.ARRAY_BUFFER, vertexBuffer);
-
向缓冲区写入数据:WebGLRenderingContext.bufferData()
/** * 第一个参数 指定缓冲区的目标类型 * 第二个参数 数据 * 第三个参数 静态绘制 */ webgl.bufferData(webgl.ARRAY_BUFFER, p, webgl.STATIC_DRAW);
-
获取变量位置 坐标值
var aPosition = webgl.getAttribLocation(glProgram, 'a_Position');
-
把缓冲区对象分配给变量a_Position
/** * aPosition 修改的位置 * 2 顶点的组成数量 * webgl.FLOAT 每个元素的数据类型 * false 转换为浮点数时是否应该将整数数值归一化到特定的范围 * 0 紧密打包 * 0 顶点属性数组中第一部分的字节偏移量 */ webgl.vertexAttribPointer(aPosition, 2, webgl.FLOAT, false, 0, 0);
-
链接缓冲区对象和a_Position:
webgl.enableVertexAttribArray(aPosition)
-
绘制你想要几个顶点
//0 数组中下标为0 //3 数组中下标为2 webgl.drawArrays(webgl.POINTS,0,3);
绘制三角形 - 即为连接三个点
可改变要连接点的起始位置和末尾位置 绘制三角形
webgl.drawArrays(webgl.TRIANGLES,0,3);
整体代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<!-- canvas的宽度和高度设置 尽量使用width这种形式定义 不要使用style这种形式 -->
<canvas id="canvas" width="400" height="400"></canvas>
<script>
/*
var canvas = document.getElementById('canvas'), //绘制canvas
webgl = canvas.getContext('webgl'); //获取webgl
webgl.viewport(0, 0, canvas.width, canvas.height); //视口
webgl.clearColor(0.043,0.5,0.2,1.0); //使用一种颜色清空之前的颜色
webgl.clear(webgl.COLOR_BUFFER_BIT); //使用clear填入进去
*/
//1、 获取webgl
var canvas = document.getElementById('canvas'), //绘制canvas
webgl = canvas.getContext('webgl'); //获取webgl
webgl.clearColor(0.043,0.5,0.2,1.0); //使用一种颜色清空之前的颜色
webgl.clear(webgl.COLOR_BUFFER_BIT); //使用clear填入进去
//顶点着色器 可以使用上面那种方式 也可以使用这种
//每一句的分号结尾不可省略
//a_Position; //声明一个变量 变量名可随便赋值
//在声明变量时 注意你声明的类型 要与之后你所传递值的类型对应
var vs_source = `
attribute vec4 a_Position;
attribute float a_PointSize;
void main(){
gl_Position = a_Position;
gl_PointSize = a_PointSize;
}
`;
//片元着色器
var fs_source = `
#ifdef GL_ES
precision mediump float;
#endif
uniform vec4 u_FragColor;
void main(){
gl_FragColor = u_FragColor;
}
`
//2、创建着色器对象并绑定好对应的着色器字符串
//创建顶点着色器容器
var vertexShader = webgl.createShader(webgl.VERTEX_SHADER);
//将着色器容器与资源绑定
webgl.shaderSource(vertexShader, vs_source);
//编译顶点着色器
webgl.compileShader(vertexShader);
//片元着色器的容器创建 绑定 编译
var fragmentShader = webgl.createShader(webgl.FRAGMENT_SHADER);
webgl.shaderSource(fragmentShader, fs_source);
webgl.compileShader(fragmentShader);
//3、创建着色器程序并添加前面创建的着色器对象
//创建着色器程序
var glProgram = webgl.createProgram();
//添加到着色器程序中
webgl.attachShader(glProgram,vertexShader);
webgl.attachShader(glProgram,fragmentShader);
//4、把着色起程序链接成一个完整的程序并使用它
webgl.linkProgram(glProgram);
webgl.useProgram(glProgram);
/**
* vertexAttrib 顶点属性
* f float类型
* 3 3个参数 代表位置信息
*/
var p = new Float32Array([
0.0, 0.0, 0.8,
0.5, 0.0, 0.8,
0.5, 0.0, 0.4
]);
//1、创建缓冲区
var vertexBuffer = webgl.createBuffer();
//2、绑定缓冲区,将缓冲区绑定到目标,在内存中申请一片区域
/**
* webgl.bindBuffer(target, buffer)
* 第一个参数 指定缓冲区的目标类型
* 第二个参数 创建的缓冲区对象
*/
webgl.bindBuffer(webgl.ARRAY_BUFFER, vertexBuffer);
//3、向缓冲区写入数据
/**
* 第一个参数 指定缓冲区的目标类型
* 第二个参数 数据
* 第三个参数 静态绘制
*/
webgl.bufferData(webgl.ARRAY_BUFFER, p, webgl.STATIC_DRAW);
//4、获取attribute变量的存储位置,返回对应的地址信息
var aPosition = webgl.getAttribLocation(glProgram, 'a_Position');
//5、把缓冲区对象分配给变量aPosition
/**
* aPosition 修改的位置
* 2 顶点的组成数量
* webgl.FLOAT 每个元素的数据类型
* false 转换为浮点数时是否应该将整数数值归一化到特定的范围
* 0 紧密打包
* 0 顶点属性数组中第一部分的字节偏移量
*/
webgl.vertexAttribPointer(aPosition, 2, webgl.FLOAT, false, 0, 0);
//6、链接缓冲区对象和a_Position
webgl.enableVertexAttribArray(aPosition)
//给变量赋值
var aPointSize = webgl.getAttribLocation(glProgram, 'a_PointSize');
webgl.vertexAttrib1f(aPointSize, 10.0);
var uFragColor = webgl.getUniformLocation(glProgram, 'u_FragColor');
webgl.uniform4f(uFragColor,1.0,0.5,0.5,1.0);
//5、绘制
/**
* 第一个参数 表示你绘制的形状 gl.POINTS 绘制一个点
* 第二个参数 0 表示你从哪个位置开始绘制
* 第三个参数 1 表示到哪儿结束
*/
webgl.drawArrays(webgl.TRIANGLES,0,3);
</script>
</body>
</html>