一.实现效果
二.逻辑
为了在WebGL中给图片添加背景,主要的逻辑步骤包括初始化WebGL上下文、编写和编译着色器、创建和绑定缓冲区、加载和配置纹理以及绘制场景。以下是代码逻辑的详细说明:
1. 获取WebGL上下文
首先,通过获取<canvas>
元素并调用getContext('webgl')
方法来初始化WebGL上下文。
const canvas = document.getElementById('canvas');
const gl = canvas.getContext('webgl');
2. 定义顶点着色器和片段着色器
编写顶点着色器(vertex shader)和片段着色器(fragment shader)。顶点着色器负责处理顶点数据,并将纹理坐标传递给片段着色器;片段着色器则使用纹理坐标来获取纹理颜色,并将其绘制到屏幕上。
const vsSource = `attribute vec4 aPosition;attribute vec2 aTexCoord;varying vec2 vTexCoord;void main() {gl_Position = aPosition;vTexCoord = aTexCoord;}
`;const fsSource = `precision mediump float;varying vec2 vTexCoord;uniform sampler2D uSampler;void main() {gl_FragColor = texture2D(uSampler, vTexCoord);}
`;
3. 初始化WebGL着色器程序
编译和链接着色器程序,然后使用该程序。
const program = initShader(gl, vsSource, fsSource);
gl.useProgram(program);
4. 定义顶点数据和索引数据
定义包含顶点位置和纹理坐标的顶点数据,以及用于绘制四边形的索引数据。顶点数据每个顶点包含5个元素(x, y, z, s, t),其中(x, y, z)是顶点位置,(s, t)是纹理坐标。
const vertices = new Float32Array([-1.0, 1.0, 0.0, 0.0, 1.0,-1.0, -1.0, 0.0, 0.0, 0.0,1.0, 1.0, 0.0, 1.0, 1.0,1.0, -1.0, 0.0, 1.0, 0.0,
]);const indices = new Uint16Array([0, 1, 2, 1, 2, 3]);const vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);const indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
5. 获取着色器中的变量位置并启用顶点属性数组
获取着色器中属性和统一变量的位置,并启用顶点属性数组。
const aPosition = gl.getAttribLocation(program, 'aPosition');
const aTexCoord = gl.getAttribLocation(program, 'aTexCoord');
const uSampler = gl.getUniformLocation(program, 'uSampler');gl.vertexAttribPointer(aPosition, 3, gl.FLOAT, false, 20, 0);
gl.enableVertexAttribArray(aPosition);gl.vertexAttribPointer(aTexCoord, 2, gl.FLOAT, false, 20, 12);
gl.enableVertexAttribArray(aTexCoord);
6. 创建纹理对象并加载图片
创建纹理对象,加载图片并配置纹理参数。当图片加载完成时,配置纹理并调用绘制函数。
const texture = gl.createTexture();
const image = new Image();
image.src = '../asset/border.png'; // 这里需要指定背景图片的路径
image.onload = () => {gl.bindTexture(gl.TEXTURE_2D, texture);gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1); // 翻转图片Y轴// 配置纹理参数gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);// 配置纹理图像gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image);gl.uniform1i(uSampler, 0);// 绘制场景drawScene();
}
7. 绘制场景
清除颜色缓冲区,激活纹理单元并绑定纹理,绘制包含纹理的四边形。
function drawScene() {gl.clear(gl.COLOR_BUFFER_BIT);gl.activeTexture(gl.TEXTURE0); // 激活纹理单元gl.bindTexture(gl.TEXTURE_2D, texture);// 绘制背景gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
}
三.完整代码
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>WebGL Background Image</title><style>* {margin: 0;padding: 0;}canvas {margin: 50px auto 0;display: block;background: yellow;}</style><script src="test.js"></script></head><body><canvas id="canvas" width="400" height="400"></canvas><script>// 获取WebGL上下文const canvas = document.getElementById('canvas')const gl = canvas.getContext('webgl')if (!gl) {console.error('Unable to initialize WebGL.')} else {// 定义顶点着色器和片段着色器const vsSource = `attribute vec4 aPosition;attribute vec2 aTexCoord;varying vec2 vTexCoord;void main() {gl_Position = aPosition;vTexCoord = aTexCoord;}`const fsSource = `precision mediump float;varying vec2 vTexCoord;uniform sampler2D uSampler;void main() {gl_FragColor = texture2D(uSampler, vTexCoord);}`const program = initShader(gl, vsSource, fsSource)gl.useProgram(program)// 定义顶点数据const vertices = new Float32Array([-1.0, 1.0, 0.0, 0.0, 1.0, -1.0, -1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, -1.0, 0.0, 1.0, 0.0])const indices = new Uint16Array([0, 1, 2, 1, 2, 3])const vertexBuffer = gl.createBuffer()gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer)gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW)const indexBuffer = gl.createBuffer()gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer)gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW)// 获取着色器中的变量位置const aPosition = gl.getAttribLocation(program, 'aPosition')const aTexCoord = gl.getAttribLocation(program, 'aTexCoord')const uSampler = gl.getUniformLocation(program, 'uSampler')gl.vertexAttribPointer(aPosition, 3, gl.FLOAT, false, 20, 0)gl.enableVertexAttribArray(aPosition)gl.vertexAttribPointer(aTexCoord, 2, gl.FLOAT, false, 20, 12)gl.enableVertexAttribArray(aTexCoord)// 创建纹理对象const texture = gl.createTexture()const image = new Image()image.src = '../asset/border.png' // 这里需要指定背景图片的路径image.onload = () => {gl.bindTexture(gl.TEXTURE_2D, texture)gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1) // 翻转图片Y轴// 配置纹理参数gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)// 配置纹理图像gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image)gl.uniform1i(uSampler, 0)// 绘制场景drawScene()}// 绘制场景function drawScene() {gl.clear(gl.COLOR_BUFFER_BIT)gl.activeTexture(gl.TEXTURE0) // 激活纹理单元gl.bindTexture(gl.TEXTURE_2D, texture)// 绘制背景gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0)}}</script></body>
</html>