【P42】 默认情况下,<canvas>
是透明的
【P44】 它不直接提供绘图方法,而是提供一种叫上下文(context)的机制来进行绘图。
【P45】 计算机系统通常使用红、绿、蓝这三原色组合来表示颜色,这种颜色表示方式被称为RGB格式,当a (透明度)加进来之后,就成为RGBA格式。
<!DOCTYPE html>
<html>
<head>
<script src="index.js"></script>
</head>
<body onload="main()">
<canvas id="canvas" width="400" height="400">
你的浏览器不支持 canvas。
</canvas>
</body>
</html>
function main() {
var canvas = document.getElementById('canvas');
// 错误检查
if (!canvas) {
alert('无法获取 <canvas> 标签。');
return;
}
var ctx = canvas.getContext('2d'); // 参数指定 2D/3D
ctx.fillRect(120, 10, 150, 150); // 参数 x y width height
}
var gl = getWebGLContext(canvas);
if (!gl) {
alert('无法获取初始化 WebGL。');
return;
}
gl.clearColor(0.5, 0.5, 0.5, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
<script src="https://rodger.global-linguist.com/webgl/lib/webgl-utils.js"></script>
<script src="https://rodger.global-linguist.com/webgl/lib/webgl-debug.js"></script>
<script src="https://rodger.global-linguist.com/webgl/lib/cuon-utils.js"></script>
gl.clearColor(r, g, b, a)
// 三个参数的值都是 [0.0, 1.0]
<canvas>
gl.clear(gl.COLOR_BUFFER_BIT);
gl = getWebGLContext(); // 获取 WebGL 上下文
initShaders(); // 初始化着色器
gl.clearColor(0, 0, 0, 0) // 设置背景色
// 开始绘图
// `main()` 函数不能有参数,返回值必须为 `void`
void main() {
// `gl_Position`:内置变量,顶点位置,类型 `vec4`,必选。
// vec4() 函数用于构造一个 vec4 实例。
gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
// `gl_PointSize`:内置变量,顶点大小,类型 `float`,可选。
gl_PointSize = 10.0;
}
glsl
,但不一定支持。可以用 c
作为代替。 )gl_PointSize = 10
会报错!vec4
类型 / 齐次坐标
void main() {
// `gl_FragColor`:内置变量,顶点颜色,类型 `vec4`。
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
gl.drawArrays()
进行。gl.drawArrays(gl.POINTS, 0, 1);
attribute vec4 aPos; // 外部参数
void main() {
gl_Position = aPos;
gl_PointSize = 20.0;
}
JS 代码:// ...
// 初始化 Shader
if (!initShaders(gl, VERTEX_SHADER, FRAGMENT_SHADER)) {
console.error('无法初始化着色器');
}
// 获取 aPos 变量地址
// gl.program 在 initShaders() 调用之后自动创建
var pos = gl.getAttribLocation(gl.program, 'aPos');
// 设置 aPos 的值
gl.vertexAttrib3f(pos, 0.5, 0.5, 0);
gl.clearColor(0.5, 0.5, 0.5, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
// ...
gl.vertexAttrib3f()
函数是其一系列函数中的一个
3
表示矢量的元素个数,f
表示浮点数,i
表示整数,v
表示传入参数为矢量(数组)。[v2, v3, v4]
的会被赋予默认值 [0, 0, 1]
(哪个少就补上哪个的默认值)。gl.vertexAttribf1f(location, v1);
gl.vertexAttribf2f(location, v1, v2);
gl.vertexAttribf3f(location, v1, v2, v3);
gl.vertexAttribf4f(location, v1, v2, v3, v4);
gl.vertexAttribf1i(location, v1);
gl.vertexAttribf2i(location, v1, v2);
gl.vertexAttribf3i(location, v1, v2, v3);
gl.vertexAttribf4i(location, v1, v2, v3, v4);
gl.vertexAttribf1fv(location, arr);
gl.vertexAttribf2fv(location, arr);
gl.vertexAttribf3fv(location, arr);
gl.vertexAttribf4fv(location, arr);
var points = [];
// 响应点击事件
canvas.onmousedown = (event) => {
console.clear();
// 获取点击坐标
// 转换步骤:页面坐标 -> canvas 坐标 -> WebGL 坐标
// 这个坐标是页面坐标
var x = event.clientX;
var y = event.clientY;
// 转换为 <canvas> 坐标
// = 页面坐标 - <canvas> 左上角在页面中的坐标
var rect = canvas.getBoundingClientRect();
x = x - rect.left;
y = y - rect.top;
// 转换为 WebGL 坐标
// 将原点从左上角移到中间位置
console.log(x, y);
y = -y;
x = x + (-canvas.width / 2);
y = y + (canvas.height / 2)
// 缩放坐标轴
x /= canvas.width / 2;
y /= canvas.height / 2;
console.log(x, y);
points.push([x, y]);
// 画点
points.forEach((value) => {
gl.vertexAttrib2fv(locPos, value);
gl.drawArrays(gl.POINTS, 0, 1);
});
};
gl.drawArrays()
函数是可以重复调用的,会在颜色缓冲区上继续绘制,也就是和之前的结果叠加。var points = [];
canvas.onmousedown = (event) => {
// ...
console.log(x, y);
// 前面是一样的
// 保存坐标
points.push([x, y]);
// 画点
gl.clear(gl.COLOR_BUFFER_BIT);
points.forEach((value) => {
gl.vertexAttrib2fv(locPos, value);
gl.drawArrays(gl.POINTS, 0, 1);
});
};
从 Javascript 向片元着色器中传递数据需要用 uniform 变量。
gl.uniform4f()
函数和 gl.VertexAttrub4f()
函数类似,也是一个系列的函数:
GLES 代码(片元着色器):
precision mediump float; // 指定浮点数的精度为中等精度(包括范围和有效小数位)
// 第五章讨论精度问题
uniform vec4 uColor; // 外部参数
void main(){
gl_FragColor = uColor;
}
JS 代码:
// 获取 uColor 变量地址
var uColor = gl.getUniformLocation(gl.program, 'uColor');
// ...
canvas.onmousedown = function (event) {
// 画点
gl.clear(gl.COLOR_BUFFER_BIT);
points.forEach((value) => {
gl.vertexAttrib2fv(aPos, value);
// 设置颜色(uColor)
// 这里每次绘制都随机生成颜色
var uColor = gl.getUniformLocation(gl.program, 'uColor');
gl.drawArrays(gl.POINTS, 0, 1);
});
}
gl.clear(gl.COLOR_BUFFER_BIT);
points.forEach((value) => {
gl.vertexAttrib2fv(aPos, value);
// 设置颜色(uColor)
// 这里每次绘制都随机生成颜色
var uColor = gl.getUniformLocation(gl.program, 'uColor');
gl.drawArrays(gl.POINTS, 0, 1);
});
}