全部章节
06.frameBuffer-将webgl绘制的正方体作为材质
点的实现
效果:
代码
<canvas id="cvs" style="width: 100px; height: 100px" height="100px" width="100px"></canvas>
<script>
// 改变position的xyz查看点的位置变化,理解webgl的右手坐标系
const VS = `
void main() {
gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
gl_PointSize = 10.0;
}
`;
const FS = `
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`;
</script>
<script>
const cvs = document.getElementById('cvs')
const gl = cvs.getContext('webgl')
initShader(gl, VS, FS)
gl.clearColor(0.0, 0.0, 0.0, 1.0)
gl.clear(gl.COLOR_BUFFER_BIT)
gl.drawArrays(gl.POINT, 0, 1)
function initShader(gl, vs, fs) {
const program = createProgram(gl, vs, fs)
gl.useProgram(program)
gl.program = program
return true
}
function createProgram(gl, vs, fs) {
const vShader = loadShader(gl, gl.VERTEX_SHADER, vs)
const fShader = loadShader(gl, gl.FRAGMENT_SHADER, fs)
const program = gl.createProgram();
gl.attachShader(program, vShader)
gl.attachShader(program, fShader)
gl.linkProgram(program)
return program
}
function loadShader(gl, type, source) {
const shader = gl.createShader(type)
gl.shaderSource(shader, source)
gl.compileShader(shader)
return shader
}
</script>
解释
着色器代码
const VS = `
void main() {
gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
gl_PointSize = 10.0;
}
`;
const FS = `
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`;
简单理解一下两个着色器代表的含义。
顶点着色器(VS)描述了在三维空间里点的信息,如点的位置,点的大小等。
片元着色器(FS)描述了某个位置上的颜色信息。
假设要表示正方形,首先是通过顶点着色器定义了四个角的位置,然后通过片元着色器定义面的颜色就可以绘制出一个正方形。当然这里说的很简单,有些情况也需要更多的点来实现一个正方形,这里只是为了大家大致的去了解一下两个着色器大致是做什么的。
顶点着色器
先看一下顶点着色器中的代码,直接看main函数内的语句,gl_Position和gl_PointSize是webgl中内置变量,下面片元着色器中的gl_FragColor也是,webgl中还有许多其他的内置变量,都是以gl开头的。
gl_Position
顾名思义,这个变量代表了点的位置信息,vec4是webgl中的一种数据类型,可以简单理解成一个拥有四个数的数组,也存在vec2和vec3代表了只存在两位和三位数的矢量。
vec4的前三个参数就代表了xyz,比如程序中gl_Position被赋值的前三位就对应了xyz,所以最终点呈现在了canvas的正中间,原点的位置。
如果我们把赋值改成vec4(0.1,-0.2,0.0,1.0),点的显示会在中心偏右下的位置,这是因为webgl中的坐标系是右手坐标系,x轴向右,y轴向上,z轴向前。
第四个参数会影响点在画布上的最终显示,会在后续会在矩阵中解释。
gl_PointSize
该变量的意义就是点的大小,是一个浮点类型
片元着色器
本例中的片元着色器代码就比较好理解了,gl_FragColor就代表了该点的颜色值,而vec4中的四个参数就代表了rgba四个值,需要注意的是,值的区间是0.0-1.0
而不是0-255
。
js代码
本例中的着色器代码是最少的,主要是介绍一下gl_Position和gl_FragColor,这两个在着色器中最主要的东西。 接下来我们看一下js代码。
获取webgl上下文
const cvs = document.getElementById('cvs')
const gl = cvs.getContext('webgl')
这一步很容易理解,相信大家有时候也会获取canvas的2d上下文,getContext('2d')
当然getContext还有其他的参数,'webgl2','bitmaprenderer'
本系列中只需要webgl的上下文即可。
初始化着色器程序
initShader(gl, VS, FS)
function initShader(gl, vs, fs) {
const program = createProgram(gl, vs, fs)
gl.useProgram(program)
gl.program = program
return true
}
function createProgram(gl, vs, fs) {
const vShader = loadShader(gl, gl.VERTEX_SHADER, vs)
const fShader = loadShader(gl, gl.FRAGMENT_SHADER, fs)
const program = gl.createProgram();
gl.attachShader(program, vShader)
gl.attachShader(program, fShader)
gl.linkProgram(program)
return program
}
function loadShader(gl, type, source) {
const shader = gl.createShader(type)
gl.shaderSource(shader, source)
gl.compileShader(shader)
return shader
}
代码只是去实现了过程,没有做兼容性处理(还是存在部分浏览器不支持webgl) 大致的过程为
- 创建并编译顶点着色器
- 创建并编译片元着色器
- 创建着色器程序
- 引用顶点着色器和片元着色器
- 使用着色器程序
过程还是简单易懂的,首先就是两个着色器代码在js中是字符串形式的,需要把它们编译成gpu可用的代码,然后用一个着色器程序program,关联顶点和片元着色器。
在一个webgl上下文中,不止可以使用一对顶点和片元着色器代码。
我们可以再写一对着色器代码,并在程序最后再用一次initShader和drawArrays,可以实现同时绘制一个红色的点和一个蓝色的点。虽然实现这样的功能有更好的写法,但是这样实现仅仅是为了理解可以使用多个着色器程序。
PS: gl.program = program
这行代码其实是不好的,它是为了暂存一下刚定义的着色器程序,不同着色器程序之间的切换就是使用gl.useProgram(program),而参数就是这个program。但是gl对象中原本是没有program这个属性的,所以在ts中会报错,好的办法是自己用一个变量去储存。
绘制点
gl.clearColor(0.0, 0.0, 0.0, 1.0)
gl.clear(gl.COLOR_BUFFER_BIT)
gl.drawArrays(gl.POINT, 0, 1)
本例中只剩下这些代码还没有解释过,他们的功能都是在canvas上绘制。
clearColor和clear
可以理解为,用什么颜色去清空画布 如在clearColor中我们传入的参数是0.0, 0.0, 0.0, 1.0,那么就是用黑色去清空画布。 然后调用clear去用刚才定义的颜色去清空画布
drawArrays
drawArrays是去绘制图形的,本例中的意思是根据当前使用的着色器程序,去绘制一个点。具体的参数意思和可选参数会在后续章节中涉及
总结
本章节中,我们介绍了一个最简单的webgl程序的实现过程,介绍了顶点和片元着色器的作用,以及gl_Poisition和gl_FragColor。
然后介绍了如何用js去把着色器程序运行起来,并呈现在canvas上。
后续本系列会带来五个章节的内容,讲解webgl的大部分基础api,最终实现如下的效果。