D03-02

坐标转换显微镜 Coordinate Transformation Microscope

核心问题:“鼠标明明点在 Canvas 这里,为什么 WebGL 绘制出来的点可能跑到别处?”

WebGL 2.0 (ES 3.00) 大学计算机图形学 · 第3章
交互画布 (WebGL Viewport)
支持移动、点击、拖动位置与缩放
Browser Viewport Origin (0, 0)
Canvas Rect: (left: 20px, top: 20px)
坐标系:中心为 (0,0),左下 (-1,-1),右上 (1,1) 已记录点击: 0
坐标转换流水线 (Pipeline)
1Mouse Event 视口坐标 (Y向下)
clientX = -- px clientY = -- px
原点在浏览器视口左上角,y 轴向下增大
↓ 减去 Canvas 页面相对偏移 (BoundingClientRect)
2Canvas CSS 坐标 元素局部坐标
x_css = -- px y_css = -- px
x_css = clientX - rect.left
y_css = clientY - rect.top
↓ 乘以像素密度缩放比 (Buffer / CSS Size)
3Drawing Buffer 像素坐标 1 : 1
x_buf = -- px y_buf = -- px
x_buf = x_css × (canvas.width / rect.width)
y_buf = y_css × (canvas.height / rect.height)
↓ 映射到 [-1, 1] 并翻转 Y 轴
4WebGL NDC 归一化设备坐标 核心映射
x_ndc = -- y_ndc = --
x_ndc = 2.0 × (x_buf / canvas.width) - 1.0
y_ndc = 1.0 - 2.0 × (y_buf / canvas.height) /* Y 轴翻转 */
↓ 顶点着色器 gl_Position 输出
5GPU 栅格化绘制 (Draw Point) 精确重合
gl_Position = vec4(x_ndc, y_ndc, 0.0, 1.0);
通过视口变换 (Viewport Transform) 栅格化为屏幕像素
坐标监视器 (Coordinate Monitor)
Outside Canvas
同一点的三种坐标系统表示:
Browser Viewport
(--, --)
(0,0)在视口左上
Canvas CSS
(--, --)
(0,0)在元素左上
WebGL NDC
(--, --)
[-1, 1] 中心原点
系统与参数 (Properties) 数值 (Values)
Mouse clientX / clientY --, --
Canvas rect.left / rect.top --, --
Canvas CSS Display Size (W × H) 480 × 360 px
Drawing Buffer Size (W × H) 800 × 600 px
CSS 与 Buffer 缩放比率 (Scale X/Y) 1.667 / 1.667
Drawing Buffer 像素 (x_buf, y_buf) --, --
WebGL NDC 坐标 (x_ndc, y_ndc) --, --
⚠️ 常见错误算法对比
错误写法:直接拿 clientX/clientY 当作 Canvas 内部像素除以宽高,忽略页面偏移与尺寸缩放。
错误 NDC: -- 偏移误差 Δ: --
💡 教学观察提示:若改变下方“水平偏移”滑块,尽管 clientX 剧烈变化,但只要鼠标指向 Canvas 相同的相对位置,NDC 就保持完全不变!