webGL入门
这是我参与「第四届青训营 」笔记创作活动的的第9天
canvas 2d与webgl绘图的差异
canvas 2d
canvas 2d可以直接使用js就可以进行绘图,目标元素是画纸,js是笔,我们就可以用js绘制不同的东西
//获取canvas画纸
const canvas=document.getElementById('canvas');
//获取画笔
const ctx=canvas.getContext('2d');
//设置画笔的颜色
ctx.fillStyle='red';
//用画笔画一个矩形
ctx.fillRect(20,20,300,200);
webgl
但是webgl绘图并不能像下面这样
//获取canvas画纸
const canvas=document.getElementById('canvas');
//获取画笔
const ctx=canvas.getContext('webgl');
//设置画笔的颜色
ctx.fillStyle='red';
//用画笔画一个立方体
ctx.fillBox(20,20,300,200);
这是因为webgl绘图并不是直接在用笔画纸上作画,而是需要利用顶点着色器和片元着色器经过一层编译,就好像是用手绘板在电脑上绘图一样
webgl绘图
因为使用手绘板绘图我们就要有以下几个步骤
-
获取绘图的电脑
<canvas id="canvas"></canvas>/**有这样一台'电脑'**/const canvas=document.getElementById('canvas');//获取这台'电脑'当然还需要确认一下这台电脑能不能用
// 确认WebGL支持性 if (!gl) { alert("无法初始化WebGL,你的浏览器、操作系统或硬件等可能不支持WebGL。"); return; }再清理一下电脑画板
// 使用完全不透明的黑色清除所有图像 gl.clearColor(0.0, 0.0, 0.0, 1.0); // 用上面指定的颜色清除缓冲区 gl.clear(gl.COLOR_BUFFER_BIT); -
获取数位笔
const gl=canvas.getContext('webgl');//获取数位笔 -
获取手绘板
定义顶点着色器和片元着色器字符串的配置(手绘板的组件)
const vsSource = ` void main() { gl_Position = vec4(0.0 ,0.0 ,0.0 , 1.0); gl_PointSize = 10.0; } `;//顶点着色器 const fsSource = ` void main() { gl_FragColor = vec4(1.0 ,0.0 ,0.0 ,1.0); } `;//片元着色器或者也可以选择用html的script元素自定义
//顶点着色器 <script id="vertexShader" type="x-shader/x-vertex"> void main() { gl_Position = vec4(0.0, 0.0, 0.0, 1.0); gl_PointSize = 100.0; } </script> //片元着色器 <script id="fragmentShader" type="x-shader/x-fragment"> void main() { gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0); } </script>const vsSource = document.getElementById('vertexShader').innerText; const fsSource = document.getElementById('fragmentShader').innerText;两种方法的结果都是一样的
顶点着色器用于描述顶点的特征,如位置、颜色等。
片元着色器用于进行逐片元处理,如光照。可以理解成顶点着色器确定绘制的点,片元着色器用于绘制链接各个顶点之间的像素
然后有了手绘板的组件,接下来就要拼装起来
initShaders(); function initShaders(gl,vsSource,fsSource){ //创建程序对象(创建和数位笔匹配的手绘板) const program = gl.createProgram();// //建立着色对象(获取到两个组件) const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource); const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource); if (!vertexShader || !fragmentShader) { return null; };//判断下着色器对象能不能用 //把顶点着色对象装进程序对象中(装载顶点着色器) gl.attachShader(program, vertexShader); //把片元着色对象装进程序对象中(装载片元着色器) gl.attachShader(program, fragmentShader); //连接webgl上下文对象和程序对象(匹配数位笔和手绘板) gl.linkProgram(program); //判断下连接状态,连不好只能报废了 const linked = gl.getProgramParameter(program, gl.LINK_STATUS); if (!linked) { const error = gl.getProgramInfoLog(program); console.log('Failed to link program: ' + error); gl.deleteProgram(program); gl.deleteShader(fragmentShader); gl.deleteShader(vertexShader); return false; }; //启动程序对象(打开数位板电源) gl.useProgram(program); //将程序对象挂到上下文对象上(连接数位笔和手绘板) gl.program = program; return true; }function loadShader(gl, type, source) { const shader = gl.createShader(type);//建立着色器对象(创建和数位笔匹配的手绘板组件) if (!program) { console.log('Failed to create program'); return false; };//判断下色器对象能不能用 gl.shaderSource(shader, source);//将着色器源文件传入着色器对象中 gl.compileShader(shader);//编译着色器对象 return shader; //返回着色器对象 } -
绘制
gl.drawArrays(gl.POINTS, 0, 1);//绘制一个点
绘制更多
但是如上代码只能在我们设置的顶点着色器的位置绘制一个点
const vsSource = `
void main() {
gl_Position = vec4(0.0 ,0.0 ,0.0 , 1.0);
gl_PointSize = 10.0;
}
`;//顶点着色器
因此我们可以改变'gl_Position'的值去绘制不同的点,因此我们要把我们的顶点着色器改装一下,给他加个插件
const VSHADER_SOURCE = `
attribute vec4 a_Position;
void main() {
gl_Position = a_Position;
gl_PointSize = 10.0;
}
`;//顶点着色器
let a_Position = gl.getAttribLocation(gl.program, "a_Position");//获取属性的api(获取插件)
gl.vertexAttrib3f(a_Position, 0.0, 0.0, 0.0);//修改属性值的api(操控插件)
gl.drawArrays(gl.POINTS, 0, 1);
gl.vertexAttrib3f(a_Position, 0.5, 0.5, 0.0);
gl.drawArrays(gl.POINTS, 0, 1);
这样我们就能通过控制插件来绘制不同的点了
总结
就是说这篇文章是我自己看到别的博客写笔记的不知道做不做数,先发了再说,我在实习的公司有3D库存的项目,在接触项目之前,想先了解一些基本的知识,因为真的在项目中用起来应该绘制用一些边界的框架,但是在使用时肯定会更加得心应手。