Cesium进阶学习七、Globe材质

一、简介
在Cesium的三维场景中,scene.globe.material 属性用于设置全球(地形)的外观材质样式
在这里插入图片描述

目前没有提供类似new Cesium.ColorMaterialProperty这种直接实例化的类。Cesium内置的用于Globe的材质类主要有以下几个:
ElevationContour 等高线
ElevationRamp 高程
SlopeRamp 坡向
AspectRamp 坡度
ElevationBand 多级高程

要创建Globe材质可以通过以下两种方式:

1、new Cesium.Material()的方式

let material = new Cesium.Material({
   
 fabric: {
   
     type: "ElevationContour",
     uniforms: {
   
         width: 1,
         spacing: 20,
         color: Cesium.Color.YELLOW,
     },
 }
});
this.viewer.scene.globe.material = material;

2、Cesium.Material.fromType(type)

let material = new Cesium.Material.fromType("ElevationContour");
material.uniforms.color=Cesium.Color.RED;
material.uniforms.width=1;
material.uniforms.spacing=20;
viewer.scene.globe.material = material;

这些材质默认将应用于整个地球的范围,在实际的项目中,我们往往只关心项目的研究区域,所以需要对其显示的范围进行限定。限制Globe材质的作用范围,有以下两个思路:

1.将范围传入Globe顶点着色器,在顶点着色器中判断当前顶点是否在范围内,然后在片元着色器中进行处理。
2.覆写Material的source,将范围传入到source中,判断当前片元是否在范围内,然后进行处理。

第一种方式需要修改Cesium的相关源码,不便于更新维护,进阶学习我们介绍第二种方式。

二、应用场景

1、局部等高线
我们在基础篇中介绍过如何覆写Cesium内置Material的source的方法,如果忘了也没关系,您可以先去回顾一下,也可以直接往下看。我们打印一下内置等高线材质的source:

打印语句console.log(Cesium.Material._materialCache._materials.ElevationContour.fabric.source)
uniform vec4 color;
uniform float spacing;
uniform float width;

czm_material czm_getMaterial(czm_materialInput materialInput)
{
   
    czm_material material = czm_getDefaultMaterial(materialInput);

    float distanceToContour = mod(materialInput.height, spacing);

#if (__VERSION__ == 300 || defined(GL_OES_standard_derivatives))
    float dxc = abs(dFdx(materialInput.height));
    float dyc = abs(dFdy(materialInput.height));
    float dF = max(dxc, dyc) * czm_pixelRatio * width;
    float alpha = (distanceToContour < dF) ? 1.0 : 0.0;
#else
    // If no derivatives available (IE 10?), use pixel ratio
    float alpha = (distanceToContour < (czm_pixelRatio * width)) ? 1.0 : 0.0;
#endif

    vec4 outColor = czm_gammaCorrect(vec4(color.rgb, alpha * color.a));
    material.diffuse = outColor.rgb;
    material.alpha = outColor.a;

    return material;
}

可以看到等高线材质的核心是根据materialInput.height参数进行着色计算,这是一个输入参数,代表的就是的当前的高程值。如何验证materialInput.height为高程值?我们可以将着色器修改为下面这样:

Cesium.Material._materialCache._materials.ElevationContour.fabric.source = `
 uniform vec4 color;
 uniform float spacing;
 uniform float width;
 czm_material czm_getMaterial(czm_materialInput materialInput)
 {
     czm_material material = czm_getDefaultMaterial(materialInput);
     if(materialInput.height>250.){
         material.diffuse=vec3(1.,0.,0.);
     }
      return material;
 }
 `

 let material = new Cesium.Material({
   
     fabric: {
   
         type: "ElevationContour",
         uniforms: {
   
             width: 1,
             spacing: 20,
             color: Cesium.Color.YELLOW, 
         },
     }
 });
 viewer.scene.globe.material = material;

着色器代码中,我们将高程值大于250的片元设置为红色。(您可以显示一个高度为250的点进行测试)
在这里插入图片描述

虽然验证了此处的materialInput.height就是当前片元的高程值,但是此处我们这里暂时用不到该值,我们需要的是将范围数据传递到着色器中来。如何将范围数据传递到着色器中,并判断当前片元是否在范围内,在后处理章节其实已经讲解过了。我们参考后处理章节,将范围数据传递到着色器中。(后处理-限制后处理的作用范围)假设有以下范围数据:

let positions=[
    114.48165315948947, 26.88537765441287,
    114.49059645844312, 26.886623091932666,
    114.49046426464001, 26.894158820558456,
    114.48015054916547, 26.89228862770083,
];

(注意不能直接传递矩阵到Material的着色器,解决方法是将矩阵进行拆分)将其传入到着色器的完整代码如下:

Cesium.Material._materialCache._materials.ElevationContour.fabric.source = `
uniform vec4 color;
uniform float spacing;
uniform float width;  
uniform vec4 rect;  
uniform vec4 m_0;  
uniform vec4 m_1;  
uniform vec4 m_2;  
uniform vec4 m_3;  
czm_material czm_getMaterial(czm_materialInput materialInput)
{
    czm_material material = czm_getDefaultMaterial(materialInput);
    mat4 m=mat4(m_0[0],m_0[1],m_0[2],m_0[3],m_1[0],m_1[1],m_1[2],m_1[3],m_2[0],m_2[1],m_2[2],m_2[3],m_3[0],m_3[1],m_3[2],m_3[3]); 
    return material;
}
`
let material =  new Cesium.Material({
   
    fabric: {
   
        type: "ElevationContour",
        uniforms: {
   
            width: 1,
            spacing: 20,
            color: Cesium.Color.YELLOW, 
            rect: rect,
            m_0: new Cesium.Cartesian4(inverse[0], inverse[1], inverse[2], inverse[3]),
            m_1: new Cesium.Cartesian4(inverse[4], inverse[5], inverse[6], inverse[7]),
            m_2: new Cesium.Cartesian4(inverse[8], inverse[9], inverse[10], inverse[11]),
            m_3: new Cesium.Cartesian4(inverse[12] , inverse[13] , inverse[14] , inverse[15])
        },
    }
});

因为矩阵是4*4的一个数组,此处我们将其拆分为4个vec4类型的值。这样我们就将范围和矩阵传入到了着色器中,接下来我们要判断当前片元是否在范围内。在后处理章节中,我们通过深度还原了片元的世界坐标,然后将世界坐标转到局部坐标系,最后判断点是否在范围内。在Material的source中我们没有深度信息,又如何还原片元的世界坐标呢?我们在输入参数materialInput中可以获取到当前片元的在相机坐标系的坐标materialInput.positionToEyeEC(视空间坐标),获取到视空间坐标后通过 czm_inverseView矩阵还原为世界坐标,然后就可以像后处理章节里面那么进行判断了。

完整代码如下:

	let positions = [
    114.48165315948947, 26.88537765441287,
    114.49059645844312, 26.886623091932666,
    114.49046426464001, 26.894158820558456,
    114.48015054916547, 26.89228862770083,
];
positions = Cesium.Cartesian3.fromDegreesArray([].concat.apply([], positions));

//建立局部坐标系 将所有点转到该坐标系下

let m = Cesium.Transforms.eastNorthUpToFixedFrame(positions[0]);
let inverse = Cesium.Matrix4.inverse(m, new Cesium.Matrix4());
let localPositions = [];
positions.forEach
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cesium进阶学习

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值