附录D:左手还是右手坐标系
The GL does not force left-or right-handedness on of its coordinate systems.
翻译:老是问这种钻牛角尖的问题,都说了左右手都行。
那为什么之前在WebGL中频频使用右手坐标系呢?
这个答案和你问南方人为什么吃肉粽子,和北方人为什么吃甜粽子一样,
都是因为传统
CoordinateSystem.js
WebGL的z轴指向屏幕外,也就是说:
- 越深的物体z值越小
- 越浅的物体z值越大
1 | let VSHADER_SOURCE = ` |
1 | function main() { |
1 | function initVertexBuffers(gl) { |
隐藏面消除和裁剪坐标系统
蓝色三角形数据
1
2
3 0.0, 0.6, -0.1, 0.0, 0.0, 1.0,
-0.5, -0.5, -0.1, 0.4, 0.4, 0.4,
0.5, -0.5, -0.1, 0.0, 0.0, 1.0,
绿色三角形数据
1
2
3 -0.5, 0.5, -0.5, 0.0, 1.0, 0.0,
0.5, 0.5, -0.5, 0.4, 0.4, 0.4,
0.0, -0.6,-0.5, 0.0, 1.0, 0.0
这是因为没有进行隐藏面消除
这时WebGL默认是按照绘制顺序来排列深度的
打开隐藏面消除
1 | gl.enable(gl.DEPTH_TEST) |
绘制结果会改变吗?
答: 并没有哦
这是因为 WebGL使用的是左手坐标系
z轴是指向屏幕内部的
裁剪坐标系和可视空间
开启隐藏面消除的时候会用到裁剪坐标系,
裁剪坐标系本身就是左手坐标系
先要了解为什么开启消除面隐藏后还是以左手坐标系绘图
答:正因为裁剪坐标系是左手坐标系,
所以 a_Position 的数值传递给 gl_Position 时,
会自动被纳入 左手坐标系
只有设定可视空间
隐藏面消除才能够正常工作
关键就是设定可视空间时会指定:
- 近剪裁面 near
- 远剪裁面 far
这两者决定了使用的坐标系:
- near < far
- z轴指向屏幕外
- 右手坐标系
- near > far
- z轴指向屏幕里
- 左手坐标系
给CoordinateSystem.js添加上可视空间的代码:
1 | let VSHADER_SOURCE = ` |
可视空间、投影矩阵、坐标系
这里需要考虑一下 setOrtho 对应的投影矩阵,
1 | mvpMatrix.setOrtho(-1,1,-1,1,-1,1) |
left = -1
right = 1
bottom = -1
top = 1
near = -1
far = 1
对应的投影矩阵应该是
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, -1, 0,
0, 0, 0, 1,
相当于对z轴进行翻转,
setScale(1,1,-1)
由于裁剪坐标系本身就是左手坐标系,
这一操作相当于将左手左边系翻转成右手坐标系。
总结
WebGL默认行为
规定是 左手坐标系
比如裁剪面一类的默认行为
大部分WebGL库和程序
都采用的是 右手坐标系别问,问就是传统
为了解决这个冲突
需要将使用 右手坐标系的WebGL库,
通过规定 可视空间 的方式翻转z轴,
从而能够实现一些规定使用 左手坐标系的默认行为
总结
总之这个问题告诉我们程序员奇奇怪怪的习惯如何能无中生有出一个深奥晦涩的技术问题,
还告诉我们让程序员统一开发规范有多难