基础知识:
绘制基础正方体:
构成正方体的基础单元为三角形,顶点默认逆时针连接,此时的面为正面,顺时针点连接的面为背面。
Q:为什么使用三角形?
A:1、简单 2、生成模型拟合度高较光滑 3、图形处理的高效性
多边形和曲面可能具有复杂的几何形状,但是由于三角形具有逼近性,通过合理的三角剖分可以很好地逼近复杂形状。在每个小三角形内部可以进行插值计算,从而实现光滑的渐变效果,提高渲染质量。计算机图形学中很多技术和算法都是基于三角形的,如光栅化、像素填充、着色和纹理映射等。通过使用三角形作为基本元素,这些算法可以更加高效地运行,从而加速图像处理和渲染过程。(Imagination官方博客-优快云博客)
背面剔除:
绘制简单纯色正方体:
绘制贴图正方体:
添加事件:
效果:
源码:
绘制正方形(initBuffer)
// v6----- v5
// /| /|
// v1------v0|
// | | | |
// | |v7---|-|v4
// |/ |/
// v2------v3
// 初始化缓冲区并设置矩阵
function initBuffer() {
// 定义立方体的顶点数据,每个顶点包含4个分量(x, y, z, w),其中w通常用于齐次坐标
let arr = [
// 前面
1, 1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1,
// 右面
1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1,
// 后面
-1, 1, -1, 1, 1, 1, -1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1,
// 左面
-1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, 1, 1, 1, -1, -1, -1, 1, -1, -1, 1, 1,
// 上面
-1, 1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1, 1,
// 下面
-1, -1, 1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1
]
// 创建一个Float32Array类型的数组来存储顶点数据
let pointPosition = new Float32Array(arr);
// 获取顶点着色器中位置属性的位置
let aPosition = webgl.getAttribLocation(webgl.program, "a_position");
// 创建一个缓冲区对象
let triangleBuffer = webgl.createBuffer();
webgl.bindBuffer(webgl.ARRAY_BUFFER, triangleBuffer);
webgl.bufferData(webgl.ARRAY_BUFFER, pointPosition, webgl.STATIC_DRAW);
webgl.enableVertexAttribArray(aPosition);
webgl.vertexAttribPointer(aPosition, 4, webgl.FLOAT, false, 4 * 4, 0);
// 初始化投影矩阵
let ProjMatrix = glMatrix.mat4.create();
glMatrix.mat4.identity(ProjMatrix);
// 设置透视投影矩阵,参数为:矩阵、角度(转换为弧度)、宽高比、近剪裁面、远剪裁面
glMatrix.mat4.perspective(ProjMatrix, angle * Math.PI / 180, webglDiv.clientWidth / webglDiv.clientHeight, 1, 1000);
// 获取uniform变量u_formMatrix的位置
let uniformMatrix1 = webgl.getUniformLocation(webgl.program, "u_formMatrix");
// 初始化模型矩阵
let ModelMatrix = glMatrix.mat4.create();
glMatrix.mat4.identity(ModelMatrix);
// 沿x轴平移模型
glMatrix.mat4.translate(ModelMatrix, ModelMatrix, [1, 0, 0]);
// 初始化视图矩阵
let ViewMatrix = glMatrix.mat4.create();
glMatrix.mat4.identity(ViewMatrix);
// 设置视图矩阵,参数为:矩阵、相机位置、目标位置、上方向
glMatrix.mat4.lookAt(ViewMatrix, [5, 0, 0], [0, 0, 0], [0, 1, 0]);
// 计算模型视图矩阵
let mvMatrix = glMatrix.mat4.create();
glMatrix.mat4.identity(mvMatrix);
glMatrix.mat4.multiply(mvMatrix, ViewMatrix, ModelMatrix);
// 计算模型视图投影矩阵
let mvpMatrix = glMatrix.mat4.create();
glMatrix.mat4.identity(mvpMatrix);
glMatrix.mat4.multiply(mvpMatrix, ProjMatrix, mvMatrix);
// 将模型视图投影矩阵传递给着色器
webgl.uniformMatrix4fv(uniformMatrix1, false, mvpMatrix);
// 设置清除颜色为黑色,并清除颜色缓冲区和深度缓冲区
webgl.clearColor(0, 0, 0, 1);
webgl.clear(webgl.COLOR_BUFFER_BIT | webgl.DEPTH_BUFFER_BIT);
// 启用深度测试
webgl.enable(webgl.DEPTH_TEST);
// 绘制36个顶点的三角形
webgl.drawArrays(webgl.TRIANGLES, 0, 36);
}
简单矩形
let aColor = webgl.getAttribLocation(webgl.program, "a_color");
webgl.enableVertexAttribArray(aColor);
webgl.vertexAttribPointer(aColor, 4, webgl.FLOAT, false, 8 * 4, 4 * 4);
vertexAttribPointer(index, size, type, normalized, stride, offset)
告诉显卡从当前绑定的缓冲区(bindBuffer() 指定的缓冲区)中读取顶点数据。WebGL API 的 WebGLRenderingContext.vertexAttribPointer()
方法绑定当前缓冲区范围到gl.ARRAY_BUFFER
,成为当前顶点缓冲区对象的通用顶点属性并指定它的布局 (缓冲区对象中的偏移量)。
指定要修改的顶点属性的索引。
指定每个顶点属性的组成数量,必须是 1,2,3 或 4。
指定数组中每个元素的数据类型可能是:
-
gl.BYTE
: 有符号的 8 位整数,范围 [-128, 127] -
gl.SHORT
: 有符号的 16 位整数,范围 [-32768, 32767] -
gl.UNSIGNED_BYTE
:无符号的 8 位整数,范围 [0, 255] -
gl.UNSIGNED_SHORT
: 无符号的 16 位整数,范围 [0, 65535] -
gl.FLOAT
: 32 位 IEEE 标准的浮点数 -
使用 WebGL2 版本的还可以使用以下值:
gl.HALF_FLOAT
: 16 位 IEEE 标准的浮点数
当转换为浮点数时是否应该将整数数值归一化到特定的范围。
- 对于类型
gl.BYTE
和gl.SHORT
,如果是 true 则将值归一化为 [-1, 1] - 对于类型
gl.UNSIGNED_BYTE
和gl.UNSIGNED_SHORT
,如果是 true 则将值归一化为 [0, 1] - 对于类型
gl.FLOAT
和gl.HALF_FLOAT
,此参数无效
一个 GLsizei,以字节为单位指定连续顶点属性开始之间的偏移量 (即数组中一行长度)。不能大于 255。如果 stride 为 0,则假定该属性是紧密打包的,即不交错属性,每个属性在一个单独的块中,下一个顶点的属性紧跟当前顶点之后。
GLintptr指定顶点属性数组中第一部分的字节偏移量。必须是类型的字节长度的倍数。
贴图矩形
let attribOutUV = webgl.getAttribLocation(webgl.program, "a_outUV");
webgl.enableVertexAttribArray(attribOutUV);
webgl.vertexAttribPointer(attribOutUV, 2, webgl.FLOAT, false, 6 * 4, 4 * 4);
//矩阵变换
let ProjMatrix = glMatrix.mat4.create();
glMatrix.mat4.identity(ProjMatrix);
//角度小,看到的物体大,角度大,看到的物体小。
glMatrix.mat4.perspective(ProjMatrix, angle * Math.PI / 180, webglDiv.clientWidth / webglDiv.clientHeight, 1, 1000) //修改可视域范围
let uniformMatrix1 = webgl.getUniformLocation(webgl.program, "u_formMatrix");
let ModelMatrix = glMatrix.mat4.create();
glMatrix.mat4.identity(ModelMatrix);
glMatrix.mat4.translate(ModelMatrix, ModelMatrix, [0, 0, 0]);
let ViewMatrix = glMatrix.mat4.create();
glMatrix.mat4.identity(ViewMatrix);
glMatrix.mat4.lookAt(ViewMatrix, [5, 5, 5], [0, 0, 0], [0, 1, 0]);
let mvMatrix = glMatrix.mat4.create();
glMatrix.mat4.identity(mvMatrix);
glMatrix.mat4.multiply(mvMatrix, ViewMatrix, ModelMatrix);
let mvpMatrix = glMatrix.mat4.create();
glMatrix.mat4.identity(mvpMatrix);
glMatrix.mat4.multiply(mvpMatrix, ProjMatrix, mvMatrix);
webgl.uniformMatrix4fv(uniformMatrix1, false, mvpMatrix)
//纹理绘制
uniformTexture = webgl.getUniformLocation(webgl.program, "texture");
texture = initTexture("container2_specular.png");
交互事件
// 初始化缓冲区并设置矩阵变换
function initBuffer() {
// 顶点数据准备,包含顶点位置和UV坐标
let arr = [
// 前面
1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 0, 1, -1, -1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 0, 0, 1, -1, 1, 1, 1, 0,
// 右面
1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, -1, 1, 1, 0, 0, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, 0, 0, 1, -1, -1, 1, 1, 0,
// 后面
-1, 1, -1, 1, 1, 1, 1, 1, -1, 1, 0, 1, 1, -1, -1, 1, 0, 0, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 0, 0, -1, -1, -1, 1, 1, 0,
// 左面
-1, 1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 0, -1, -1, -1, 1, 0, 0, -1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 0, 0, -1, -1, 1, 1, 1, 0,
// 上面
-1, 1, -1, 1, 0, 1, -1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, -1, 1, -1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, -1, 1, 1, 1,
// 下面
-1, -1, 1, 1, 0, 1, -1, -1, -1, 1, 0, 0, 1, -1, -1, 1, 1, 0, -1, -1, 1, 1, 0, 1, 1, -1, -1, 1, 1, 0, 1, -1, 1, 1, 1, 1
]
// 创建一个Float32Array类型的数组来存储顶点数据
let pointPosition = new Float32Array(arr);
// 获取顶点着色器中位置属性的位置
let aPosition = webgl.getAttribLocation(webgl.program, "a_position");
// 创建一个缓冲区对象
let triangleBuffer = webgl.createBuffer();
webgl.bindBuffer(webgl.ARRAY_BUFFER, triangleBuffer);
webgl.bufferData(webgl.ARRAY_BUFFER, pointPosition, webgl.STATIC_DRAW);
webgl.enableVertexAttribArray(aPosition);
webgl.vertexAttribPointer(aPosition, 4, webgl.FLOAT, false, 6 * 4, 0);
// 获取顶点着色器中UV坐标属性的位置
let attribOutUV = webgl.getAttribLocation(webgl.program, "a_outUV");
webgl.enableVertexAttribArray(attribOutUV);
webgl.vertexAttribPointer(attribOutUV, 2, webgl.FLOAT, false, 6 * 4, 4 * 4);
// 矩阵变换
let ProjMatrix = glMatrix.mat4.create();
glMatrix.mat4.identity(ProjMatrix);
// 设置透视投影矩阵
glMatrix.mat4.perspective(ProjMatrix, angle * Math.PI / 180, webglDiv.clientWidth / webglDiv.clientHeight, 1, 1000);
let uniformMatrix1 = webgl.getUniformLocation(webgl.program, "u_formMatrix");
// 模型矩阵的旋转
let ModelMatrixx = glMatrix.mat4.create();
glMatrix.mat4.identity(ModelMatrixx);
glMatrix.mat4.rotate(ModelMatrixx, ModelMatrixx, offsetX * Math.PI / 180, [0, 1, 0]);
let ModelMatrixy = glMatrix.mat4.create();
glMatrix.mat4.identity(ModelMatrixy);
glMatrix.mat4.rotate(ModelMatrixy, ModelMatrixy, offsetY * Math.PI / 180, [1, 0, 0]);
let ModelMatrixxy = glMatrix.mat4.create();
glMatrix.mat4.identity(ModelMatrixxy);
glMatrix.mat4.multiply(ModelMatrixxy, ModelMatrixx, ModelMatrixy);
// 模型矩阵的平移
let ModelMatrixWheel = glMatrix.mat4.create();
glMatrix.mat4.identity(ModelMatrixWheel);
console.log(wheelMove);
glMatrix.mat4.translate(ModelMatrixWheel, ModelMatrixWheel, [0, 0, wheelMove]);
glMatrix.mat4.multiply(ModelMatrixWheel, ModelMatrixWheel, ModelMatrixxy);
// 视图矩阵
let ViewMatrix = glMatrix.mat4.create();
glMatrix.mat4.identity(ViewMatrix);
glMatrix.mat4.lookAt(ViewMatrix, [0, 0, 10], [0, 0, 0], [0, 1, 0]);
// 模型视图矩阵
let mvMatrix = glMatrix.mat4.create();
glMatrix.mat4.identity(mvMatrix);
glMatrix.mat4.multiply(mvMatrix, ViewMatrix, ModelMatrixWheel);
// 模型视图投影矩阵
let mvpMatrix = glMatrix.mat4.create();
glMatrix.mat4.identity(mvpMatrix);
glMatrix.mat4.multiply(mvpMatrix, ProjMatrix, mvMatrix);
webgl.uniformMatrix4fv(uniformMatrix1, false, mvpMatrix);
// 纹理绘制
let uniformTexture = webgl.getUniformLocation(webgl.program, "texture");
let texture = initTexture("container2_specular.png");
}
// 初始化纹理
function initTexture(imageFile) {
let textureHandle = webgl.createTexture();
textureHandle.image = new Image();
textureHandle.image.src = imageFile;
textureHandle.image.onload = function () {
handleLoadedTexture(textureHandle);
}
return textureHandle;
}
// 处理加载完成的纹理
function handleLoadedTexture(texture) {
webgl.bindTexture(webgl.TEXTURE_2D, texture);
webgl.pixelStorei(webgl.UNPACK_FLIP_Y_WEBGL, true);
webgl.texImage2D(webgl.TEXTURE_2D, 0, webgl.RGBA, webgl.RGBA, webgl.UNSIGNED_BYTE, texture.image);
webgl.texParameteri(webgl.TEXTURE_2D, webgl.TEXTURE_MAG_FILTER, webgl.LINEAR); // 纹理放大方式
webgl.texParameteri(webgl.TEXTURE_2D, webgl.TEXTURE_MIN_FILTER, webgl.LINEAR); // 纹理缩小方式
webgl.texParameteri(webgl.TEXTURE_2D, webgl.TEXTURE_WRAP_S, webgl.CLAMP_TO_EDGE); // 纹理水平填充方式
webgl.texParameteri(webgl.TEXTURE_2D, webgl.TEXTURE_WRAP_T, webgl.CLAMP_TO_EDGE); // 纹理垂直填充方式
// 清除颜色缓冲区和深度缓冲区
webgl.clearColor(0, 0, 0, 1);
webgl.clear(webgl.COLOR_BUFFER_BIT | webgl.DEPTH_BUFFER_BIT);
// 启用深度测试
webgl.enable(webgl.DEPTH_TEST);
// 激活纹理单元
webgl.activeTexture(webgl.TEXTURE0);
// 绑定纹理
webgl.bindTexture(webgl.TEXTURE_2D, texture);
// 将纹理传递给着色器
webgl.uniform1i(uniformTexture, 0);
// 绘制三角形
webgl.drawArrays(webgl.TRIANGLES, 0, 36);
}
WebGL API 的 WebGLRenderingContext.bindTexture()
方法将给定的 WebGLTexture 绑定到目标(绑定点)。