3D火星视角

This commit is contained in:
along
2026-02-22 11:45:18 +08:00
parent 9d3eb833db
commit 9159120279
8 changed files with 695 additions and 71 deletions

View File

@@ -1,71 +1,11 @@
<template>
<div ref="cesiumContainer" id="cesium-container"></div>
<RouterView />
<nav class="page-nav">
<RouterLink to="/" class="nav-link">Earth</RouterLink>
<RouterLink to="/mars" class="nav-link">Mars</RouterLink>
</nav>
</template>
<script setup>
import { onMounted, onBeforeUnmount, ref } from 'vue'
import * as Cesium from 'cesium'
import 'cesium/Build/Cesium/Widgets/widgets.css'
// 替换为你自己的 tokenhttps://ion.cesium.com
Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI1ZGQ4MTNmMy01YTMwLTQ3MzYtOWYwOS0yNWJjY2M4NGMwZDkiLCJpZCI6MzkyNzAxLCJpYXQiOjE3NzE2Njg3NjV9.Ocngj9fTNpIJVIOD8__NGQd5o5blbBKJ-pl9Xzf-Cd4'
const cesiumContainer = ref(null)
let viewer = null
onMounted(() => {
viewer = new Cesium.Viewer(cesiumContainer.value, {
terrain: Cesium.Terrain.fromWorldTerrain(),
baseLayerPicker: false,
geocoder: false,
homeButton: false,
sceneModePicker: false,
navigationHelpButton: false,
animation: false,
timeline: false,
fullscreenButton: false,
})
// 移除默认 Bing Maps 底图,换成自己的全球图层
viewer.imageryLayers.remove(viewer.imageryLayers.get(0))
// 第一层Natural Earth 全球底图port 8001
viewer.imageryLayers.addImageryProvider(
new Cesium.UrlTemplateImageryProvider({
url: 'http://localhost:8010/tiles/{z}/{x}/{y}.png',
tilingScheme: new Cesium.WebMercatorTilingScheme(),
maximumLevel: 15,
credit: 'Natural Earth - HYP_HR_SR_OB_DR',
})
)
// // 第二层NJ 高分辨率航拍port 8000叠加在全球底图之上
// viewer.imageryLayers.addImageryProvider(
// new Cesium.UrlTemplateImageryProvider({
// url: 'http://localhost:8000/tiles/{z}/{x}/{y}.png',
// tilingScheme: new Cesium.WebMercatorTilingScheme(),
// maximumLevel: 21,
// credit: 'NJ Open Imagery 2020 - I7D16',
// })
// )
// 从全球视角出发,飞向 NJ 影像区域
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(-74.30054, 40.61087, 12000000),
// complete: () => {
// viewer.camera.flyTo({
// destination: Cesium.Cartesian3.fromDegrees(-74.30054, 40.61087, 3000),
// duration: 3,
// })
// },
})
})
onBeforeUnmount(() => {
viewer?.destroy()
})
</script>
<style>
* {
margin: 0;
@@ -80,8 +20,40 @@ body {
overflow: hidden;
}
#cesium-container {
width: 100vw;
height: 100vh;
.page-nav {
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
z-index: 100;
display: flex;
gap: 8px;
background: rgba(0, 0, 0, 0.5);
padding: 6px 10px;
border-radius: 20px;
backdrop-filter: blur(6px);
}
.nav-link {
color: rgba(255, 255, 255, 0.7);
text-decoration: none;
font-family: sans-serif;
font-size: 13px;
font-weight: 600;
letter-spacing: 0.06em;
text-transform: uppercase;
padding: 4px 14px;
border-radius: 14px;
transition: background 0.2s, color 0.2s;
}
.nav-link:hover {
color: #fff;
background: rgba(255, 255, 255, 0.15);
}
.nav-link.router-link-active {
color: #fff;
background: rgba(255, 255, 255, 0.2);
}
</style>

View File

@@ -1,5 +1,9 @@
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router'
import * as Cesium from 'cesium'
createApp(App).mount('#app')
Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI1ZGQ4MTNmMy01YTMwLTQ3MzYtOWYwOS0yNWJjY2M4NGMwZDkiLCJpZCI6MzkyNzAxLCJpYXQiOjE3NzE2Njg3NjV9.Ocngj9fTNpIJVIOD8__NGQd5o5blbBKJ-pl9Xzf-Cd4'
createApp(App).use(router).mount('#app')

13
src/router/index.js Normal file
View File

@@ -0,0 +1,13 @@
import { createRouter, createWebHashHistory } from 'vue-router'
import EarthView from '../views/EarthView.vue'
import MarsView from '../views/MarsView.vue'
const routes = [
{ path: '/', component: EarthView },
{ path: '/mars', component: MarsView },
]
export default createRouter({
history: createWebHashHistory(),
routes,
})

51
src/views/EarthView.vue Normal file
View File

@@ -0,0 +1,51 @@
<template>
<div ref="cesiumContainer" class="cesium-fullscreen"></div>
</template>
<script setup>
import { onMounted, onBeforeUnmount, ref } from 'vue'
import * as Cesium from 'cesium'
import 'cesium/Build/Cesium/Widgets/widgets.css'
const cesiumContainer = ref(null)
let viewer = null
onMounted(() => {
viewer = new Cesium.Viewer(cesiumContainer.value, {
terrain: Cesium.Terrain.fromWorldTerrain(),
baseLayerPicker: false,
geocoder: false,
homeButton: false,
sceneModePicker: false,
navigationHelpButton: false,
animation: false,
timeline: false,
fullscreenButton: false,
})
viewer.imageryLayers.remove(viewer.imageryLayers.get(0))
viewer.imageryLayers.addImageryProvider(
new Cesium.UrlTemplateImageryProvider({
url: 'http://localhost:8010/tiles/{z}/{x}/{y}.png',
tilingScheme: new Cesium.WebMercatorTilingScheme(),
maximumLevel: 15,
credit: 'Natural Earth - HYP_HR_SR_OB_DR',
})
)
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(-74.30054, 40.61087, 12000000),
})
})
onBeforeUnmount(() => {
viewer?.destroy()
})
</script>
<style scoped>
.cesium-fullscreen {
width: 100vw;
height: 100vh;
}
</style>

