Skip to content

添加水体

loading

与 sky 类似,直接把 threejs 的 water 示例搬过来即可

ts
function initWater() {
    const center = map.geo2map(new THREE.Vector3(89.4, 42.7));
    const waterGeometry = new THREE.PlaneGeometry(300 * 1000, 300 * 1000);

    const water = new Water(waterGeometry, {
        textureWidth: 512,
        textureHeight: 512,
        waterNormals: new THREE.TextureLoader().load("../images/waternormals.jpg", function (texture) {
            texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
        }),
        sunDirection: new THREE.Vector3(),
        sunColor: 0xffffff,
        waterColor: 0x001e0f,
        distortionScale: 1,
        alpha: 1,
    });
    water.material.transparent = true;
    water.material.uniforms["size"].value = 0.1;
    water.position.set(center.x, center.y + 5, 200);

    const before = water.onBeforeRender;
    const after = water.onAfterRender;
    water.onBeforeRender = (renderer, scene, camera, geometry, material, group) => {
        map.autoUpdate = false;
        before.call(water, renderer, scene, camera, geometry, material, group);
    };
    water.onAfterRender = (renderer, scene, camera, geometry, material, group) => {
        map.autoUpdate = true;
        after.call(water, renderer, scene, camera, geometry, material, group);
    };
    map.add(water);

    viewer.addEventListener("update", () => {
        water.material.uniforms["time"].value += 1.0 / 60.0;
    });

    return water;
}

TIP

threejs 的 water 在渲染前会修改 camera 位置做离屏渲染,这会触发地图的 LOD 造成地图抖动,所以需要在 water 渲染前禁止地图更新,渲染后再放开.

TIP

水面与陆地交界有些生硬,我想可以用 threejs 的 FXAA、SAO 等后期缓解,有兴趣的同学可以试试。

Released under the MIT License.