【cesium】可视域分析

本文详细介绍了使用Cesium库创建光照相机、阴影贴图、视网椎体以及后期处理阶段来实现地形阴影效果的过程。在创建过程中,通过调整相机位置、方向和视锥参数来控制阴影的呈现。同时,注意到当相机视角变化时,由于LOD(Level of Detail)导致地形可视域显示出现问题,而建筑物不受影响。解决方案在于优化获取点的监听方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

视域分析// 创建相机
createLightCamera () {
this.lightCamera = new Cesium.Camera(this.viewer.scene);
this.lightCamera.position = this.viewPosition;
// if (this.viewPositionEnd) {
// let direction = Cesium.Cartesian3.normalize(Cesium.Cartesian3.subtract(this.viewPositionEnd, this.viewPosition, new Cesium.Cartesian3()), new Cesium.Cartesian3());
// this.lightCamera.direction = direction; // direction是相机面向的方向
// }
this.lightCamera.frustum.near = this.viewDistance * 0.00001;
this.lightCamera.frustum.far = this.viewDistance;
const hr = Cesium.Math.toRadians(this.horizontalViewAngle);
const vr = Cesium.Math.toRadians(this.verticalViewAngle);
// 视锥的宽度与高度的纵横比
const aspectRatio =
(this.viewDistance * Math.tan(hr / 2) * 2) /
(this.viewDistance * Math.tan(vr / 2) * 2);
this.lightCamera.frustum.aspectRatio = aspectRatio;
if (hr > vr) {
this.lightCamera.frustum.fov = hr;
} else {
this.lightCamera.frustum.fov = vr;
}
this.lightCamera.setView({
destination: this.viewPosition,
orientation: {
heading: Cesium.Math.toRadians(this.viewHeading || 0),
pitch: Cesium.Math.toRadians(this.viewPitch || 0),
roll: 0
}
});
}
// 创建阴影贴图
createShadowMap () {
this.shadowMap = new Cesium.ShadowMap({
context: (this.viewer.scene).context,
lightCamera: this.lightCamera,
enabled: this.enabled,
isPointLight: true,
pointLightRadius: this.viewDistance,
cascadesEnabled: false,
size: this.size,
softShadows: true,
normalOffset: false,
fromLightSource: false
});
this.viewer.scene.shadowMap = this.shadowMap
this.viewer.scene.globe.shadows = Cesium.ShadowMode.ENABLED
this.viewer.scene.globe.depthTestAgainstTerrain = true
}
// 创建视网椎体
drawWedge () {
this.Wedge = this.viewer.entities.add({
name: “Wedge”,
position: this.viewPosition,
orientation: new Cesium.CallbackProperty(() => {
return Cesium.Transforms.headingPitchRollQuaternion(
this.viewPosition,
Cesium.HeadingPitchRoll.fromDegrees(this.viewHeading - this.horizontalViewAngle, this.viewPitch, 0.5)
)
}, false),
ellipsoid: {
radii: new Cesium.CallbackProperty(() => {
return new Cesium.Cartesian3(this.viewDistance,
this.viewDistance,
this.viewDistance)
}, false),
// new Cesium.Cartesian3(this.viewDistance,
// this.viewDistance,
// this.viewDistance),
innerRadii: new Cesium.Cartesian3(1.0, 1.0, 1.0),
minimumClock: Cesium.Math.toRadians(-this.horizontalViewAngle / 2),
maximumClock: Cesium.Math.toRadians(this.horizontalViewAngle / 2),
minimumCone: Cesium.Math.toRadians(this.verticalViewAngle + 7.75),
maximumCone: Cesium.Math.toRadians(180 - this.verticalViewAngle - 7.75),
material: Cesium.Color.DARKCYAN.withAlpha(0.3),
outline: true,
outlineColor: Cesium.Color.YELLOWGREEN
},
});
this.sketch = this.viewer.entities.add({
name: “sketch”,
position: this.viewPosition,
orientation: new Cesium.CallbackProperty(() => {
return Cesium.Transforms.headingPitchRollQuaternion(
this.viewPosition,
Cesium.HeadingPitchRoll.fromDegrees(this.viewHeading - this.horizontalViewAngle, this.viewPitch, 0.0)
)
}, false),
ellipsoid: {
radii: new Cesium.CallbackProperty(() => {
return new Cesium.Cartesian3(this.viewDistance,
this.viewDistance,
this.viewDistance)
}, false),
minimumClock: Cesium.Math.toRadians(-this.horizontalViewAngle / 2),
maximumClock: Cesium.Math.toRadians(this.horizontalViewAngle / 2),
minimumCone: Cesium.Math.toRadians(this.verticalViewAngle + 7.75),
maximumCone: Cesium.Math.toRadians(180 - this.verticalViewAngle - 7.75),
material: Cesium.Color.DARKCYAN.withAlpha(0.3),
outline: true,
subdivisions: 256,
stackPartitions: 64,
slicePartitions: 64,
outlineColor: Cesium.Color.YELLOWGREEN
},
});
/* this.sketch = this.viewer.entities.add({
name: ‘sketch’,
position: this.viewPosition,
orientation: Cesium.Transforms.headingPitchRollQuaternion(
this.viewPosition,
Cesium.HeadingPitchRoll.fromDegrees(this.viewHeading - this.horizontalViewAngle, this.viewPitch, 0.0)
),
ellipsoid: {
radii: new Cesium.Cartesian3(
this.viewDistance,
this.viewDistance,
this.viewDistance
),
// innerRadii: new Cesium.Cartesian3(2.0, 2.0, 2.0),
minimumClock: Cesium.Math.toRadians(-this.horizontalViewAngle / 2),
maximumClock: Cesium.Math.toRadians(this.horizontalViewAngle / 2),
minimumCone: Cesium.Math.toRadians(this.verticalViewAngle + 7.75),
maximumCone: Cesium.Math.toRadians(180 - this.verticalViewAngle - 7.75),
fill: false,
outline: true,
subdivisions: 256,
stackPartitions: 64,
slicePartitions: 64,
outlineColor: Cesium.Color.YELLOWGREEN
}
}); */
}
// 创建PostStage
createPostStage () {
const glsl = `
#define USE_CUBE_MAP_SHADOW true
uniform sampler2D colorTexture;
// 深度纹理
uniform sampler2D depthTexture;
// 纹理坐标
varying vec2 v_textureCoordinates;

    uniform mat4 camera_projection_matrix;

    uniform mat4 camera_view_matrix;
    // 观测距离
    uniform float far;
    //阴影
    uniform samplerCube shadowMap_textureCube;

    uniform mat4 shadowMap_matrix;
    uniform vec4 shadowMap_lightPositionEC;
    uniform vec4 shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness;
    uniform vec4 shadowMap_texelSizeDepthBiasAndNormalShadingSmooth;

    struct zx_shadowParameters
    {
        vec3 texCoords;
        float depthBias;
        float depth;
        float nDotL;
        vec2 texelStepSize;
        float normalShadingSmooth;
        float darkness;
    };

    float czm_shadowVisibility(samplerCube shadowMap, zx_shadowParameters shadowParameters)
    {
        float depthBias = shadowParameters.depthBias;
        float depth = shadowParameters.depth;
        float nDotL = shadowParameters.nDotL;
        float normalShadingSmooth = shadowParameters.normalShadingSmooth;
        float darkness = shadowParameters.darkness;
        vec3 uvw = shadowParameters.texCoords;

        depth -= depthBias;
        float visibility = czm_shadowDepthCompare(shadowMap, uvw, depth);
        return czm_private_shadowVisibility(visibility, nDotL, normalShadingSmooth, darkness);
    }

    vec4 getPositionEC(){
      return czm_windowToEyeCoordinates(gl_FragCoord);
    }

    vec3 getNormalEC(){
      return vec3(1.);
    }

    vec4 toEye(in vec2 uv,in float depth){
      vec2 xy=vec2((uv.x*2.-1.),(uv.y*2.-1.));
      vec4 posInCamera=czm_inverseProjection*vec4(xy,depth,1.);
      posInCamera=posInCamera/posInCamera.w;
      return posInCamera;
    }

    vec3 pointProjectOnPlane(in vec3 planeNormal,in vec3 planeOrigin,in vec3 point){
      vec3 v01=point-planeOrigin;
      float d=dot(planeNormal,v01);
      return(point-planeNormal*d);
    }

    float getDepth(in vec4 depth){
      float z_window=czm_unpackDepth(depth);
      z_window=czm_reverseLogDepth(z_window);
      float n_range=czm_depthRange.near;
      float f_range=czm_depthRange.far;
      return(2.*z_window-n_range-f_range)/(f_range-n_range);
    }

    float shadow( in vec4 positionEC ){
      vec3 normalEC=getNormalEC();
      zx_shadowParameters shadowParameters;
      shadowParameters.texelStepSize=shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.xy;
      shadowParameters.depthBias=shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.z;
      shadowParameters.normalShadingSmooth=shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.w;
      shadowParameters.darkness=shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness.w;
      vec3 directionEC=positionEC.xyz-shadowMap_lightPositionEC.xyz;
      float distance=length(directionEC);
      directionEC=normalize(directionEC);
      float radius=shadowMap_lightPositionEC.w;
      if(distance>radius)
      {
        return 2.0;
      }
      vec3 directionWC=czm_inverseViewRotation*directionEC;

      shadowParameters.depth=distance/radius-0.0003;
      shadowParameters.nDotL=clamp(dot(normalEC,-directionEC),0.,1.);

      shadowParameters.texCoords=directionWC;
      float visibility=czm_shadowVisibility(shadowMap_textureCube,shadowParameters);
      return visibility;
    }

    bool visible(in vec4 result)
    {
      result.x/=result.w;
      result.y/=result.w;
      result.z/=result.w;
      return result.x>=-1.&&result.x<=1.&&result.y>=-1.&&result.y<=1.&&result.z>=-1.&&result.z<=1.;
    }

    void main(){
      // 得到釉色 = 结构二维(彩色纹理,纹理坐标)
      gl_FragColor=texture2D(colorTexture,v_textureCoordinates);
      // 深度 = (釉色 = 结构二维(深度纹理,纹理坐标))
      float depth=getDepth(texture2D(depthTexture,v_textureCoordinates));
      // 视角 = (纹理坐标,深度)
      vec4 viewPos=toEye(v_textureCoordinates,depth);
      //世界坐标
      vec4 wordPos=czm_inverseView*viewPos;
      // 虚拟相机中坐标
      vec4 vcPos=camera_view_matrix*wordPos;
      float near=.001*far;
      float dis=length(vcPos.xyz);
      if(dis>near&&dis<far){
        //透视投影
        vec4 posInEye=camera_projection_matrix*vcPos;
        // 可视区颜色
        vec4 v_color=vec4(0.,1.,0.,.5);
        vec4 inv_color=vec4(1.,0.,0.,.5);
        if(visible(posInEye)){
          float vis=shadow(viewPos);
          if(vis>0.3){
            gl_FragColor=mix(gl_FragColor,v_color,.5);
          } else {
            gl_FragColor=mix(gl_FragColor,inv_color,.5);
          }
        }
      }
    }`;
    const fs = glsl
    const postStage = new Cesium.PostProcessStage({
        fragmentShader: fs,
        uniforms: {
            camera_projection_matrix: this.lightCamera.frustum.projectionMatrix,
            camera_view_matrix: this.lightCamera.viewMatrix,
            shadowMap: this.shadowMap,
            far: () => {
                return this.viewDistance;
            },
            shadowMap_textureCube: () => {
                this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState"));
                return Reflect.get(this.shadowMap, "_shadowMapTexture");
            },
            shadowMap_matrix: () => {
                this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState"));
                return Reflect.get(this.shadowMap, "_shadowMapMatrix");
            },
            shadowMap_lightPositionEC: () => {
                this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState"));
                return Reflect.get(this.shadowMap, "_lightPositionEC");
            },
            shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness: () => {
                this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState"));
                const bias = this.shadowMap._pointBias;
                return Cesium.Cartesian4.fromElements(
                    bias.normalOffsetScale,
                    this.shadowMap._distance,
                    this.shadowMap.maximumDistance,
                    0.0,
                    new Cesium.Cartesian4()
                );
            },
            shadowMap_texelSizeDepthBiasAndNormalShadingSmooth: () => {
                this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState"));
                const bias = this.shadowMap._pointBias;
                const scratchTexelStepSize = new Cesium.Cartesian2();
                const texelStepSize = scratchTexelStepSize;
                texelStepSize.x = 1.0 / this.shadowMap._textureSize.x;
                texelStepSize.y = 1.0 / this.shadowMap._textureSize.y;

                return Cesium.Cartesian4.fromElements(
                    texelStepSize.x,
                    texelStepSize.y,
                    bias.depthBias,
                    bias.normalShadingSmooth,
                    new Cesium.Cartesian4()
                );
            }
        }
    });
    this.postStage = this.viewer.scene.postProcessStages.add(postStage);
}

当前存在问题,相机视角变化时,地形可视域显示会变化,是因为lod记载的问题,建筑物则不会出现该情况,但需要在修改获取点的监听方式。
在这里插入图片描述

评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

gis分享

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

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

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

打赏作者

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

抵扣说明:

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

余额充值