复现
vite搭建了新项目,设置canvas,然后加载3d模型很虚,然后创建一个点也很虚。
如图所示:

javascript
#app {
width: 100%;
height: 100%;
}
<canvas id="app"></canvas>
原因
画布分辨率问题确实是WebGL中导致图形模糊的最主要原因
实际发生的情况:
默认canvas尺寸:Canvas元素默认是300×150像素
CSS拉伸:CSS将300×150像素的画布拉伸到800×600像素
像素化拉伸:WebGL实际上是在300×150的像素缓冲区中渲染,然后被拉伸显示。
解决方案
javascript
// 在获取WebGL上下文后,设置canvas的实际像素尺寸
const setCanvasSize = (canvas,gl) => {
const dpr = window.devicePixelRatio || 1;
const rect = canvas.getBoundingClientRect();
// 设置canvas的实际像素尺寸(与CSS尺寸分离)
canvas.width = rect.width * dpr;
canvas.height = rect.height * dpr;
// 设置WebGL视口
gl.viewport(0, 0, canvas.width, canvas.height);
};
export {
setCanvasSize
}
// 初始化和窗口大小变化时都调用
setCanvasSize(canvas,gl);
window.addEventListener('resize', () => {
setCanvasSize(canvas,gl)
});
试试鼠标点击生成点的方法中:
javascript
let ponitArr = []
let pointColorArr = []
// 鼠标点击
canvas.addEventListener('click', (event) => {
const rect = canvas.getBoundingClientRect();
// 使用 clientWidth/clientHeight,而不是 width/height
let x = event.clientX - rect.left;
let y = event.clientY - rect.top;
// 正确公式:
x = (x / canvas.clientWidth) * 2 - 1;
y = 1 - (y / canvas.clientHeight) * 2; // Y轴翻转
let point = new Float32Array([x, y, 0]);
let color = new Float32Array([0.0, 1.0, 0.0, 1.0]);
if(x<0 && y<0) {
color = new Float32Array([1.0, 0.0, 0.0, 1.0]); // 左下 红色
} else if(x<0 && y>0){
color = new Float32Array([0.0, 1.0, 0.0, 1.0]); // 左上 绿色
} else if(x>0 && y<0){
color = new Float32Array([0.0, 0.0, 1.0, 1.0]); // 右下 蓝色
} else if(x>0 && y>0){
color = new Float32Array([1.0, 1.0, 0.0, 1.0]); // 右上 黄色
}
ponitArr.push(point);
pointColorArr.push(new Float32Array(color));
gl.clear(gl.COLOR_BUFFER_BIT);
console.log(ponitArr);
ponitArr.forEach((point, index) => {
gl.vertexAttrib3f(a_position, point[0], point[1], 0.0);
gl.uniform4fv(u_FragColor, pointColorArr[index]);
gl.drawArrays(gl.POINTS, 0, 1);
});
});

总结
记住这个黄金法则:
在WebGL中,canvas.width/height(像素尺寸)必须匹配CSS的显示尺寸乘以设备像素比,并且必须调用gl.viewport()设置相同的尺寸。
这是WebGL开发中最常见的"坑"之一!