初次接触WebGL,若有错误之处欢迎留言,共同窗习进步. vjavascript
我,WebGL,全名Web Graphics Library
,是为了让死宅程序猿们(摊手)能在浏览器上随心所欲的画女友,并还能动手动脚,而屈尊降临于猿类的世界内。哇哈哈哈哈,快来臣服于我吧,哇嘎嘎嘎嗝~java
WebGL小姐姐神通广大,法力无边。那咱们怎么用她来创造一个猿猿幸(有)福(女)美(朋)满(友)的世界呢?web
首先,咱们须要一个名为canvas
的祭坛,举行一个召唤WebGL
小姐姐的小仪式。canvas
const canvas = document.createElement('canvas'); const gl = canvas.getContext('webgl');
那么,WebGL
小姐姐Get到手了,接下来咱们须要先将两样'祭品'交给她的两名侍女。api
gl_Position
是每次绘制的点,是vec4类型,分别空间点(x, y, z)
和最后一个w
。对于w
能够参考文章Explaining Homogeneous Coordinates & Projective Geometry,能够理解为投影仪与空间点的距离,距离不一样会致使缩放效应,距离远则投放的物体越大。咱们这里使用没有缩放效果的值1.0
,并使用了position
这个定义的变量值。每次绘制gpu buffer
会更新position
的值.const vertexShaderSource = ` precision mediump float; attribute vec2 position; void main(void) { gl_Position = vec4(position.x, position.y, 0.0, 1.0); } `;
glFragColor
定义的颜色值,一样是vec4类型,分别表明(r, g, b, a)
const fragmentShaderSource = ` precision mediump float; void main(void) { gl_FragColor = vec4(0.7, 0.5, 0.38, 0.0); } `
关于precision
:因为openGL
没有声明float
类型的默认精度,因此其姐妹WebGL
也就须要为shader
声明精度。又因为高精度openGL
没有支持,低精度在手机上能够有兼容问题,因此默认推荐mediump
。参考 https://stackoverflow.com/a/28540641/2326199 和 Use mediump precision in WebGL when possible
const vertexShader = gl.createShader(gl.VERTEX_SHADER); // 唤醒 gl.shaderSource(vertexShader, vertexShaderSource); // 上交祭品 gl.compileShader(vertexShader); // 处理祭品 if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) { // 因为祭品偶尔不新鲜或者侍女偷懒,咱们要好好确认祭品是否处理完毕 throw new Error(`Error in compileing vertexShader: ${gl.getShaderInfoLog(vertexShader)}`); } const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(fragmentShader, fragmentShaderSource); gl.compileShader(fragmentShader); if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) { throw new Error(`Error in compileing vertexShader: ${gl.getShaderInfoLog(vertexShader)}`); }
祭品已准备稳当,接下来就是要请出WebGL
小姐姐御用创世神器program
并使用祭品开光,而后交与小姐姐手中。浏览器
const program = gl.createProgram(); // 神器现世 gl.attachShader(program, vertexShader); // 开第一封印:原料 gl.attachShader(program, fragmentShader); // 开第二封印:色开 gl.linkProgram(program); // 交与小姐姐 if(!gl.getProgramParameter(program, gl.LINK_STATUS)) { // 咳咳,因为神器与祭品偶尔没法契合,致使神器失效,须要检查一下 ~_~ throw new Error(`invalid program: ${gl.getProgramInfoLog(program)}`); }
注意了注意了,WebGL
小姐姐起手式完毕,开天辟地,万物复苏。咱们如今能够向她许愿,描述咱们心中的猩福世界
了~v;v~编辑器
WebGL
小姐姐有多个许愿池,咱们这里使用gl.ARRAY_BUFFER
。而后告诉神器program
怎么收取愿望。学习
const buffer = gl.createBuffer(); // 建立许愿树 gl.bindBuffer(gl.ARRAY_BUFFER, buffer); // 将许愿树种到`ARRAY_BUFFER`这个许愿池内 // 获取神器`program`的`position`之力 const position = gl.getAttribLocation(program, 'position'); // position之力为2个float类型的数一组,不转化`buffer`类型, // 从头开始,不跳过任何一个愿望 gl.vertexAttribPointer(position, 2, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(position);
小姐姐迎着丝毫都没有的狂风,望着漫无编辑器的虚无黑暗,眼角迸发出一丝丝精光,大笔一挥, 左一划右一挥。webgl
gl.viewport(0, 0, 400, 400); gl.useProgram(program); gl.clearColor(255 / 255, 192 / 255, 203 / 255, 1.0); gl.clear(gl.COLOR_BUFFER_BIT); gl.lineWidth(1.5); const points = new Float32Array([ -0.9, 0.9, 0.0, 0.0, 0.9, -0.9, ]); gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW); gl.drawArrays(gl.LINE_LOOP, 0, points.length / 2); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ -0.9, -0.9, 0.0, 0.0, 0.9, 0.9 ]), gl.STATIC_DRAW); gl.drawArrays(gl.LINE_LOOP, 0, 3);
创世之做在漫天闪电,山崩海啸之下庄严出世!! 登登登,piapia(背景乐)google
最后来一张WebGL
绘制整个过程的流程图:
未完待续
本文章首发于本人公众号:枫之叶
若您能喜欢本文,并欲转发本文请保留公众号声明与公众号二维码。谢谢 ^v^