63
src/views/MarsView.vue Normal file
View File

@@ -0,0 +1,63 @@
<template>
<div ref="cesiumContainer" class="cesium-fullscreen"></div>
</template>
<script setup>
import { onMounted, onBeforeUnmount, ref } from 'vue'
import * as Cesium from 'cesium'
import 'cesium/Build/Cesium/Widgets/widgets.css'
const cesiumContainer = ref(null)
let viewer = null
onMounted(async () => {
viewer = new Cesium.Viewer(cesiumContainer.value, {
terrainProvider: false,
baseLayer: false,
baseLayerPicker: false,
geocoder: false,
homeButton: false,
sceneModePicker: false,
navigationHelpButton: false,
animation: false,
timeline: false,
fullscreenButton: false,
shadows: false,
globe: new Cesium.Globe(Cesium.Ellipsoid.MARS),
skyBox: Cesium.SkyBox.createEarthSkyBox(),
skyAtmosphere: new Cesium.SkyAtmosphere(Cesium.Ellipsoid.MARS),
})
// Hide the default globe mesh — surface comes from the Ion tileset
viewer.scene.globe.show = false
// Mars-like atmosphere (reddish, thinner than Earth)
const atmo = viewer.scene.skyAtmosphere
atmo.atmosphereMieCoefficient = new Cesium.Cartesian3(9.0e-5, 2.0e-5, 1.0e-5)
atmo.atmosphereRayleighCoefficient = new Cesium.Cartesian3(9.0e-6, 2.0e-6, 1.0e-6)
atmo.atmosphereRayleighScaleHeight = 9000
atmo.atmosphereMieScaleHeight = 2700.0
atmo.saturationShift = -0.1
atmo.perFragmentAtmosphere = true
// Mars global 3D tileset from Cesium Ion (asset 3644333)
try {
const tileset = await Cesium.Cesium3DTileset.fromIonAssetId(3644333)
viewer.scene.primitives.add(tileset)
viewer.zoomTo(tileset)
} catch (error) {
console.error('Failed to load Mars tileset:', error)
}
})
onBeforeUnmount(() => {
viewer?.destroy()
})
</script>
<style scoped>
.cesium-fullscreen {
width: 100vw;
height: 100vh;
}
</style>