用cesium的后期处理实现类似three.js中的spotLight效果

一、背景

当我们用cesium来做一些灯光效果的时候,比如扫光效果啥的,会发现cesium没有像three.js或者babylon.js那样自定义灯光,cesium只有直射光也就是太阳光,如果要是实现类似three.js的灯光效果怎么办呢?

一般是有三种效果:

一、片元着色器直接着色,这个无论在那个引擎都是一样的,再细分一下有两种,一种是通过uv坐标来计算光照;另一种加入三维坐标,例如要做一个扫光的效果,扫光的中心需要自己定义,也就是将笛卡尔坐标从cpu传到GPU,这不展开说,先挖个坑;但是这个有一个缺点,因为这个是当前对象表面着色的,没办法影响到别的对象;试想,当灯光打下来了,为什么只有你被照亮了,旁边的咋办,这个灯光太偏心了;那没办啊,只能给旁边的对象也用同样的方式着色了

二、通过后期处理,在这里其实和上面说的通过uv着色有点点像,但是也有差别,它是在原来对象的表面颜色加上灯光的颜色,当然也可以直接纯颜色代替对象面的颜色,但是这个就不是灯光了,在cesium因为不需要灯光也能看到对象,所以就是会让被灯光找到的物体更加亮了,怎么样算是被找到呢,这就是我们要计算的了,带会让在代码里说明

三、通过模板、这个了解不多,不是很懂也没用过,不过据说可以,在three.js中

本次是采用的时候后期处理来实现,但是坐标也是从外面传进去的也是第一点说的有点像,至于里面的坐标转换部分,也就是将坐标传进去GPU之前做的转换我是参考,忘了那个大佬的,虽然我想尊重原创,但是我已经不知道哪个是原创的了,哈哈哈,感觉网上很多都一样,所以那些坐标转换部分我就不改了,尊重原创,重要事着色器部分哈

import * as Cesium from 'cesium'
// 圆扩散
class CircleDiffusion {
    viewer: any
    lastStageList: Array<any>
    constructor(viewer: any) {
      this.viewer = viewer
      this.lastStageList = []
    }
    add(
      position: Array<number>,
      radio = 300
    ) {
      this.lastStageList.push(
        this.showCircleScan(position, radio)
      )
    }
    clear() {
      this.lastStageList.forEach((ele: any) => {
        this.clearScanEffects(ele)
      })
      this.lastStageList = []
    }
    /**
     * 圆扩散
     * @param {*} position  扫描中心 如[117.270739,31.84309,32]
     * @param {*} scanColor 扫描颜色 如"rgba(0,255,0,1)"
     * @param {*} maxRadius 扫描半径,单位米 如1000米
     * @param {*} duration 持续时间,单位毫秒 如4000
     */
    showCircleScan(
      position: Array<number>,
      maxRadius: number,
    ) {
      const cartographicCenter = new Cesium.Cartographic(
        Cesium.Math.toRadians(position[0]),
        Cesium.Math.toRadians(position[1]),
        position[2]
      )
      const lastStage = this._addCircleScanPostStage(
        cartographicCenter,
        maxRadius,
      )
      return lastStage
    }
    /**
     * 添加扩散效果扫描线
     * @param {*} cartographicCenter  扫描中心
     * @param {*} maxRadius 扫描半径
     */
    _addCircleScanPostStage(
      cartographicCenter: any,
      maxRadius = 300,
    ) {
      const _Cartesian3Center =
        Cesium.Cartographic.toCartesian(cartographicCenter)
      const _Cartesian4Center = new Cesium.Cartesian4(
        _Cartesian3Center.x,
        _Cartesian3Center.y,
        _Cartesian3Center.z,
        1
      )
      const _CartograhpicCenter1 = new Cesium.Cartographic(
        cartographicCenter.longitude,
        cartographicCenter.latitude,
        cartographicCenter.height + 500
      )
      const _Cartesian3Center1 =
        Cesium.Cartographic.toCartesian(_CartograhpicCenter1)
      const _Cartesian4Center1 = new Cesium.Cartesian4(
        _Cartesian3Center1.x,
        _Cartesian3Center1.y,
        _Cartesian3Center1.z,
        1
      )
      const _scratchCartesian4Center = new Cesium.Cartesian4()
      const _scratchCartesian4Center1 = new Cesium.Cartesian4()
      const _scratchCartesian3Normal = new Cesium.Cartesian3()
      const _this = this
      const ScanPostStage = new Cesium.PostProcessStage({
        fragmentShader: _this._getScanSegmentShader(),
        uniforms: {
          u_scanCenterEC: function() {
            const temp = Cesium.Matrix4.multiplyByVector(
              _this.viewer.camera._viewMatrix,
              _Cartesian4Center,
              _scratchCartesian4Center
            )
            return temp
          },
          u_scanPlaneNormalEC: function() {
            const temp = Cesium.Matrix4.multiplyByVector(
              _this.viewer.camera._viewMatrix,
              _Cartesian4Center,
              _scratchCartesian4Center
            )
            const temp1 = Cesium.Matrix4.multiplyByVector(
              _this.viewer.camera._viewMatrix,
              _Cartesian4Center1,
              _scratchCartesian4Center1
            )
            _scratchCartesian3Normal.x = temp1.x - temp.x
            _scratchCartesian3Normal.y = temp1.y - temp.y
            _scratchCartesian3Normal.z = temp1.z - temp.z
            Cesium.Cartesian3.normalize(
              _scratchCartesian3Normal,
              _scratchCartesian3Normal
            )
            return _scratchCartesian3Normal
          },
          u_radius: function() {
            return maxRadius
          },
          u_scanColor: new Cesium.Color(0.2,0.25,0.3,0.1),
        },
      })
      this.viewer.scene.postProcessStages.add(ScanPostStage)
      return ScanPostStage
    }
    /**
     * 扩散效果Shader
     */
    _getScanSegmentShader() {
      const scanSegmentShader =
        ` uniform sampler2D colorTexture;
          uniform sampler2D depthTexture;
          in vec2 v_textureCoordinates;
          uniform vec4 u_scanCenterEC;
          uniform vec3 u_scanPlaneNormalEC;
          uniform float u_radius;
          uniform vec4 u_scanColor;
          vec4 toEye(in vec2 uv, in float depth){
            vec2 xy = vec2((uv.x * 2.0 - 1.0),(uv.y * 2.0 - 1.0));
            vec4 posInCamera = czm_inverseProjection * vec4(xy, depth, 1.0);
            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.0 * z_window - n_range - f_range) / (f_range - n_range);
          }
          
          void main(){
              out_FragColor = texture(colorTexture, v_textureCoordinates);
              float depth = getDepth(texture(depthTexture, v_textureCoordinates));
              vec4 viewPos = toEye(v_textureCoordinates, depth);
              vec3 scanCenterEC = u_scanCenterEC.xyz + vec3(cos(czm_frameNumber * 0.05) * 300.0,sin(czm_frameNumber * 0.05) * 300.0, sin(czm_frameNumber * 0.01) * 300.0);
              vec3 prjOnPlane = pointProjectOnPlane(u_scanPlaneNormalEC.xyz, scanCenterEC.xyz, viewPos.xyz);
              float dis = length(prjOnPlane.xyz - scanCenterEC.xyz);
              if(dis < u_radius){
                out_FragColor += pow(150.0/max(dis,150.0),2.0) * u_scanColor;
              }
          }
        `
      return scanSegmentShader
    }
    /**
     * 清除特效对象
     * @param {*} lastStage 特效对象
     */
    clearScanEffects(lastStage: any) {
      this.viewer.scene.postProcessStages.remove(lastStage)
    }
  }
  
  export default CircleDiffusion

