对webgl 一些简单的使用方法做了示例展示,给出webgl 绘制功能制基本要素。要了解更多关于webgl内容查看详情
<template>
<canvas id="parkingLot" ref="parkingLot"></canvas>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from "vue";
const parkingLot = ref();
onMounted(async () => {
const scpt = document.createElement("script");
scpt.src ="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.8.1/gl-matrix-min.js";
document.head.appendChild(scpt);
scpt.onload = () => {
var then = 0;
var squareRotation = 0.0;
const DOMEl = parkingLot.value;
console.log(DOMEl,"DOMEl")
const gl = DOMEl.getContext("webgl")
// 获取 DOMEl 的宽度和高度,以设置渲染器的大小。
// const width = DOMEl.clientWidth;
// const height = DOMEl.clientHeight;
gl.clearColor(0.0,0.0,1.0,1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
// 以下的顶点着色器接收一个我们定义的属性(aVertexPosition)的顶点位置值。之后这个值与两个 4x4 的矩阵(uProjectionMatrix 和 uModelMatrix)相乘; 乘积赋值给 gl_Position。
const vsSource = `
attribute vec4 aVertexPosition;
attribute vec4 aVertexColor;
uniform mat4 uModelViewMatrix;
uniform mat4 uProjectionMatrix;
varying lowp vec4 vColor;
void main(void) {
gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
vColor = aVertexColor;
}
`;
// 定义一个白色的片段着色器
const fsSource = `
varying lowp vec4 vColor;
void main(void) {
gl_FragColor = vColor;
}
`;
// 初始化着色器程序,让 WebGL 知道如何绘制我们的数据
function initShaderProgram(gl, vsSource, fsSource) {
const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
// 创建着色器程序
const shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
// 如果创建失败,alert
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert(
"Unable to initialize the shader program: " +
gl.getProgramInfoLog(shaderProgram),
);
return null;
}
return shaderProgram;
}
// 创建指定类型的着色器,上传 source 源码并编译
function loadShader(gl, type, source) {
// 调用gl.createShader().创建一个新的着色器。
const shader = gl.createShader(type);
// 调用gl.shaderSource().将源代码发送到着色器。
gl.shaderSource(shader, source);
// 一旦着色器获取到源代码,就使用gl.compileShader().进行编译。
gl.compileShader(shader);
// 为了检查是否成功编译了着色器,将检查着色器参数 gl.COMPILE_STATUS 状态。通过调用gl.getShaderParameter()获得它的值,并指定着色器和我们想要检查的参数的名字(gl.COMPILE_STATUS)。如果返回错误,则着色器无法编译,因此通过gl.getShaderInfoLog()从编译器中获取日志信息并 alert,然后删除着色器返回 null,表明加载着色器失败。
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert(
"An error occurred compiling the shaders: " + gl.getShaderInfoLog(shader),
);
gl.deleteShader(shader);
return null;
}
// 如果着色器被加载并成功编译,则返回编译的着色器。
return shader;
}
const shaderProgram = initShaderProgram(gl, vsSource, fsSource);
const programInfo = {
program: shaderProgram,
attribLocations: {
// 获取 shaderProgram 中的 aVertexPosition
vertexPosition: gl.getAttribLocation(shaderProgram, "aVertexPosition"),
vertexColor: gl.getAttribLocation(shaderProgram, "aVertexColor"),
},
uniformLocations: {
// 获取 shaderProgram 中的对应属性
projectionMatrix: gl.getUniformLocation(shaderProgram, "uProjectionMatrix"),
modelViewMatrix: gl.getUniformLocation(shaderProgram, "uModelViewMatrix"),
},
};
function initBuffers(gl) {
// 初始化位息信息
const positionBuffer = initPositionBuffer(gl);
const colorBuffer = initColorBuffer(gl);
// 返回位置信息
return {
position: positionBuffer,
color: colorBuffer
};
};
function initColorBuffer(gl) {
const colors = [
1.0,
1.0,
1.0,
1.0, // 白
1.0,
0.0,
0.0,
1.0, // 红
0.0,
1.0,
0.0,
1.0, // 绿
0.0,
0.0,
1.0,
1.0, // 蓝
];
const colorBuffer = gl.createBuffer();
// 通过这两个步骤,颜色数据就存储在 colorBuffer 缓冲区中,可以被GPU访问,并在后续的绘制操作中使用这些颜色数据渲染图形。
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);// gl.bindBuffer 是将一个缓冲区绑定到WebGL的目标(ARRAY_BUFFER)。
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);// gl.bufferData 则是将颜色数据加载到绑定的缓冲区中,这些数据将被发送到GPU,用于着色器中的颜色属性。
return colorBuffer;
}
function initPositionBuffer(gl) {
// 创建一个 gl buffer
const positionBuffer = gl.createBuffer();
// 将 gl 绑定 为 array buffer 信息
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
// 给出一个正方形的位置数据信息
const positions = [1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, -1.0];
// 将 gl buffer 设置为 信息
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
return positionBuffer;
};
function setColorAttribute(gl, buffers, programInfo) {
const numComponents = 4;
const type = gl.FLOAT;
const normalize = false;
const stride = 0;
const offset = 0;
gl.bindBuffer(gl.ARRAY_BUFFER, buffers.color);
gl.vertexAttribPointer(
programInfo.attribLocations.vertexColor,
numComponents,
type,
normalize,
stride,
offset,
);
gl.enableVertexAttribArray(programInfo.attribLocations.vertexColor);
}
function drawScene(gl, programInfo, buffers, deltaTime) {
gl.clearColor(0.0, 0.0, 0.0, 1.0); // 将场影颜色初始化为 黑色
gl.clearDepth(1.0); // 清除深度信息
gl.enable(gl.DEPTH_TEST); // 启用深度测试
gl.depthFunc(gl.LEQUAL); // Near things obscure far things
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
const fieldOfView = (45 * Math.PI) / 180; // 观查角度
const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;// 宽度比
const zNear = 0.1; // 近截剪距离
const zFar = 100.0; // 远截剪距离
const projectionMatrix = mat4.create(); // 创建矩阵
// 设置矩阵信息
mat4.perspective(projectionMatrix, fieldOfView, aspect, zNear, zFar);
// 创建矩阵
const modelViewMatrix = mat4.create();
// 设置移动位置
mat4.translate(
modelViewMatrix,
modelViewMatrix,
[-0.0, 0.0, -6.0],
);
mat4.rotate(
modelViewMatrix, // destination matrix
modelViewMatrix, // matrix to rotate
squareRotation, // amount to rotate in radians
[0, 0, 1],
); // axis to rotate around
{
const numComponents = 2; // 每次从缓冲区读取的值数量,这里设置为2,表示每次读取2个数值。这个常用于2D坐标,比如一个顶点的(x, y)位置。
const type = gl.FLOAT; // 指定缓冲区数据的类型,这里是32位浮点数。顶点位置的每个组件都是浮点数。
const normalize = false; // 是否将数据归一化,设置为 false 表示不归一化。如果数据本身已经是正确的值(如坐标),则不需要归一化。
const stride = 0; // 步幅,表示从一个顶点到下一个顶点需要跳过多少字节。 这里设置为 0 表示顶点数据是紧密排列的,一个接着一个。
const offset = 0; // 缓冲区中从哪个字节开始读取数据。这里从头开始读取,所以是0。
gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position); // 将包含顶点位置数据的缓冲区绑定到 ARRAY_BUFFER。 绑定了 buffers.position 缓冲区,WebGL会接下来使用这个缓冲区。
// 告诉WebGL如何从绑定的缓冲区中获取数据。
gl.vertexAttribPointer(
programInfo.attribLocations.vertexPosition,
numComponents,
type,
normalize,
stride,
offset,
);
// 启用顶点属性数组。 WebGL默认禁用顶点属性,需要显式启用这个属性数组,才能进行渲染。
gl.enableVertexAttribArray(programInfo.attribLocations.vertexPosition);
}
setColorAttribute(gl, buffers, programInfo);
// 告诉WebGL使用 programInfo.program 着色器程序进行绘制。 programInfo.program 是编译并链接好的着色器程序,WebGL在绘制时会使用这个程序。这个程序中包含顶点着色器和片段着色器。
gl.useProgram(programInfo.program);
// 将矩阵数据传递给着色器中的uniform变量。这里的 uniformMatrix4fv 用来传递4x4的浮点数矩阵,主要用于在顶点着色器中进行坐标变换。
gl.uniformMatrix4fv(
// programInfo.uniformLocations.projectionMatrix,这是着色器中投影矩阵的uniform变量的位置。
programInfo.uniformLocations.projectionMatrix,
// false 表示矩阵不需要转置。
false,
// projectionMatrix 是传递给着色器的实际矩阵数据。
projectionMatrix,
);
// 第二次调用传递的是 modelViewMatrix,这是模型视图矩阵。总的来说,这两个矩阵会用来进行顶点的变换,从局部坐标转换到屏幕坐标。
gl.uniformMatrix4fv(
programInfo.uniformLocations.modelViewMatrix,
false,
modelViewMatrix,
);
{
// 绘制时从第一个顶点开始。
const offset = 0;
// 绘制四个顶点。
const vertexCount = 4;
// 通过绘制方法 gl.drawArrays 来实际渲染图形 这里的 gl.TRIANGLE_STRIP 指定了要绘制的图元类型,TRIANGLE_STRIP 是一种可以用最少的顶点创建多个三角形的方法:
gl.drawArrays(gl.TRIANGLE_STRIP, offset, vertexCount);
};
squareRotation += deltaTime;
};
// 初始化buffer数据
const buffers = initBuffers(gl);
// Draw the scene repeatedly
function render(now) {
now *= 0.001; // convert to seconds
const deltaTime = now - then;
then = now;
drawScene(gl, programInfo, buffers, deltaTime);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
});
</script>
<style lang="scss" scoped="scoped">
#parkingLot {
width: 940px;
height: 940px;
border: 1px solid #ccc;
margin: 30px auto;
}
</style>