一、简介
反射水面的原理是根据当前相机计算出反射相机,利用反射相机进行离屏渲染,将渲染的结果作为纹理贴合到水面几何,并加入一些噪声使其更加逼真。
离屏渲染相关的知识已在“离屏渲染”章节介绍过,这里主要的难点是计算反射相机,计算反射相机的方法也很多,这里介绍一个利用反射向量计算的方法。反射向量计算方法的原理: 计算从当前相机位置指向水面中心 O 的向量 V 和距离 D,根据向量 V 和水面法线 N 计算反射向量 R。此时反射相机的位置为:O - D * R,视线方向和上方向可以同理可得。
二、计算反射相机
1、假定水面点位数组如下:
let positions = [
[-75.59674, 40.03768, 80],
[-75.59691, 40.03795, 80],
[-75.59697, 40.03802, 80],
[-75.5972, 40.03794, 80],
[-75.5974, 40.03796, 80],
[-75.59767, 40.03789, 80],
[-75.5979, 40.03779, 80],
[-75.59805, 40.03769, 80],
[-75.59806, 40.03758, 80],
[-75.598, 40.03734, 80],
[-75.59789, 40.0372, 80],
[-75.59772, 40.03717, 80],
[-75.59745, 40.03728, 80],
[-75.59716, 40.0374, 80],
[-75.59693, 40.0375, 80],
[-75.59677, 40.03756, 80],
[-75.59662, 40.03761, 80]
];
positions = Cesium.Cartesian3.fromDegreesArrayHeights([].concat.apply([], positions));//经纬度转为笛卡尔
2、将其添加到场景中
viewer.entities.add({
polygon: {
hierarchy: new Cesium.PolygonHierarchy(positions),
perPositionHeight: true,
material: Cesium.Color.WITHE
}
})
3、 求取水面法线:水面法线即为平面的法线,可以用平面中心的法线代替
let n = positions.length;
let a = new Cesium.Cartesian3();
positions.forEach(p => {
a = Cesium.Cartesian3.add(a, p, a);
})
a = Cesium.Cartesian3.multiplyByScalar(a, 1 / n, a);//中心点
//获取中心点的法线
let normal= Cesium.Ellipsoid.WGS84.geodeticSurfaceNormal(a);
console.log(normal);
4、计算反射相机的位置
a、首先获取场景相机到水面中心点的向量
//场景相机到水面中心点的向量
let V=Cesium.Cartesian3.sub(centerPosition,viewer.camera.positionWC,new Cesium.Cartesian3());
b、然后根据水面法线计算反射后的向量
//计算向量V通过法线反射后的向量R
n = Cesium.Cartesian3.dot(normal, V);
let t = Cesium.Cartesian3.multiplyByScalar(normal, 2 * n, new Cesium.Cartesian3());
let R = Cesium.Cartesian3.subtract(V, t, new Cesium.Cartesian3());
根据法线计算反射向量的公式为:
float3 reflect( float3 i, float3 n ){
return i - 2.0 n dot(n,i);
}
c、然后对反射向量进行取反即可得到反射相机的向量
//对R进行取反即为反射相机的向量
R = Cesium.Cartesian3.negate(R, R);
d、然后计算反射相机的位置
//此时反射相机的坐标为
let reflectCameraPosition = Cesium.Cartesian3.add(centerPosition, R, new Cesium.Cartesian3());
5、计算反射相机的方向:反射相机的方向即为最开始的R向量的归一化向量
//计算反射相机的方向
let reflectCameraDirection = Cesium.Cartesian3.