我的github
posts - 3243,  comments - 42,  views - 158万

This is a guest post by Rayman Ng about his open source wind map built on top of CesiumJS.

这是Rayman Ng关于他在CesiumJS之上构建的开源风图的客座帖子。

Wind is an important element in studying the weather and climate, and it affects our daily lives in various ways. Analyzing wind is critical in many fields such as climate analysis and wind farm management. Visualizing it is crucial in being able to quickly understand the numerical wind data collected by measurement devices.

风是研究天气和气候的重要元素,它以各种方式影响着我们的日常生活。在气候分析和风电场管理等许多领域,分析风是至关重要的。将其可视化对于能够快速理解测量设备收集的数值风数据至关重要。

There are already some wind visualization applications, like Earth Nullschool and Windy, but unfortunately it seems that none of them can display the terrain, which is important for estimating the effect of wind on a specific location.

已经有一些风的可视化应用程序,如Earth Nullschool和Windy,但不幸的是,它们似乎都无法显示地形,这对于估计风对特定位置的影响很重要。

Given that I could not find an existing visualization application that met all my requirements, I decided to make my own. I found Cesium, which contains almost everything I need: 3D globe and terrain, Web Map Service layer display, and a powerful rendering engine. Basically I just needed to implement the wind visualization part.

考虑到我找不到满足我所有需求的现有可视化应用程序,我决定自己制作。我找到了Cesium,它几乎包含了我所需要的一切:3D地球仪和地形、Web地图服务层显示和强大的渲染引擎。基本上,我只需要实现风的可视化部分。

You can run the live demo in your browser or access the source code on GitHub.

您可以在浏览器中运行实时演示,也可以访问GitHub上的源代码。

How it works工作原理

A common technique to visualize wind is to use a particle system, which places lots of particles in the wind field and updates their positions regularly with the wind force. The trails of moving particles can be used to reveal the flow pattern of the wind.

可视化风的一种常见技术是使用粒子系统,该系统将大量粒子放置在风场中,并随着风力定期更新其位置。运动粒子的轨迹可以用来揭示风的流动模式。

 

At first I tried the Entity API to draw the particle trails, but the performance was not satisfying when I placed more than 10,000 particles. After some investigation, I realized that the Entity API performs computation on the CPU, and the computation for more than 10,000 particles is just too much for my CPU. For better performance, I needed to move the computation to the GPU, but I still had to render the trails, which meant working with the low level Cesium Renderer module.

起初,我尝试使用实体API绘制粒子轨迹,但当我放置超过10000个粒子时,性能并不令人满意。经过一些调查,我意识到实体API在CPU上执行计算,对于我的CPU来说,10000多个粒子的计算量太大了。为了获得更好的性能,我需要将计算转移到GPU,但我仍然必须渲染轨迹,这意味着要使用低级别的Cesium渲染器模块。

In Cesium, the key object of the rendering procedure is Cesium.DrawCommand: it is created in Cesium.Primitive, dispatched by Cesium.Scene, and executed in the render engine. The Cesium.DrawCommand contains everything needed in rendering, for example, Cesium.FramebufferCesium.Texture, and Cesium.ShaderProgram.

在Cesium中,渲染过程的关键对象是Cesium.DrawCommand:它在Cesium.Primitive中创建,由Cesium.Scene调度,并在渲染引擎中执行。Cesium.DrawCommand包含渲染所需的一切,例如Cesium.Framebuffer、Cesium.Tructure和Cesium.ShaderProgram。

To perform custom rendering, a custom DrawCommand is required. To build a DrawCommand, first initialize its components, which are ShaderProgramTextureUniforms, and Framebuffer, piece by piece, and then combine them together to create a DrawCommand object. To inject the DrawCommand into the render engine, a custom primitive object is needed. It does not need to implement all the methods of Cesium.Primitive, only the update, isDestroyed, and the destroy method are necessary. The update method will be called before the start of each rendering.

若要执行自定义渲染,需要自定义DrawCommand。要构建DrawCommand,首先逐个初始化其组件,即ShaderProgram、Texture、Uniforms和Framebuffer,然后将它们组合在一起以创建DrawCommand对象。若要将DrawCommand注入到渲染引擎中,需要一个自定义基本体对象。它不需要实现Cesium.Primitive的所有方法,只有update、isDestroyd和destroy方法是必要的。更新方法将在每次渲染开始之前调用。

