绘制一个点
- 其实是一个矩形,比绘制圆更快
- 绘图机制依赖于着色器(shader)
着色器
- 着色器程序是GLSL ES语言
- 以字符串的方式嵌套在js语言中
顶点着色器(Vertex shader)
- 顶点是二维或三维空间的一个点
- 顶点着色器是来描述顶点特性(位置、颜色等)
片元着色器(Fragment shader)
- 片元是图像的单元(像素)
- 片元着色器是来描述逐个片元处理过程的(光照等)
着色器程序
- 顶点着色器程序类似C语言必须包含一个main()函数。
- 内置变量
- gl_Position(vec4)表示顶点位置,必须
- gl_PointSize(float)表示点的尺寸(像素),默认1.0
- gl_FragColor(vec4)指定片元颜色。
- 变量类型:
- float 浮点数
- vec4 表示四个浮点数组成的矢量
- 齐次坐标
齐次坐标(x,y,z,w)等价于三维坐标(x/w,y/w,z/w),所以如果w=1,则可以当它是一个三维坐标。0<w,所以齐次坐标是有无穷的概念的
绘制操作
- gl.drawArrays
gl.drawArrays(mode, first, cout);
- mode 绘制方式
- first 从哪个顶点开始
- count 需要用到多少个顶点
WebGL坐标系
- 默认它为右手坐标系就好了
- 坐标点与canvas是不一样的
canvas坐标系是左上角为原点,向下为y正方向,向右为x正方向
WebGL坐标系,原点在中心,向上为y正方向,向右为x正方向,边界坐标为1
变量传递
- js传递变量给shader
- attribute变量(存储限定符),表示接着的变量是一个attribute变量 ,与顶点相关的数据
- uniform变量 所有顶点都相同或与顶点无关的数据
鼠标画点代码
// 顶点着色器
var VSHADER_SOURCE =
'attribute vec4 a_Position;\n' + // 将从js读取值
'void main() {\n' +
' gl_Position = a_Position;\n' + // 设置坐标
' gl_PointSize = 10.0;\n' + // 设置尺寸
'}\n';
// 片元着色器程序
var FSHADER_SOURCE =
'precision mediump float;\n' +
'uniform vec4 u_FragColor;\n' +
'void main() {\n' +
' gl_FragColor = u_FragColor;\n' + // 设置颜色
'}\n';
function main() {
var canvas = document.getElementById('webgl');
var gl = getWebGLContext(canvas);
if (!gl) {
console.log('Failed to get the rendering context for WebGL');
return;
}
// 初始化着色器
if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
console.log('Failed to intialize shaders.');
return;
}
// 获取attribute变量的存储位置
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
if(a_Position < 0) {
console.log('Failed to get the storage location of a_Position');
return;
}
// 获取u_FragColor变量的存储位置
var u_FragColor = gl.getUniformLocation(gl.program, 'u_FragColor');
// 注册鼠标点击响应函数
canvas.onmousedown = function(ev){
click(ev, gl, canvas, a_Position, u_FragColor);
}
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
}
var gPoints = []; // 鼠标点击位置数组
var gColors = [];
function click(ev, gl, canvas, a_Position, u_FragColor){
var x = ev.clientX; // 鼠标点击的x坐标
var y = ev.clientY; // 鼠标点击处的y坐标
var rect = ev.target.getBoundingClientRect();
x = ((x - rect.left) - canvas.width/2)/(canvas.width/2);
y = (canvas.height/2 - (y - rect.top)) / (canvas.height/2);
gPoints.push({x:x,y:y});
gColors.push({r:Math.random().toFixed(1),g:Math.random().toFixed(1),b:Math.random().toFixed(1),a:1.0})
// 先清除再绘制
gl.clear(gl.COLOR_BUFFER_BIT);
for(var i= 0; i < gPoints.length; i++){
// 将顶点位置传输给attribute变量
gl.vertexAttrib3f(a_Position, gPoints[i].x, gPoints[i].y, 0.0);
// 将点的颜色传输到u_FragColor变量中
gl.uniform4f(u_FragColor, gColors[i].r, gColors[i].g, gColors[i].b, gColors[i].a);
// 绘制一个点
// gl.POINTS 点
// 常用 gl.LINES gl.LINE_STAIP gl.LINE_LOOP gl.TRIANGLES gl.TRIANGLE_STRIP gl.TRIANGLE_FAN
gl.drawArrays(gl.POINTS, 0, 1);
}
}
相关demo可以在我的公众号【xyzzlky】中回复【WebGL】获取,今日内容在HelloPoint中。