前端-风场可视化研究3

项目 https://github.com/RaymanNg/3D-Wind-Field 是把风场融合到了 cesiumJs 的三维球形地图中。
b50c42e1400ec88d4f99104e6acf1385

着色器的调用流程是 calculateSpeed.frag => updatePosition.frag => postProcessingPosition.frag => segmentDraw.vert => segmentDraw.frag => fullscreen.vert => trailDraw.frag => fullscreen.vert => screenDraw.frag

calculateSpeed.frag => updatePosition.frag => postProcessingPosition.frag 这三个着色器的调用在 particlesComputing.js 中,其余的在 particlesRendering.js 中调用

calculateSpeed.frag 中的 currentParticlesPosition 的分辨率为 64 x 64, 每帧都会更新。U纹理 和 V纹理 是风场数据不会每帧都改变,这两个纹理的分辨率是 720 x 361 x 1

        var particlesArray = DataProcess.randomizeParticles(userInput.maxParticles, viewerParameters)
        var zeroArray = new Float32Array(4 * userInput.maxParticles).fill(0);

        this.particlesTextures = {
            previousParticlesPosition: Util.createTexture(particlesTextureOptions, particlesArray),
            currentParticlesPosition: Util.createTexture(particlesTextureOptions, particlesArray),
            nextParticlesPosition: Util.createTexture(particlesTextureOptions, particlesArray),
            postProcessingPosition: Util.createTexture(particlesTextureOptions, particlesArray),

            particlesSpeed: Util.createTexture(particlesTextureOptions, zeroArray)
        };

这里对五张纹理previousParticlesPosition currentParticlesPosition nextParticlesPosition postProcessingPosition particlesSpeed都进行了初始化
五张纹理的分辨率为64 x 64 由风粒子的总数决定这个分辨率

这个着色器中

void main() {
    speedScaleFactor = speedFactor * pixelSize;

    // texture coordinate must be normalized
    vec3 lonLatLev = texture(currentParticlesPosition, v_textureCoordinates).rgb;
    vec3 speed = calculateSpeedByRungeKutta2(lonLatLev);
    vec3 speedInLonLat = convertSpeedUnitToLonLat(lonLatLev, speed);

    vec4 particleSpeed = vec4(speedInLonLat, calculateWindNorm(speed / speedScaleFactor));
    outputColor = particleSpeed;
}

pixelSize来自 cesium camera

        var pixelSize = this.camera.getPixelSize(
            this.globeBoundingSphere,
            this.scene.drawingBufferWidth,
            this.scene.drawingBufferHeight
        );

        if (pixelSize > 0) {
            this.viewerParameters.pixelSize = pixelSize;
        }

我无法理解为什么这里必须是 calculateSpeedByRungeKutta2,RK2数值积分方法,计算下一时刻的风速,通义千问的解释是,这样做得到速度更加精确和稳定。
我尝试过将 calculateSpeedByRungeKutta2 修改为

vec3 calculateSpeedByRungeKutta2(vec3 lonLatLev) {
    // see https://en.wikipedia.org/wiki/Runge%E2%80%93Kutta_methods#Second-order_methods_with_two_stages for detail
    const float h = 0.5;

    vec3 y_n = lonLatLev;
    vec3 f_n = linearInterpolation(lonLatLev);
    return convertSpeedUnitToLonLat(y_n, f_n) * speedScaleFactor;
}

修改后,风粒子无法流动起来,没有线条轨迹了。二维风场图 https://github.com/mapbox/webgl-wind 都没有使用 RK2 数值积分方法,为什么这里必须使用?

segmentDraw.vert 顶点着色器中使用了 previousParticlesPosition currentParticlesPosition postProcessingPosition 三张纹理来绘制三角形带,组成可以设置宽度的线条

posted @ 2025-07-21 16:35  randomGood1984  阅读(18)  评论(0)    收藏  举报