As for the computation on GPU (also known as GPGPU), by using the technique of rendering to texture, it is similar to doing custom rendering; just use a fullscreen quad as vertex shader and write the calculation code in the fragment shader. Fortunately, Cesium already provides the rendering to texture function—all I needed to do was simply pass my fragment shader code to Cesium.ComputeCommand and use Cesium.ComputeEngine to perform the GPGPU.

对于GPU(也称为GPGPU)上的计算,通过使用渲染到纹理的技术,类似于进行自定义渲染;只需使用全屏四边形作为顶点着色器,并在片段着色器中编写计算代码。幸运的是,Cesium已经提供了渲染到纹理的功能,我所需要做的就是简单地将我的碎片着色器代码传递给Cesium.ComputeCommand,并使用Cesium.ComputeEngine来执行GPGPU。

The final step is to add the CustomPrimitive that contains the custom DrawCommand to the PrimitiveCollection of Scene. Below is a fully commented example of how to create a primitive and add it to the scene with a custom draw command.

最后一步是将包含自定义DrawCommand的CustomPrimitive添加到场景的PrimitiveCollection中。下面是一个完整注释的示例,说明如何创建基本体并使用自定义绘制命令将其添加到场景中。

复制代码
class CustomPrimitive {
    constructor() {

        // most of the APIs in the renderer module are private,
        // so you may want to read the source code of Cesium to figure out how to initialize the below components,
        // or you can take my wind visualization code as a example (https://github.com/RaymanNg/3D-Wind-Field)
        var vertexArray = new Cesium.VertexArray(parameters);
        var primitiveType = Cesium.PrimitiveType.TRIANGLES // you can set it to other values
        var uniformMap = {
            uniformName: function() {
                // return the value corresponding to the name in the function
                // value can be a number, Cesium Cartesian vector, or Cesium.Texture
            }
        }
        var modelMatrix = new Cesium.Matrix4(parameters);
        var shaderProgram = new Cesium.ShaderProgram(parameters);
        var framebuffer = new Cesium.Framebuffer(parameters);
        var renderState = new Cesium.RenderState(parameters);
        var pass = Cesium.Pass.OPAQUE // if you want the command to be executed in other pass, set it to corresponding value


        this.commandToExecute = new Cesium.DrawCommand({
            owner: this,
            vertexArray: vertexArray,
            primitiveType: primitiveType,
            uniformMap: uniformMap,
            modelMatrix: modelMatrix,
            shaderProgram: shaderProgram,
            framebuffer: framebuffer,
            renderState: renderState,
            pass: pass
        });
    }

    update(frameState) {
        // if (!this.show) return;
        // if you do not want to show the CustomPrimitive, use return statement to bypass the update

        frameState.commandList.push(this.commandToExecute);
    }

    isDestroyed() {
        // return true or false to indicate whether the CustomPrimitive is destroyed
    }

    destroy() {
        // this method will be called when the CustomPrimitive is no longer used
    }
}

// To begin the custom rendering, add the CustomPrimitive to the Scene
var viewer = new Cesium.Viewer('cesiumContainer');
var customPrimitive = new CustomPrimitive();
viewer.scene.primitives.add(customPrimitive);
复制代码

创建好了类以后,如何对它进行初始化呢?怎么传递参数进去呢?例如vertexArray。

Conclusion总结

Compared with the Entity API, the Primitive API with custom draw commands provides lower level functions, making it possible to achieve better performance but requiring more coding work. By making use of the powerful render engine, wind visualization is possible with satisfying performance, and I believe that there are many other ways to use this powerful yet general render engine.

与实体API相比,带有自定义绘制命令的Primitive API提供了较低级别的函数,可以实现更好的性能,但需要更多的编码工作。通过使用强大的渲染引擎,风的可视化可以获得令人满意的性能,我相信还有很多其他方法可以使用这种强大而通用的渲染引擎。

For example, it was very useful to be able to switch between different imagery layers, so you can see dynamic wind data in its global context and easily switch to comparing it with historic wind data. This is shown below using the slider.

例如,能够在不同的图像层之间切换非常有用,这样你就可以在其全球背景下看到动态风数据,并很容易地将其与历史风数据进行比较。这显示在下面使用滑块。

参考1:https://www.jianshu.com/p/bff42183ce2c

参考2:https://cesium.com/blog/2019/04/29/gpu-powered-wind/

 

posted on   XiaoNiuFeiTian  阅读(345)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
历史上的今天:
2019-06-26 apache Internal Server Error 解决方法
2019-06-26 php命令行工具
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示