WebGL07
多个缓冲区对象
const vertices = new Float32Array([
-.6, -.6,
0., .8,
.6, -.6,
])
const colors = new Float32Array([
1., 0., 0., 1., // 红色
0., 1., 0., 1., // 绿色
0., 0., 1., 1., // 蓝色
])
对应的数据准备好之后,我们就可以继续创建我们的缓冲区了。
- 创建缓冲区对象。
- 绑定缓冲区对象到target。
- 分配缓冲区数据。
- 将缓冲区分配到attribute变量。
- 开启attribute变量。 这样我们就通过建立多种缓冲区传递不同种类的数据,当使用gl.drawArrays绘制时,各种数据将按照其缓冲区中的顺序一一传递到顶点着色器的attribute变量中。
var canvas = document.getElementById("canvas");
canvas.width = canvas.height = 600;
const gl = canvas.getContext("webgl", { preserveDrawingBuffer: true });
const vertexCode = `
// 顶点坐标数据
attribute vec4 a_Position;
// 颜色数据
attribute vec4 a_Color;
// varying 变量传递到片元着色器
varying vec4 v_Color;
void main () {
gl_Position = a_Position;
v_Color= a_Color;
}
`;
const fragmentCode = `
precision mediump float;
// 颜色值变量
varying vec4 v_Color;
void main () {
gl_FragColor = v_Color;
}
`;
//着色器代码的初始化
// 绘制实现
document.getElementById("redFn").addEventListener("click", () => {
gl.clear(gl.COLOR_BUFFER_BIT);
});
function createShader({ glslCode, type }) {
// 创建对应类型着色器
const shader = gl.createShader(type);
// 传入对应着色器代码
gl.shaderSource(shader, glslCode);
// 编译着色器
gl.compileShader(shader);
return shader;
}
// 创建顶点着色器
const vertexShader = createShader({
glslCode: vertexCode,
type: gl.VERTEX_SHADER
});
// 创建片元着色器
const fragmentShader = createShader({
glslCode: fragmentCode,
type: gl.FRAGMENT_SHADER
});
// 创建着色器程序
const program = gl.createProgram();
// 分别添加两个着色器 gl.attachShader
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
// 链接两个着色器
gl.linkProgram(program);
gl.useProgram(program);
// 动态修改顶点位置
const a_Position = gl.getAttribLocation(program, "a_Position");
const a_Color = gl.getAttribLocation(program, "a_Color");
// 绘制多个点
// const vertices = new Float32Array([0, 0.8, -0.6, -0.6, 0.6, -0.6]);
// 本节的顶点坐标
const vertices = new Float32Array([-0.5, 0.5, 0, -0.9, 0.5, 0.5]);
const colors = new Float32Array([
1.0,
0.0,
0.0,
1.0,
0.0,
1.0,
0.0,
1.0,
0.0,
0.0,
1.0,
1.0
]);
function createBuffer({ gl, target, bufferData, attribute, size }) {
const buffer = gl.createBuffer();
gl.bindBuffer(target, buffer);
gl.bufferData(target, bufferData, gl.STATIC_DRAW);
gl.vertexAttribPointer(attribute, size, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(attribute);
}
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(a_Position);
createBuffer({
gl,
target: gl.ARRAY_BUFFER,
bufferData: colors,
attribute: a_Color,
size: 4
});
gl.clearColor(0.0, 0.0, 0.0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
// gl.drawArrays(gl.LINE_STRIP, 0, 3);
// gl.drawArrays(gl.TRIANGLES, 0, 3);
// gl.drawArrays(gl.POINTS, 0, 3);
// gl.drawArrays(gl.LINES, 0, 6);
// gl.drawArrays(gl.LINE_STRIP, 0, 6);
// gl.drawArrays(gl.LINE_LOOP, 0, 6);
// gl.drawArrays(gl.TRIANGLES, 0, 6);
// gl.drawArrays(gl.TRIANGLE_STRIP, 0, 6);
gl.drawArrays(gl.TRIANGLES, 0, 3);
canvas.addEventListener("click", (e) => {
const halfWidth = canvas.width / 2;
const halfHeight = canvas.height / 2;
const x = (e.offsetX - halfWidth) / halfWidth;
const y = (halfHeight - e.offsetY) / halfHeight;
// gl.clear(gl.COLOR_BUFFER_BIT);
gl.vertexAttrib2f(a_Position, x, y);
// gl.vertexAttrib4f(a_Color, Math.random(), Math.random(), Math.random(), 0.9);
//动态设置颜色值
gl.drawArrays(gl.POINTS, 0, 1);
});
gl.vertexAttribPointer的神奇参数
通过参数配置,我们可以将多种类数据存放在一个缓冲区对象中。
- index 表示attribute变量地址。
- size 每个顶点分配到缓冲区数据的个数。范围[1-4]
- type 数据格式
- normalize boolean值 是否将非浮点数转换时归一到[0,1]或[-1,1] 对于float类型无效
- stride 指两个顶点之间的字节数 默认是0.
- offset 指定缓冲区数据的偏移量(单位是字节)若为开始的位置则是0。
stride参数详解
指两个顶点之间的字节数 默认是0。 这个间距字节数其实就和顶点自身字节数一致。
TypedArray.BYTES_PER_ELEMENT表示强类型数组中每个元素所占的字节数。
const verticesColors = new Float32Array([
0.0, 0.0, 1.0, 0.0, 0.0, // 第一个点包括坐标、颜色rgb
0.1, 0.1, 1.0, 0.0, 0.0, // 第二个点包括坐标、颜色rgb
0.2, 0.2, 1.0, 0.0, 0.0, // 第三个点包括坐标、颜色rgb
])
// 每个元素占用的字节数
const FSIZE = verticesColors.BYTES_PER_ELEMENT
// 每个顶点数据总共有 5 个浮点数
stride参数 = FSIZE * 5
offset参数详解
表示一组数据距离首个类型数据元素的距离。
// 获取坐标数据
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE * 5, 0)
// 获取颜色数据
gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, FSIZE * 5, FSIZE * 2)
通过这个参数再配合我们的size就可以告诉WebGl我们的数据从哪里获取。
使用一个缓冲区对象和多个缓冲区对象实现渐变三角的区别。
// 顶点 坐标数据、颜色数据放在一起
const verticesColors = new Float32Array([
-.6, -.6, 1., 0., 0., 1.,
0., .8, 0., 1., 0., 1.,
.6, -.6, 0., 0., 1., 1.,
])
// 分配坐标数据,注意看 size分配个数、 stride步进参数 和 offset偏移参数 的值
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE * 6, 0)
gl.enableVertexAttribArray(a_Position)
// 分配颜色数据,注意看 size分配个数、 stride步进参数 和 offset偏移参数 的值
gl.vertexAttribPointer(a_Color, 4, gl.FLOAT, false, FSIZE * 6, FSIZE * 2)
gl.enableVertexAttribArray(a_Color)
写在最后
未完待续…
希望大家好好生活,健康快乐。