diff --git a/.gitignore b/.gitignore index 78a752d..aed7921 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ selenium-debug.log package-lock.json yarn.lock +pnpm-lock.yaml diff --git a/src/assets/icons/toolbar_night.png b/src/assets/icons/toolbar_night.png new file mode 100644 index 0000000..b9808ed Binary files /dev/null and b/src/assets/icons/toolbar_night.png differ diff --git a/src/assets/images/night_box/negx.jpg b/src/assets/images/night_box/negx.jpg new file mode 100644 index 0000000..8488ee3 Binary files /dev/null and b/src/assets/images/night_box/negx.jpg differ diff --git a/src/assets/images/night_box/negy.jpg b/src/assets/images/night_box/negy.jpg new file mode 100644 index 0000000..2598bee Binary files /dev/null and b/src/assets/images/night_box/negy.jpg differ diff --git a/src/assets/images/night_box/negz.jpg b/src/assets/images/night_box/negz.jpg new file mode 100644 index 0000000..f9f2b0d Binary files /dev/null and b/src/assets/images/night_box/negz.jpg differ diff --git a/src/assets/images/night_box/posx.jpg b/src/assets/images/night_box/posx.jpg new file mode 100644 index 0000000..ca34480 Binary files /dev/null and b/src/assets/images/night_box/posx.jpg differ diff --git a/src/assets/images/night_box/posy.jpg b/src/assets/images/night_box/posy.jpg new file mode 100644 index 0000000..bbaa382 Binary files /dev/null and b/src/assets/images/night_box/posy.jpg differ diff --git a/src/assets/images/night_box/posz.jpg b/src/assets/images/night_box/posz.jpg new file mode 100644 index 0000000..f6b756e Binary files /dev/null and b/src/assets/images/night_box/posz.jpg differ diff --git a/src/components/CesiumMap/skyBoxOnGround.js b/src/components/CesiumMap/skyBoxOnGround.js new file mode 100644 index 0000000..ea4aa89 --- /dev/null +++ b/src/components/CesiumMap/skyBoxOnGround.js @@ -0,0 +1,230 @@ +import * as Cesium from 'cesium' + +//片元着色器,直接从源码复制 +const SkyBoxFS = `uniform samplerCube u_cubeMap; + in vec3 v_texCoord; + out vec4 fragColor; + void main(){ + vec4 color = texture(u_cubeMap, normalize(v_texCoord)); + fragColor = vec4(czm_gammaCorrect(color).rgb, czm_morphTime); + } +`; + +//顶点着色器有修改,主要是乘了一个旋转矩阵 +const SkyBoxVS = ` + in vec3 position; + out vec3 v_texCoord; + uniform mat3 u_rotateMatrix; + void main(){ + vec3 p = czm_viewRotation * u_rotateMatrix * (czm_temeToPseudoFixed * (czm_entireFrustum.y * position)); + gl_Position = czm_projection * vec4(p, 1.0); + v_texCoord = position.xyz; + } +`; + +const BoxGeometry = Cesium.BoxGeometry; +const Cartesian3 = Cesium.Cartesian3; +const defaultValue = Cesium.defaultValue; +const defined = Cesium.defined; +const destroyObject = Cesium.destroyObject; +const DeveloperError = Cesium.DeveloperError; +const GeometryPipeline = Cesium.GeometryPipeline; +const Matrix3 = Cesium.Matrix3; +const Matrix4 = Cesium.Matrix4; +const Transforms = Cesium.Transforms; +const VertexFormat = Cesium.VertexFormat; +const BufferUsage = Cesium.BufferUsage; +const CubeMap = Cesium.CubeMap; +const DrawCommand = Cesium.DrawCommand; +const loadCubeMap = Cesium.loadCubeMap; +const RenderState = Cesium.RenderState; +const VertexArray = Cesium.VertexArray; +const BlendingState = Cesium.BlendingState; +const SceneMode = Cesium.SceneMode; +const ShaderProgram = Cesium.ShaderProgram; +const ShaderSource = Cesium.ShaderSource; + +const skyboxMatrix3 = new Matrix3(); + +// 存储默认天空盒 +let defaultSkybox = null +// 存储当前天空盒 +let currentSkybox = null + +const checkSkyBoxEventHandler = (scene) => { + let position = scene.camera.position; + let cameraHeight = Cesium.Cartographic.fromCartesian(position).height; + if (cameraHeight < 240000) { + scene.skyBox = currentSkybox; + scene.skyAtmosphere.show = false; + } else { + scene.skyBox = defaultSkybox; + scene.skyAtmosphere.show = true; + } +} + + +/** +* 为了兼容高版本的Cesium,因为新版cesium中getRotation被移除 +*/ +if (!Cesium.defined(Cesium.Matrix4.getRotation)) { + Cesium.Matrix4.getRotation = Cesium.Matrix4.getMatrix3 +} + +/** +* 近景天空盒 +* @type Object +* @default undefined +*/ +export default class SkyBoxOnGround { + constructor(options) { + this.sources = options.sources; + this._sources = undefined; + /** + * Determines if the sky box will be shown. + * + * @type {Boolean} + * @default true + */ + this.show = defaultValue(options.show, true); + + this._command = new DrawCommand({ + modelMatrix: Matrix4.clone(Matrix4.IDENTITY), + owner: this + }); + this._cubeMap = undefined; + + this._attributeLocations = undefined; + this._useHdr = undefined; + + // 将生成的天空盒传出保存 + currentSkybox = this; + } + + update(frameState, useHdr) { + const that = this; + + if (!this.show) { + return undefined; + } + + if ((frameState.mode !== SceneMode.SCENE3D) && (frameState.mode !== SceneMode.MORPHING)) { + return undefined; + } + + if (!frameState.passes.render) { + return undefined; + } + + const context = frameState.context; + + if (this._sources !== this.sources) { + this._sources = this.sources; + const sources = this.sources; + + if ((!defined(sources.positiveX)) || (!defined(sources.negativeX)) || (!defined(sources.positiveY)) || (!defined(sources.negativeY)) || (!defined(sources.positiveZ)) || (!defined(sources.negativeZ))) { + throw new DeveloperError('this.sources is required and must have positiveX, negativeX, positiveY, negativeY, positiveZ, and negativeZ properties.'); + } + + if ((typeof sources.positiveX !== typeof sources.negativeX) || (typeof sources.positiveX !== typeof sources.positiveY) || (typeof sources.positiveX !== typeof sources.negativeY) || (typeof sources.positiveX !== typeof sources.positiveZ) || (typeof sources.positiveX !== typeof sources.negativeZ)) { + throw new DeveloperError('this.sources properties must all be the same type.'); + } + + if (typeof sources.positiveX === 'string') { + loadCubeMap(context, this._sources).then(function (cubeMap) { + that._cubeMap = that._cubeMap && that._cubeMap.destroy(); + that._cubeMap = cubeMap; + }); + } else { + this._cubeMap = this._cubeMap && this._cubeMap.destroy(); + this._cubeMap = new CubeMap({ + context: context, + source: sources + }); + } + } + + const command = this._command; + + command.modelMatrix = Transforms.eastNorthUpToFixedFrame(frameState.camera._positionWC); + + if (!defined(command.vertexArray)) { + command.uniformMap = { + u_cubeMap: function () { + return that._cubeMap; + }, + u_rotateMatrix: function () { + return Matrix4.getRotation(command.modelMatrix, skyboxMatrix3); + }, + }; + + const geometry = BoxGeometry.createGeometry(BoxGeometry.fromDimensions({ + dimensions: new Cartesian3(2.0, 2.0, 2.0), + vertexFormat: VertexFormat.POSITION_ONLY + })); + const attributeLocations = this._attributeLocations = GeometryPipeline.createAttributeLocations(geometry); + + command.vertexArray = VertexArray.fromGeometry({ + context: context, + geometry: geometry, + attributeLocations: attributeLocations, + bufferUsage: BufferUsage._DRAW + }); + + command.renderState = RenderState.fromCache({ + blending: BlendingState.ALPHA_BLEND + }); + } + + if (!defined(command.shaderProgram) || this._useHdr !== useHdr) { + const fs = new ShaderSource({ + defines: [useHdr ? 'HDR' : ''], + sources: [SkyBoxFS] + }); + command.shaderProgram = ShaderProgram.fromCache({ + context: context, + vertexShaderSource: SkyBoxVS, + fragmentShaderSource: fs, + attributeLocations: this._attributeLocations + }); + this._useHdr = useHdr; + } + + if (!defined(this._cubeMap)) { + return undefined; + } + return command; + } + + setSkyBox(viewer) { + + // 自带的默认天空盒 + defaultSkybox = viewer.scene.skyBox; + + // 渲染前监听并判断相机位置 + viewer.scene.preUpdate.addEventListener(checkSkyBoxEventHandler); + } + + removeSkyBox(viewer) { + if(!viewer || !defaultSkybox) return; + + viewer.scene.preUpdate.removeEventListener(checkSkyBoxEventHandler); + viewer.scene.skyBox = defaultSkybox; + viewer.scene.skyAtmosphere.show = true; + defaultSkybox = null; + } + + isDestroyed() { + return false + } + + destroy() { + defaultSkybox = null; + currentSkybox = null; + const command = this._command; + command.vertexArray = command.vertexArray && command.vertexArray.destroy(); + command.shaderProgram = command.shaderProgram && command.shaderProgram.destroy(); + this._cubeMap = this._cubeMap && this._cubeMap.destroy(); + return destroyObject(this); + } +} diff --git a/src/views/systemTemplate/forestFire/Toolbar/Toolbar.vue b/src/views/systemTemplate/forestFire/Toolbar/Toolbar.vue index 4f492f0..6cd4d37 100644 --- a/src/views/systemTemplate/forestFire/Toolbar/Toolbar.vue +++ b/src/views/systemTemplate/forestFire/Toolbar/Toolbar.vue @@ -74,10 +74,11 @@ import { drawKeyarea, pickFeatureProperty, } from './forestFireDraw' +import SkyBoxOnGround from "@/components/CesiumMap/skyBoxOnGround"; // 属性弹窗相关 -import DialogPropertyGrid from './../DialogPropertyGrid'; -import { setPropertyData } from './../DialogPropertyGrid/property'; -import FeatureGroundPrimitive from '@/components/CesiumMap/FeatureGroundPrimitive'; +// import DialogPropertyGrid from './../DialogPropertyGrid'; +// import { setPropertyData } from './../DialogPropertyGrid/property'; +// import FeatureGroundPrimitive from '@/components/CesiumMap/FeatureGroundPrimitive'; // 工具栏图标 import baseDrawIcon from "@/assets/icons/toolbar_base_draw.png"; @@ -111,6 +112,14 @@ import toolbarKeyareaIcon from '@/assets/icons/toolbar_keyarea.png'; import toolbarRainIcon from '@/assets/icons/toolbar_rain.png'; import toolbarSnowIcon from '@/assets/icons/toolbar_snow.png'; import toolbarFogIcon from '@/assets/icons/toolbar_fog.png'; +import toolbarNightIcon from '@/assets/icons/toolbar_night.png'; +// 夜空盒图片 +import posx from '@/assets/images/night_box/posx.jpg'; +import negx from '@/assets/images/night_box/negx.jpg'; +import posy from '@/assets/images/night_box/posy.jpg'; +import negy from '@/assets/images/night_box/negy.jpg'; +import posz from '@/assets/images/night_box/posz.jpg'; +import negz from '@/assets/images/night_box/negz.jpg'; const props = defineProps({ viewer: { @@ -120,6 +129,19 @@ const props = defineProps({ // 初始化地图实例 let viewer = null +// cesium自带天空盒 +let defaultSkybox = null +// 近地夜空盒 +const groundSkyBox = new SkyBoxOnGround({ + sources: { + positiveX: posx, + negativeX: negx, + positiveY: posy, + negativeY: negy, + positiveZ: posz, + negativeZ: negz, + }, +}) let drawTool = null let measureTool = null let weatherParticle = null @@ -279,6 +301,13 @@ const options = ref([ icon: toolbarFogIcon, active: false }, + { + id: 34, + name: 'night', + label: '近地夜晚环境', + icon: toolbarNightIcon, + active: false + }, ] }, { @@ -341,11 +370,18 @@ const weatherSwitchClick = (name) => { if(option.active) { option.active = false; - weatherParticle.destroy(); + if(option.name === 'night') { + groundSkyBox.removeSkyBox(viewer); + } else { + weatherParticle.destroy(); + } } else { // 取消其它天气按钮的激活状态 list.forEach(item => { if(item.name !== name) { + if(item.name === 'night') { + groundSkyBox.removeSkyBox(viewer); + } item.active = false; } }); @@ -361,6 +397,8 @@ const weatherSwitchClick = (name) => { case 'fog': weatherParticle && weatherParticle.fog() break + case 'night': + groundSkyBox.setSkyBox(viewer); } } } @@ -368,6 +406,7 @@ const weatherSwitchClick = (name) => { watch(() => props.viewer, (v) => { if (v) { viewer = v; + defaultSkybox = v.scene.skyBox // 添加绘制图层 toolbarLayer = new Cesium.CustomDataSource('toolbarLayer'); @@ -416,6 +455,7 @@ watch(() => props.viewer, (v) => { bus.on('toolbar_rain', () => weatherSwitchClick('rain')) bus.on('toolbar_snow', () => weatherSwitchClick('snow')) bus.on('toolbar_fog', () => weatherSwitchClick('fog')) + bus.on('toolbar_night', () => weatherSwitchClick('night')) // 清空 bus.on('toolbar_clear', toolbarClear);