紋理貼到canvas上,然後通過點擊canvas上的點找紋理對應的位置然後反算世界座標系
注意:cesium相機實時渲染紋理 默認會進行y軸翻轉
1.拿到的fbo 經過readPixels後,會有一堆Uint8Array 數據 需要給轉換成rgba;
let r = pixels[i];
let g = pixels[i + 1];
let b = pixels[i + 2];
let a = pixels[i + 3];
2.拿到這些值後需要根據canvas的寬度計算出對應的x,y值,簡稱canvas下的屏幕座標.,
let x = (i / 4) % width;
let y = Math.floor(i / (4 * width));
3.由深度圖和當前uv座標得到當前像素的NDC座標,
let ndc = new Cesium.Cartesian4(); //等價於 Cesium.Cartesian4.UNIT_W
ndc.x = (x / width) * 2.0 - 1.0;
ndc.y = (y / height) * 2.0 - 1.0;
ndc.z = 2;//寬度值
ndc.w = 1.0;
4.然後只要採用View-Projection(視圖-裁剪)的逆矩陣就可以將NDC座標變換到世界座標
注意:矩陣乘積的逆等於矩陣的逆的相反順序的乘積
模型視圖投影矩陣=投影矩陣×視圖矩陣×模型矩陣
視圖投影矩陣的逆矩陣 = 視圖矩陣的逆矩陣 * 投影矩陣的逆矩陣
let inverseViewProjection = Cesium.Matrix4.multiply(
this.customCamera.inverseViewMatrix,//應該是生成紋理的當時的矩陣,不是scene 下的矩陣
uniformState.inverseProjection,
new Cesium.Matrix4()
);
let worldCoords = Cesium.Matrix4.multiplyByVector(
inverseViewProjection,
ndc,
new Cesium.Cartesian4()
);
let w = 1.0 / worldCoords.w; //投影座標的轉ndc 需要除以w 分量
Cesium.Cartesian3.multiplyByScalar(worldCoords, w, worldCoords);
worldPositions.push(worldCoords);
到此爲止世界座標計算出來了,開始下一步.從canvas上拾取點然後換世界座標
5.canvas 的座標系和webgl的座標系 不同,還有由於我的canvas 並不是全屏的
let rect = canvas.getBoundingClientRect();
let x = event.clientX - rect.left * (canvas.width / rect.width);
let y = event.clientY - rect.top * (canvas.height / rect.height);
這樣把x,y 值傳入計算世界座標的時候就能換算出點擊canvas對應的世界座標.其中座標的轉換包括canvas到webgl的座標轉換,屏幕座標到ndc座標轉換,ndc 到世界座標的轉換.