|
@@ -0,0 +1,206 @@
|
|
|
+<template>
|
|
|
+ <div>
|
|
|
+ <canvas ref="canvas" id="canvas" width="500" height="500" />
|
|
|
+ <component
|
|
|
+ :is="'script'"
|
|
|
+ src="https://webglfundamentals.org/webgl/resources/webgl-utils.js"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { onMounted, ref } from "vue";
|
|
|
+
|
|
|
+/**
|
|
|
+ * @type {import("vue").Ref<HTMLCanvasElement>}
|
|
|
+ */
|
|
|
+const canvas = ref();
|
|
|
+
|
|
|
+/**
|
|
|
+ * @param {WebGLRenderingContext} gl
|
|
|
+ * @param {number} type
|
|
|
+ * @param {string} source
|
|
|
+ */
|
|
|
+function createShader(gl, type, source) {
|
|
|
+ var shader = gl.createShader(type); // 创建着色器对象
|
|
|
+ gl.shaderSource(shader, source); // 提供数据源
|
|
|
+ gl.compileShader(shader); // 编译 -> 生成着色器
|
|
|
+ var success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
|
|
|
+ if (success) {
|
|
|
+ return shader;
|
|
|
+ }
|
|
|
+
|
|
|
+ gl.deleteShader(shader);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * @param {WebGLRenderingContext} gl
|
|
|
+ * @param {WebGLShader} vertexShader
|
|
|
+ * @param {WebGLShader} fragmentShader
|
|
|
+ */
|
|
|
+function createProgram(gl, vertexShader, fragmentShader) {
|
|
|
+ var program = gl.createProgram();
|
|
|
+ gl.attachShader(program, vertexShader);
|
|
|
+ gl.attachShader(program, fragmentShader);
|
|
|
+ gl.linkProgram(program);
|
|
|
+ var success = gl.getProgramParameter(program, gl.LINK_STATUS);
|
|
|
+ if (success) {
|
|
|
+ return program;
|
|
|
+ }
|
|
|
+
|
|
|
+ gl.deleteProgram(program);
|
|
|
+}
|
|
|
+
|
|
|
+// 返回 0 到 range 范围内的随机整数
|
|
|
+function randomInt(range) {
|
|
|
+ return Math.floor(Math.random() * range);
|
|
|
+}
|
|
|
+
|
|
|
+// 用参数生成矩形顶点并写进缓冲
|
|
|
+
|
|
|
+function setRectangle(gl, x, y, width, height) {
|
|
|
+ var x1 = x;
|
|
|
+ var x2 = x + width;
|
|
|
+ var y1 = y;
|
|
|
+ var y2 = y + height;
|
|
|
+
|
|
|
+ // 注意: gl.bufferData(gl.ARRAY_BUFFER, ...) 将会影响到
|
|
|
+ // 当前绑定点`ARRAY_BUFFER`的绑定缓冲
|
|
|
+ // 目前我们只有一个缓冲,如果我们有多个缓冲
|
|
|
+ // 我们需要先将所需缓冲绑定到`ARRAY_BUFFER`
|
|
|
+
|
|
|
+ gl.bufferData(
|
|
|
+ gl.ARRAY_BUFFER,
|
|
|
+ new Float32Array([x1, y1, x2, y1, x1, y2, x1, y2, x2, y1, x2, y2]),
|
|
|
+ gl.STATIC_DRAW
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ const gl = canvas.value.getContext("webgl");
|
|
|
+
|
|
|
+ const vertexShader = createShader(
|
|
|
+ gl,
|
|
|
+ gl.VERTEX_SHADER,
|
|
|
+ `
|
|
|
+ // 一个属性变量,将会从缓冲中获取数据
|
|
|
+ attribute vec2 a_position;
|
|
|
+
|
|
|
+ uniform vec2 u_resolution;
|
|
|
+ varying vec4 v_color;
|
|
|
+
|
|
|
+ void main() {
|
|
|
+ // 从像素坐标转换到 0.0 到 1.0
|
|
|
+ vec2 zeroToOne = a_position / u_resolution;
|
|
|
+
|
|
|
+ // 再把 0->1 转换 0->2
|
|
|
+ vec2 zeroToTwo = zeroToOne * 2.0;
|
|
|
+
|
|
|
+ // 把 0->2 转换到 -1->+1 (裁剪空间)
|
|
|
+ vec2 clipSpace = zeroToTwo - 1.0;
|
|
|
+
|
|
|
+ // gl_Position = vec4(clipSpace, 0, 1);
|
|
|
+
|
|
|
+ gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
|
|
|
+
|
|
|
+ v_color = gl_Position * 0.5 + 0.5;
|
|
|
+
|
|
|
+ }
|
|
|
+ `
|
|
|
+ );
|
|
|
+ const fragmentShader = createShader(
|
|
|
+ gl,
|
|
|
+ gl.FRAGMENT_SHADER,
|
|
|
+ `
|
|
|
+ // 片段着色器没有默认精度,所以我们需要设置一个精度
|
|
|
+ // mediump是一个不错的默认值,代表“medium precision”(中等精度)
|
|
|
+ precision mediump float;
|
|
|
+
|
|
|
+ uniform vec4 u_color;
|
|
|
+
|
|
|
+ varying vec4 v_color;
|
|
|
+
|
|
|
+ void main() {
|
|
|
+ // gl_FragColor = u_color;
|
|
|
+ gl_FragColor = u_color;
|
|
|
+ }
|
|
|
+ `
|
|
|
+ );
|
|
|
+ var program = createProgram(gl, vertexShader, fragmentShader);
|
|
|
+ var positionAttributeLocation = gl.getAttribLocation(program, "a_position");
|
|
|
+ var resolutionUniformLocation = gl.getUniformLocation(
|
|
|
+ program,
|
|
|
+ "u_resolution"
|
|
|
+ );
|
|
|
+
|
|
|
+ var positionBuffer = gl.createBuffer();
|
|
|
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
|
|
+ // gl.bufferData(
|
|
|
+ // gl.ARRAY_BUFFER,
|
|
|
+ // new Float32Array([0, 0, 0, 0.5, 0.5, 0]),
|
|
|
+ // gl.STATIC_DRAW
|
|
|
+ // );
|
|
|
+
|
|
|
+ gl.bufferData(
|
|
|
+ gl.ARRAY_BUFFER,
|
|
|
+ new Float32Array([0, 0, 0, 100, 100, 0, 500, 0, 500, 100, 400, 0]),
|
|
|
+ gl.STATIC_DRAW
|
|
|
+ );
|
|
|
+
|
|
|
+ gl.useProgram(program);
|
|
|
+ gl.enableVertexAttribArray(resolutionUniformLocation);
|
|
|
+ gl.uniform2f(resolutionUniformLocation, gl.canvas.width, gl.canvas.height);
|
|
|
+
|
|
|
+ window.webglUtils.resizeCanvasToDisplaySize(gl.canvas);
|
|
|
+ gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
|
|
|
+
|
|
|
+ gl.clearColor(0, 0, 0, 0);
|
|
|
+ gl.clear(gl.COLOR_BUFFER_BIT);
|
|
|
+
|
|
|
+ var size = 2; // 每次迭代运行提取两个单位数据
|
|
|
+ var type = gl.FLOAT; // 每个单位的数据类型是32位浮点型
|
|
|
+ var normalize = false; // 不需要归一化数据
|
|
|
+ var stride = 0; // 0 = 移动单位数量 * 每个单位占用内存(sizeof(type)) 每次迭代运行运动多少内存到下一个数据开始点
|
|
|
+ var offset = 0; // 从缓冲起始位置开始读取
|
|
|
+ gl.vertexAttribPointer(
|
|
|
+ resolutionUniformLocation,
|
|
|
+ size,
|
|
|
+ type,
|
|
|
+ normalize,
|
|
|
+ stride,
|
|
|
+ offset
|
|
|
+ );
|
|
|
+
|
|
|
+ var primitiveType = gl.TRIANGLES;
|
|
|
+ gl.drawArrays(primitiveType, 0, 100);
|
|
|
+
|
|
|
+ var colorUniformLocation = gl.getUniformLocation(program, "u_color");
|
|
|
+
|
|
|
+ // 绘制50个随机颜色矩形
|
|
|
+ for (var ii = 0; ii < 50; ++ii) {
|
|
|
+ // 创建一个随机矩形
|
|
|
+ // 并将写入位置缓冲
|
|
|
+ // 因为位置缓冲是我们绑定在
|
|
|
+ // `ARRAY_BUFFER`绑定点上的最后一个缓冲
|
|
|
+ setRectangle(
|
|
|
+ gl,
|
|
|
+ randomInt(300),
|
|
|
+ randomInt(300),
|
|
|
+ randomInt(300),
|
|
|
+ randomInt(300)
|
|
|
+ );
|
|
|
+
|
|
|
+ // 设置一个随机颜色
|
|
|
+ gl.uniform4f(
|
|
|
+ colorUniformLocation,
|
|
|
+ Math.random(),
|
|
|
+ Math.random(),
|
|
|
+ Math.random(),
|
|
|
+ 1
|
|
|
+ );
|
|
|
+
|
|
|
+ // 绘制矩形
|
|
|
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
|
|
|
+ }
|
|
|
+});
|
|
|
+</script>
|