在了解Three.js和Cesium.js前先了解并弄清楚图形学关于空间的基本概念流程:
计算机图形学
图形学中涉及到多个坐标空间,这些空间之间的变换是图形渲染中的核心部分。下面是一些常见的图形学空间及其变换顺序:
-
对象空间(Object Space):
- 这是模型的原始坐标空间,模型的顶点数据是在这个空间中定义的。
- 变换:通常通过模型变换(Model Transformation)来改变模型在对象空间中的位置、旋转和缩放。
-
世界空间(World Space):
- 模型在场景中的位置,旋转和缩放都是在世界空间中定义的。
- 变换:世界变换(World Transformation)。
-
观察空间(View Space 或 Camera Space):
- 这是从相机视角看到的场景。
- 变换:视图变换(View Transformation)或摄像机变换。
-
裁剪空间(Clip Space):
- 在这里进行透视除法,得到规范化设备坐标。
- 变换:透视变换(Perspective Transformation)。
-
规范化设备坐标空间(Normalized Device Coordinates,NDC):
- 所有的顶点坐标都被映射到[-1, 1]的范围内。
- 变换:规范化。
-
屏幕空间(Screen Space):
- 最后一步变换,将NDC坐标映射到屏幕像素坐标。
- 变换:视口变换(Viewport Transformation)。
变换的顺序通常是从对象空间开始,经过模型变换,然后是世界变换,接着是视图变换,透视变换,规范化,最后是视口变换。
在图形管线中,几何数据首先被转换到世界空间(World Space),然后到相机空间(Camera Space),接着进行投影变换,得到裁剪空间的坐标。这个裁剪空间的坐标在[-w, w]范围内,其中w是顶点的齐次坐标的w分量。
裁剪空间中的坐标之后会经过视口变换(Viewport Transformation),将其映射到屏幕空间,最终渲染到屏幕上。
在裁剪空间中,可以进行裁剪操作,例如剔除不在视锥体内部的顶点,这样可以提高渲染效率。
在计算裁剪空间坐标时,通常使用齐次坐标来表示顶点位置,这样可以简化透视除法的计算。透视除法将裁剪空间中的坐标转换为规范化设备坐标(Normalized Device Coordinates,NDC),其x、y和z坐标范围在[-1, 1]之间。
案例参考GAMES101 04 games101-变换(模型、视图、投影)-CSDN博客
Three.js
Canvas画布空间(规范化设备空间)(-1,1)
Canvas画布布局和全屏
threejs渲染输出的结果就是一个Cavnas画布,canvas画布也是HTML的元素之一,这意味着three.js渲染结果的布局和普通web前端习惯是一样的。
通过renderer.domElement
属性可以访问threejs的渲染结果,也就是HTML的元素canvas
画布。
12. Canvas画布布局和全屏 | Three.js中文网
屏幕空间
坐标转化(屏幕坐标转标准设备坐标)[transformI]
// .offsetY、.offsetX以canvas画布左上角为坐标原点,单位px
const px = event.offsetX;
const py = event.offsetY;
//屏幕坐标px、py转WebGL标准设备坐标x、y
//width、height表示canvas画布宽高度
const x = (px / width) * 2 - 1;
const y = -(py / height) * 2 + 1;
纹理贴图UV坐标空间
顶点UV坐标可以在0~1.0之间任意取值,纹理贴图左下角对应的UV坐标是(0,0)
,右上角对应的坐标(1,1)
。
UV纹理空间转到Canvas画布空间(裁剪空间) [transformII]
物体坐标空间
局部坐标(x,y,z)
坐标转换流程
模型转换:(不同坐标系)
局部坐标 -> 世界坐标 -> 观察空间坐标 -> 裁剪空间坐标 -> 屏幕空间坐标
我们将 观察空间坐标系 和 裁剪空间坐标系 之间的转换统一处理,最终得到 标准设备坐标系
局部坐标 Inverse MVP ->世界坐标 -> MVP标准设备坐标 transformI->屏幕空间坐标
纹理转换:(不同坐标系)
纹理坐标 (transformII)-->裁剪空间坐标(Inverse MVP)->世界坐标
-> (MVP)标准设备坐标 ->(Inverse transformII)纹理坐标
MVP矩阵API
const viewMatrix = orthoCamera.matrixWorldInverse;//视图矩阵:世界到相机的变换矩阵。 const projectionMatrix = orthoCamera.projectionMatrix;//投影矩阵:三维到二维屏幕。 orthVpMatrix = new THREE.Matrix4(); orthVpMatrix.multiplyMatrices(projectionMatrix, viewMatrix);//为先投影,后视图orthVpMatrix.getInverse()//获取逆矩阵
Matrix4: 用于创建和操作 4x4 矩阵。
// 创建一个单位矩阵
const matrix = new THREE.Matrix4();
// 平移物体
matrix.makeTranslation(x, y, z);
// 旋转物体
matrix.makeRotationX(angle);
// 缩放物体
matrix.makeScale(scaleX, scaleY, scaleZ);
Object3D.matrix: 用于表示物体的变换矩阵。
// 创建一个立方体
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
// 设置物体的位置、旋转和缩放 cube.position.set(x, y, z);
cube.rotation.set(rx, ry, rz); cube.scale.set(sx, sy, sz);
ShaderMaterial.uniforms: 用于向着色器传递 uniform 变量,包括 MVP 矩阵。
// 创建着色器材质
const material = new THREE.ShaderMaterial
({ uniforms:
{ // 传递 MVP 矩阵给着色器
modelViewProjectionMatrix: { value: new THREE.Matrix4() }
},
vertexShader: vertexShaderCode,
fragmentShader: fragmentShaderCode });
以上是一些常用的 MVP 矩阵相关的 API 和方法,可以通过它们来创建和操作模型的视图和投影变换。
Cesium
Cesium中常用的坐标有两种:WGS84地理坐标系和笛卡尔空间坐标系。其中,WGS84地理坐标系包括:WGS84经纬度坐标系(没有实际的对象)和 WGS84弧度坐标系(Carto-graphic);笛卡尔空间坐标系包括:笛卡尔空间直角坐标系(Cartesian3)、平面坐标系(Cartesian2),4D笛卡尔坐标系(Cartesian4)。
三维
WGS-84坐标实例创建https://blog.csdn.net/qq_27814951/article/details/131645978?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171431375216800186598178%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=171431375216800186598178&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-2-131645978-null-null.142^v100^control&utm_term=cesium%E4%B8%AD%E5%9D%90%E6%A0%87%E7%B3%BB%E5%8F%8A%E5%85%B6%E8%BD%AC%E6%8D%A2&spm=1018.2226.3001.4187#1.WGS-84%E5%9D%90%E6%A0%87%E5%AE%9E%E4%BE%8B%E5%88%9B%E5%BB%BA
Cartographic
(1)通过弧度创建实例:new Cesium.Cartographic(lng, lat, height) //lng, lat为弧度,height为高度(m)
(2)通过弧度创建实例:Cesium.Cartographic.fromRadians(lng, lat, height) //lng, lat为弧度,height为高度(m)
(3)通过角度创建实例:Cesium.Cartographic.fromDegrees(lng, lat, height) //lng, lat为角度,height高度(m)
弧度与角度转换:
// 弧度转角度
- Cesium.Math.toDegrees()
//角度转弧度
- Cesium.Math.toRadians()
世界坐标系(笛卡尔)实例创建https://blog.csdn.net/qq_27814951/article/details/131645978?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171431375216800186598178%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=171431375216800186598178&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-2-131645978-null-null.142^v100^control&utm_term=cesium%E4%B8%AD%E5%9D%90%E6%A0%87%E7%B3%BB%E5%8F%8A%E5%85%B6%E8%BD%AC%E6%8D%A2&spm=1018.2226.3001.4187#2.%E4%B8%96%E7%95%8C%E5%9D%90%E6%A0%87%E7%B3%BB%E5%AE%9E%E4%BE%8B%E5%88%9B%E5%BB%BA
Cartesian3
(1)通过笛卡尔空间直角坐标系创建实例:new Cesium.Cartesian3(x, y, z)
经纬度转Cartesian3
(2)通过弧度创建实例:Cesium.Cartesian3.fromRadians(lng, lat, height) //lng, lat为弧度,height为高度(m)
(3)通过角度创建实例:Cesium.Cartesian3.fromDegrees(lng, lat, height) //lng, lat为角度,height为高度(m)
Cesium中的坐标系统及其转换-CSDN博客
(4) // 方法:借助ellipsoid对象,先转换成弧度再转换
var cartographic = Cesium.Cartographic.fromDegrees(lng, lat, height); //单位:度,度,米
var cartesian3 = ellipsoid.cartographicToCartesian(cartographic)
3.WGS-84坐标实例和世界坐标系实例相互转换https://blog.csdn.net/qq_27814951/article/details/131645978?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171431375216800186598178%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=171431375216800186598178&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-2-131645978-null-null.142^v100^control&utm_term=cesium%E4%B8%AD%E5%9D%90%E6%A0%87%E7%B3%BB%E5%8F%8A%E5%85%B6%E8%BD%AC%E6%8D%A2&spm=1018.2226.3001.4187#3.WGS-84%E5%9D%90%E6%A0%87%E5%AE%9E%E4%BE%8B%E5%92%8C%E4%B8%96%E7%95%8C%E5%9D%90%E6%A0%87%E7%B3%BB%E5%AE%9E%E4%BE%8B%E7%9B%B8%E4%BA%92%E8%BD%AC%E6%8D%A2
(1)世界坐标转WGS-84坐标:
- Cesium.Cartographic.fromCartesian(cartesian3);
(2)WGS-84坐标转世界坐标:
- Cesium.Cartographic.toCartesian(cartographic);
二维
Cartesian2->Cartesian3
- 应用:屏幕坐标转场景坐标-获取倾斜摄影或模型点击处的坐标
Cesium.SceneTransforms.wgs84ToWindowCoordinates(viewer.scene,cartesian3);
viewer.screenSpaceEventHandler.setInputAction(function (event) {
// 获取屏幕坐标;Cartesian2平面坐标格式
const windowPosition = event.position;
const ray = viewer.camera.getPickRay(windowPosition); //相交的射线
// 获取世界坐标系地表坐标,考虑地形,不包括模型,倾斜摄影模型表面;
const cartesian = viewer.scene.globe.pick(ray, viewer.scene);
// 获取倾斜摄影模型或其他三维模型点击位置的世界坐标系场景坐标
const cartesian = viewer.scene.pickPosition(windowPosition);
// 获取世界坐标系椭球面坐标,不考虑地形,模型,倾斜摄影模型表面等;
const cartesian = viewer.scene.camera.pickEllipsoid(windowPosition);
})
空间变换
Cesium为我们提供了很有用的变换工具类:Cesium.Cartesian3(相当于Point3D)Cesium.Matrix3(3x3矩阵,用于描述旋转变换)Cesium.Matrix4(4x4矩阵,用于描述旋转加平移变换),Cesium.Quaternion(四元数,用于描述围绕某个向量旋转一定角度的变换)。