解决webgl画面虚问题

复现

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开发中最常见的"坑"之一!

相关推荐
Jmyd01234 天前
3D数字协同设计实训空间技术架构解析:从三维采集到WebGL虚拟展示的全链路实现
3d·架构·webgl·虚拟实训
总要学点什么4 天前
第57篇:三维场景演示_基础版——同一秒,播过去和拖过去差出一千多米
3d·数据挖掘·数据分析·gis·webgl
总要学点什么5 天前
第55篇:空间分析-剖面分析——红线走大圆,剖面却按经纬直线采样
前端框架·gis·webgl·cesium·空间分析
:mnong5 天前
Web 三维可视化技术对比:ParaView Web vs 本项目 wasm + Three.js
前端·webgl·opengl·opencl·科学可视化
疯狂敲代码的老刘5 天前
my-fingerprint浏览器扩展:1.4K星开源指纹防护神器,Canvas/WebGL/WebGPU伪装一键开启
webgl
总要学点什么6 天前
第51篇:数据分析-热力图——笔刷画的是圆,落到地上却成了椭圆
3d·数据挖掘·数据分析·前端框架·gis·webgl·cesium
子龙_6 天前
来在网页上用threejs画个蛋白质吧
前端·webgl·three.js
总要学点什么8 天前
第47篇:三维特效-雷达波效果——波纹一圈圈往外推,一半却埋在地下
3d·前端框架·gis·webgl·cesium
八荒启·交互动画15 天前
Web特效025—用 Canvas 2D 做Web特效的定义与边界:这支画笔能做到哪一步
前端·webgl·网页特效·八荒启-交互动画·八荒启
Bruce_Liuxiaowei16 天前
网页版 DeepSeek “harness desktop“ WebGL 上下文创建失败排查实录
开发语言·javascript·webgl