在WebGL2中,gl.pixelStorei() 是一个用于控制像素存储模式的函数,它允许你设置如何从图像(如PNG、JPEG等)或数据源中读取和解包像素数据。这个函数主要影响 gl.texImage2D()、gl.texSubImage2D() 等操作像素数据的函数的行为。
常用参数:
以下是 gl.pixelStorei() 在WebGL2中常用的参数(第二个参数是整数值):
-
gl.UNPACK_FLIP_Y_WEBGL-
设置为
1(true)时,图像会在上传时垂直翻转(Y轴反转),因为WebGL的纹理坐标原点在左下角,而图像的坐标原点通常在左上角。 -
示例:
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);
-
-
gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL- 设置为
1时,图像的RGB值会预乘Alpha值(即RGB = RGB * (A / 255)),适用于透明纹理的混合处理。
- 设置为
-
gl.UNPACK_COLORSPACE_CONVERSION_WEBGL- 控制是否进行颜色空间转换(默认
gl.NONE,不转换)。
- 控制是否进行颜色空间转换(默认
-
gl.UNPACK_ALIGNMENT-
指定内存中像素数据的对齐方式(默认为4,即每行按4字节对齐)。如果图像数据每行的字节数不是4的倍数,可能需要调整为1、2、4等值以避免解析错误。
-
示例:
gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
-
使用示例:
以下是一个可直接运行的示例, 主要通过 翻转Y轴 来展示pixelStorei()方法的功能
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebGL2 纹理示例(翻转Y轴)</title>
<style>
body { margin: 0; overflow: hidden; }
canvas { display: block; width: 600px; height: 400px; }
</style>
</head>
<body>
<canvas id="glCanvas"></canvas>
<div>
<button onclick="notYFlip()">不翻转</button>
<button onclick="yFlip()">y轴翻转</button>
</div>
<script>
// 编译着色器
function createShader(gl, source, type) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
console.error('着色器编译错误:', gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}
return shader;
}
function createProgram(vertexShader, fragmentShader) {
// 创建着色器程序
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.error('程序链接错误:', gl.getProgramInfoLog(program));
}
return program;
}
function createTexture() {
// 创建纹理
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
// 设置纹理参数(缩小/放大时使用线性过滤)
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_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.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([255, 255, 255, 255]));
return texture;
}
// 渲染函数
function render() {
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.useProgram(program);
// 创建并绑定顶点缓冲区
const vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
// 获取属性位置
const positionLoc = gl.getAttribLocation(program, 'aPosition');
const texCoordLoc = gl.getAttribLocation(program, 'aTexCoord');
// 启用属性
gl.enableVertexAttribArray(positionLoc);
gl.enableVertexAttribArray(texCoordLoc);
// 设置属性指针
const stride = 4 * Float32Array.BYTES_PER_ELEMENT; // 每个顶点4个float(x,y,s,t)
gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, stride, 0);
gl.vertexAttribPointer(texCoordLoc, 2, gl.FLOAT, false, stride, 2 * Float32Array.BYTES_PER_ELEMENT);
// 创建并绑定索引缓冲区
const indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);
}
function loadImg() {
return new Promise((resolve, reject) => {
// 加载图像
const image = new Image();
image.onload = function() {
resolve(image);
};
image.src = './小狼狗.jpg'; // 使用一个示例图片(可替换为你的本地图片)
});
}
async function notYFlip() {
const image = await loadImg();
// 绑定纹理
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
// 将图像数据上传到纹理
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
// 渲染
render();
}
async function yFlip() {
const image = await loadImg();
// 绑定纹理
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
// 将图像数据上传到纹理
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
// 渲染
render();
}
// 初始化WebGL2上下文
const canvas = document.getElementById('glCanvas');
const gl = canvas.getContext('webgl2');
if (!gl) {
alert('您的浏览器不支持WebGL2!');
throw new Error('WebGL2 not supported');
}
// 顶点和纹理坐标数据(一个正方形)
const vertices = new Float32Array([
// 位置 (x, y) 纹理坐标 (s, t)
-0.5, -0.5, 0.0, 1.0, // 左下
0.5, -0.5, 1.0, 1.0, // 右下
0.5, 0.5, 1.0, 0.0, // 右上
-0.5, 0.5, 0.0, 0.0 // 左上
]);
// 索引数据(两个三角形组成正方形)
const indices = new Uint16Array([0, 1, 2, 0, 2, 3]);
// 顶点着色器
const vsSource = `#version 300 es
in vec2 aPosition;
in vec2 aTexCoord;
out vec2 vTexCoord;
void main() {
gl_Position = vec4(aPosition, 0.0, 1.0);
vTexCoord = aTexCoord;
}
`;
// 片段着色器
const fsSource = `#version 300 es
precision highp float;
in vec2 vTexCoord;
uniform sampler2D uTexture;
out vec4 fragColor;
void main() {
fragColor = texture(uTexture, vTexCoord);
}
`;
const vertexShader = createShader(gl, vsSource, gl.VERTEX_SHADER);
const fragmentShader = createShader(gl, fsSource, gl.FRAGMENT_SHADER);
const program = createProgram(vertexShader, fragmentShader);
const texture = createTexture();
notYFlip();
</script>
</body>
</html>
注意事项:
- 这些设置是全局状态,调用后会持续生效,直到再次修改。
- WebGL2还保留了WebGL1的类似参数,并可能新增了一些扩展选项(如
gl.PACK_ROW_LENGTH等)。