D03-02
坐标转换显微镜 Coordinate Transformation Microscope
核心问题:“鼠标明明点在 Canvas 这里,为什么 WebGL 绘制出来的点可能跑到别处?”
WebGL 2.0 (ES 3.00)
大学计算机图形学 · 第3章
交互画布 (WebGL Viewport)
支持移动、点击、拖动位置与缩放
坐标系:中心为 (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
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)
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 轴翻转 */
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) 栅格化为屏幕像素
通过视口变换 (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 就保持完全不变!