在着色器中,给出了半径和角度还有根据光线到中心点的衰减是通过一个指数来实现的,可以自定义优化一下,我去的指数为2,可以根据实际项目需要进行更改

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 雷达测控是一种常见的遥感技术,通过使用雷达设备来获取目标物体的位置信息,进而实现目标物体跟踪和测控的功能。three.js是一个强大的JavaScript库,用于在网页上创建和渲染3D图形,而Cesium是一个开源的地理信息系统库,用于创建地球表面的3D可视化。 结合three.jsCesium,我们可以实现雷达测控的可视化效果。首先,我们需要使用Cesium创建一个地球表面的3D场景,将目标物体的位置数据与地球模型关联起来。Cesium提供了许多API来实现地图的交互和展示功能,我们可以使用这些API来控制地球的旋转、缩放等操作,以及在地球表面上添加其他的标记和图层。 通过three.js的框架,我们可以创建3D模型来代表目标物体。我们可以使用three.js提供的几何体和材质来创建一个雷达设备的模型,并将其放置在Cesium创建的场景的目标物体的位置上。这样,雷达设备的模型就能够随着地球的旋转和缩放而移动和调整位置。 除了将雷达设备的模型放置在地球表面上,我们还可以通过three.js的灯光和阴影效果,使整个场景更加逼真。我们可以通过调整灯光的位置和强度,使雷达设备的模型有更真实的光照效果,并通过阴影效果来增加场景的深度和立体感。 总之,通过结合three.jsCesium,我们可以实现雷达测控的可视化效果,提供一个交互性强、真实感强的系统。用户可以通过控制操作来旋转、放大、缩小地球模型,并观察目标物体在地球表面的位置和状态。这样的系统可以为雷达测控提供更直观、更方便的展示和分析平台。 ### 回答2: three.js是一个用于创建和渲染3D图形的JavaScript库,而Cesium是一个用于创建和渲染地理信息的JavaScript库。结合使用这两个库可以实现雷达测控系统。 雷达测控系统,雷达用于侦测目标物体的位置和运动状态,而测控系统则负责接收雷达的数据,并对目标进行跟踪和分析。在结合three.jscesium之前,通常需要使用其他的工具或方法将雷达数据进行处理和可视化。但借助three.jscesium,我们可以更加方便地实现整个雷达测控系统的可视化。 首先,我们可以使用three.js创建雷达的几何模型和纹理材质,以展示雷达设备的外观和形态。可以通过three.js的相机、光照和渲染器等功能,将雷达设备渲染成逼真的3D模型,并将其放置在场景。 接着,我们可以使用cesium的地理坐标系功能,将雷达设备的位置精确地在地球表面上定位。通过cesium的地球模型,我们可以实现对雷达设备的地理信息的可视化显示,包括地形、地图等。可以将地球模型和雷达设备模型进行融合,形成一个整体的测控系统模型。 此外,我们可以通过three.jscesium提供的API,将雷达数据以点云或网格的形式进行可视化。可以根据雷达测量到的目标物体的距离、速度等信息,将其以点云或网格的形式展示在场景,并通过三维空间的位置、颜色等属性,对目标物体进行可视化分析和跟踪。 最后,借助three.jscesium的交互功能,我们可以实现对雷达测控系统的交互操作,例如缩放、旋转、选择目标等。通过用户的交互操作,可以对目标物体进行测控系统的控制和调整,进一步提高雷达测控系统的可视化效果和用户体验。 综上所述,借助three.jscesium,我们可以更加方便地实现雷达测控系统的可视化,包括雷达设备、地球表面的地理信息以及目标物体的可视化分析和跟踪。这种结合使用能够提高雷达测控系统的效率和准确性,同时也提升了用户对系统的理解和操作能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值