cesium 局部区域的等高线如何实现

cesium 局部区域的等高线如何实现?基于cesium 自带的ElevationContour材质实现,目前想到的解决办法为修改着色器限制material的作用区域,但是不会具体实施方法,有没有人能提供相似参考博文

要实现 Cesium 中局部区域的等高线,可以使用 Cesium 自带的 ElevationContour 材质,并结合修改着色器的方法来限制其作用区域。下面是一个简单的实现思路和代码示例。

1、实现思路
Cesium 中的 ElevationContour 材质可以用于绘制等高线,它的作用是根据高度值将地形网格进行分层,并使用不同的颜色来表示不同的高度层。为了实现局部区域的等高线,我们可以通过修改着色器的方式来限制 ElevationContour 材质的作用范围,只对局部区域进行渲染。

具体来说,我们可以在 ElevationContour 材质的着色器中添加一个额外的输入变量,用于传入局部区域的坐标范围。然后在着色器中判断当前像素是否在局部区域内,如果在,则进行等高线绘制,否则不进行绘制。

2、代码示例
下面是一个简单的代码示例,用于实现 Cesium 中局部区域的等高线。这里假设已经有一个高程数据集,并且已经使用 Cesium.CesiumTerrainProvider 将其加载到了场景中。代码中使用了 ElevationContour 材质和修改后的着色器来实现局部区域的等高线。

// 定义局部区域的范围
var rect = new Cesium.Rectangle.fromDegrees(west, south, east, north);

// 创建等高线材质
var contourMaterial = new Cesium.ElevationContourMaterialProperty({
    color: Cesium.Color.RED,
    lineThickness: 4,
    spacing: 50,
    // 自定义着色器
    shaderSource: {
        vertexShader: `
            attribute vec3 position3DHigh;
            attribute vec3 position3DLow;
            attribute vec4 color;
            attribute vec3 normal;

            uniform mat4 modelViewProjection;

            varying vec4 v_color;

            void main() {
                vec4 position = czm_computePosition();
                v_color = color;
                gl_Position = modelViewProjection * position;
            }
        `,
        fragmentShader: `
            varying vec4 v_color;

            // 添加额外的输入变量,用于传入局部区域的坐标范围
            uniform vec4 u_rect;

            void main() {
                // 判断当前像素是否在局部区域内
                vec2 st = gl_FragCoord.xy / czm_viewport.zw;
                vec2 coord = mix(czm_viewportOrthographic.xy, czm_viewportOrthographic.zw, st);
                vec3 position = czm_inverseModelViewProjection * vec4(coord, 1.0);
                if (position.x >= u_rect.x && position.x <= u_rect.y &&
                    position.y >= u_rect.z && position.y <= u_rect.w) {
                    gl_FragColor = v_color;
                } else {
                    discard;
                }
            }
        `
    }
});

// 创建等高线 Primitive
var contourPrimitive = new Cesium.Primitive({
    geometryInstances: new Cesium.GeometryInstance({
        geometry: new Cesium.RectangleGeometry({
            rectangle: Cesium.Rectangle.MAX_VALUE,
            ellipsoid: Cesium.Ellipsoid.WGS84,
            height: 0
        }),
        attributes: {
            color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.RED)
        }
    }),
    appearance: new Cesium.ElevationContourAppearance({
        material: contourMaterial
    })
});

// 在场景中添加等高线 Primitive
viewer.scene.primitives.add(contourPrimitive);

//以上代码示例中,通过创建 `ElevationContourMaterialProperty`

该回答引用ChatGPT4与博主@晓码自在合作编写:

问题的解答:

  1. FrameWork基类的继承实现主要用于代码重用和减少重复工作。可以定义公共的抽象基类,派生类继承并实现相关方法。
  2. HIS系统的典型分层包括:表示层、业务逻辑层、数据访问层、数据层。对应代码文件夹可以命名为:UI、BLL、DAL、Model。
  3. HIS系统存储控制参数的方法有:配置文件、数据库、缓存。
  4. HISTimeJob是一个定时任务服务,用于在HIS系统中执行定时调度任务。可以在TimeJob类中增加定时方法,并在程序启动时向计划调度服务注册该TimeJob,指定定时规则,就可以定时执行该方法。
  5. ReadMarkNo动态库主要实现条形码识别和解析,提供识别出的条形码结果。

关于cesium的等高线实现,你可以:

  1. 继承Cesium自带的ElevationContourMaterial,重写其fragment着色器,在里面增加if判断,只在指定区域内绘制等高线。
  2. 不继承ElevationContourMaterial,自己编写等高线材质。在fragment着色器中根据纹理坐标等判断是否在指定区域,如果是则绘制等高线,否则丢弃片段。
  3. 将需要显示等高线的区域用PolygonGeometry等封装成一个区域图形,然后只在这个区域图形上应用ElevationContourMaterial材质,从而达到限制其作用区域的目的。

具体的GLSL代码实现可以参考:

glsl
// 自定义的等高线材质fragment着色器
void main() {
  // 获取片段在区域图形中的位置
  vec2 position = GetScreenSpacePosition();  
  
  // 判断位置是否在我们指定的区域内
  bool inArea = // ...  
  
  if (inArea) {
    // 在区域内,正常绘制等高线
    DrawElevationContour(); 
  } else {
    // 不在区域内,丢弃片段
    discard;
  }
}