three.js 地球与卫星绕地飞行【真实三维数据】
·
(真实经纬度运行轨迹)
完整代码
<template>
<div class="home3dMap" id="home3dMap" v-loading="loading"></div>
</template>
<script>
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
export default {
name:"home3dMap",
data(){
return {
loading:true,
scene:null, //场景
camera:null, //相机
meshMaterial:null, //网络模型
renderer:null, //渲染器
controls:null, //控制器
areaSize:{
width:960,
height:685,
},
//canvas内的数据
map:{
earthRadius:75, //地球半径
satList:[], //卫星列表
originalData:{}, //原始数据
satellitePoint:[], //卫星画线 (包括卫星名称,三维xyz)
circleLonLat:[], //单个卫星画圈集合(卫星轨迹) 用于圆环跟随地球旋转
satelliteArr:[], //卫星集合 (针对卫星)
circleTime:"", //卫星间隔时间
satTime:[], //画圈定时器 (多个圆环的定时)
setInteI:[], //卫星画圈定时器索引 (多个卫星圆环的定时器初始值)
flag:true, //true:实时模式、false:历史模式
speedValue:1, //最终选择的倍速值
},
}
},
beforeDestroy(){
//清除定时器,如果定时器存在
if(this.map.satTime.length > 0){
for(let i=0,list=this.map.satTime; i<list.length; i++){
window.clearInterval(list[i]);
}
}
this.map.satTime = [];
//重置定时器初始值
this.map.setInteI = [];
},
mounted(){
//初始化
this.init();
},
methods:{
init(){
this.createScene(); //创建场景
this.createLight(); //创建光源
this.createCamera(); //创建相机
//稍后启动
this.laterInit()
},
//稍后启动
async laterInit(){
let sadData = await this.orbitCalcFunAcquisition(); //世界地图轨道数据
this.loading = false; //关闭loading
if(sadData.length < 1){
return;
}
this.createMesh(); //创建几何体
this.createRender(); //创建渲染器
this.createControls(); //创建轨道控制器
this.animate();
},
//创建场景
createScene(){
let scene = new THREE.Scene();
this.scene = scene;
},
//创建光源
createLight(){
// 环境光
const ambientLight = new THREE.AmbientLight(0xcccccc, 2)
this.scene.add(ambientLight)
// 平行光
let directionalLight = new THREE.DirectionalLight(0xffffff, 0.2)
directionalLight.position.set(1, 0.2, 0).normalize()
// 平行光2
let directionalLight2 = new THREE.DirectionalLight(0xff2ffff, 0.2)
directionalLight2.position.set(1, 0.2, 0.1).normalize()
this.scene.add(directionalLight)
this.scene.add(directionalLight2)
// 半球光
let hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444, 0.2)
hemiLight.position.set(5, 50, 0)
// this.scene.add(hemiLight)
// 平行光3
let directionalLight3 = new THREE.DirectionalLight(0xffffff, 0)
// directionalLight3.position.set(1, 50, -2)
// 开启阴影
directionalLight3.castShadow = true
// 设置光边界
// directionalLight3.shadow.camera.top = 18
// directionalLight3.shadow.camera.bottom = -10
// directionalLight3.shadow.camera.left = -52
// directionalLight3.shadow.camera.right = 12
this.scene.add(directionalLight3)
},
//创建相机
createCamera(){
let areaSize = this.areaSize;
//渲染区域
let camera = new THREE.PerspectiveCamera(60, areaSize.width / areaSize.height, 0.1, 10000)
//设置相机位置
camera.position.set(50, -10, 200)
//设置相机方向
camera.lookAt(0, 0, 0)
this.camera = camera;
this.scene.add(this.camera);
},
//创建几何体
createMesh(){
//地球
let geometry = new THREE.SphereGeometry( this.map.earthRadius, 64, 32);
let earthImgSrc = require('@/assets/img/home/home3dMapBackground.png');
//材质
let earthMater = new THREE.MeshPhongMaterial({
map: new THREE.TextureLoader().load(earthImgSrc),
transparent:true,
depthWrite:false,
});
//网络模型对象 -- 地球
let meshMaterial = new THREE.Mesh(geometry,earthMater);
//地球模型
this.meshMaterial = meshMaterial;
//添加到场景中
this.scene.add(meshMaterial);
//添加圆环
this.initSatellite(meshMaterial);
},
//添加圆环
initSatellite(meshMaterial){
//返回一个卫星和轨道的组合体
// satelliteSize/卫星大小 satelliteRadius/卫星旋转半径 rotation /组合体的旋转方向 speed/卫星运动速度
// 圆环图片
let sadImgSrc = require('@/assets/img/control/satellite.png');
//循环卫星轨迹 默认一个轨迹上只有一个卫星 【卫星轨迹的第一个位置数据就是卫星初次的位置数据】
for(let i=0,list=this.map.satellitePoint; i<list.length; i++){
// 卫星轨迹使用曲线办法,曲线轨迹不是闭合的,第一圈和下一圈似乎轨迹位置不是重合的】
// 卫星轨迹三维点数据
let circleArr = list[i].mapArray;
// 数据格式格式化
let circleArrForamt = [];
//当前卫星轨迹曲线
for(let j=0; j<circleArr.length; j++){
let item = circleArr[j];
circleArrForamt.push(new THREE.Vector3(item.x3d,item.y3d,item.z3d))
}
const curve = new THREE.CatmullRomCurve3( circleArrForamt );
const points = curve.getPoints( 70 );
const geometry = new THREE.BufferGeometry().setFromPoints( points );
const material = new THREE.LineBasicMaterial( { color: 0xffffff } );
const circleLonLat = new THREE.Line( geometry, material );
//将圆环存储
this.map.circleLonLat.push(circleLonLat); //用于圆环跟随地球旋转
//卫星
let satellite = new THREE.Sprite(new THREE.SpriteMaterial({
map: new THREE.TextureLoader().load(sadImgSrc),
blending: THREE.AdditiveBlending
}));
//卫星大小
satellite.scale.x = satellite.scale.y = satellite.scale.z = 12;
//卫星旋转半径
satellite.position.set(circleArr[0].x3d, circleArr[0].y3d, circleArr[0].z3d);
//Object3D
let pivotPoint = new THREE.Object3D();
pivotPoint.add(satellite);
//将卫星对象增加到圆环轨迹中
circleLonLat.add(pivotPoint);
//将卫星存储
this.map.satelliteArr.push(satellite);
//将圆环添加到场景中
this.scene.add(circleLonLat);
//物体延线移动方法
if(curve && satellite){ //轨道和卫星都存在
this.map.satTime = [];
this.map.setInteI[i] = 0;
this.map.satTime[i] = setInterval(()=>{
if(this.map.setInteI[i] - circleArr.length <= 0){
//每一个
// let point = curve.getPointAt(this.map.setInteI); //获取曲线指定点坐标
// if(point){
// satellite.position.set(point.x, point.y, point.z);
// }
let point = circleArr[this.map.setInteI[i]];
if(point){
satellite.position.set(point.x3d, point.y3d, point.z3d);
}
}else{
//实时模式重新触发接口事件
if(this.map.flag){
this.laterInit();
}else{
//历史械重新走数据
}
this.map.setInteI[i] = 0;
}
//定时器开启
this.map.setInteI[i]++;
},Math.ceil(this.map.circleTime/this.map.speedValue))
}
}
},
//发光的星星
generateSprite(color){
let canvas = document.createElement('canvas');
canvas.width = 16;
canvas.height = 16;
let context = canvas.getContext('2d');
let gradient = context.createRadialGradient(canvas.width / 2, canvas.height / 2, 0, canvas.width / 2, canvas.height / 2, canvas.width / 2);
gradient.addColorStop(0, 'rgba(' + color + ',1)');
gradient.addColorStop(0.2, 'rgba(' + color + ',1)');
gradient.addColorStop(0.4, 'rgba(' + color + ',.6)');
gradient.addColorStop(1, 'rgba(0,0,0,0)');
context.fillStyle = gradient;
context.fillRect(0, 0, canvas.width, canvas.height);
return canvas;
},
//创建渲染器
createRender(){
let element = document.getElementById("home3dMap");
//创建渲染器
let renderer = new THREE.WebGLRenderer({
antialias:true, //开启抗锯齿
alpha:true,
})
let areaSize = this.areaSize;
renderer.setSize(areaSize.width,areaSize.height) //设置渲染区域尺寸
renderer.shadowMap.enabled = true; //显示阴影
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.setClearColor(0x3f3f3f, 0); //设置背景颜色
this.renderer = renderer;
element.appendChild(this.renderer.domElement)
},
//创建轨道控制器
createControls(){
let controls = new OrbitControls(this.camera, this.renderer.domElement);
controls.enableDamping = true; //开启衰弱
controls.maxZoom = Infinity;
controls.minDistance = 75; //设置最小可缩放
this.controls = controls;
},
//循环
animate(){
this.controls.update(); //控制阻尼器
//地球自传
this.meshMaterial.rotation.y += 0.0015;
this.renderer.render(this.scene, this.camera);
//卫星轨迹转动
for(let i=0; i<this.map.circleLonLat.length; i++){
this.map.circleLonLat[i].rotation.y += 0.0015;
}
requestAnimationFrame(this.animate.bind(this));
},
//卫星列表
async sadListAcquisition(){
return new Promise(resolve => {
this.$apilist.OBSERVE_stationControl_satellite_list("").then(res => {
if(res.code == "200"){
this.map.satList = res.data;
resolve(res.data);
}
})
})
},
//世界地图轨道数据
async orbitCalcFunAcquisition(){
//关闭定时器
if(this.map.satTime.length > 0){
for(let i=0,list=this.map.satTime; i<list.length; i++){
window.clearInterval(list[i]);
}
}
let satList = await this.sadListAcquisition();
if(satList.length < 1){
this.$message.warning("卫星列表为空");
return;
}
//公共方法
return new Promise(resolve=>{
this.orbitCalcFunAcquisitionPublic(resolve);
})
},
//公共方法
async orbitCalcFunAcquisitionPublic(resolve){
let jsonData = {
startTime:this.$dateFormat.format(new Date()),
endTime:this.$dateFormat.format(new Date(new Date().getTime() + 2*50*60*1000))
};
this.$apilist.OBSERVE_stationControl_globalMapTrack_list(jsonData).then(res => {
if(res.code == "200"){
this.map.originalData = res.data; //保存原始数据
this.map.satellitePoint = []; //清空卫星画线
let mapArray = res.data.positionMap; //卫星数组(卫星经纬度-轨迹经纬度)
let mapTime = res.data.dateTimeList; //卫星时间
this.map.circleTime = (res.data.timeGap + '000')*1; //卫星间隔时间
//卫星轨迹高度 卫星轨迹高度870km/地球半径6378km*当前地球球体半径(this.map.earthRadius)
let satelliteRadius = (this.map.earthRadius-0)+(870-0)/6378*(this.map.earthRadius-0);
//轨迹三维
for(let key in mapArray){
mapArray[key].forEach((item,index)=>{
let obj = this.$lnglatFormat.lnlt2xyz(item.lon,item.lat,satelliteRadius);
item.x3d = obj.x;
item.y3d = obj.y;
item.z3d = obj.z;
});
this.map.satellitePoint.push({
sat:key,
mapArray:mapArray[key],
})
};
//push卫星名
this.map.satellitePoint.forEach((item,index)=>{
this.map.satList.forEach((value,i)=>{
if(item.sat == value.satelliteCode){
item.satName = value.satelliteName;
}
})
});
resolve(this.map.satellitePoint);
}
})
}
},
}
</script>
<style>
.home3dMap{
width:100%;
height:100%;
/* background:rgba(103,22,173,0.3); */
}
</style>
lnlt2xyz方法:
//二维经纬度数据转为三维空间位置数据
lnlt2xyz(lon, lat, h){
let radius = h;
const phi = (360 + lon) * (Math.PI / 180)
const theta = (180 - lat) * (Math.PI / 180)
return {
x: -radius * Math.sin(theta) * Math.cos(phi),
y: radius * Math.cos(theta),
z: radius * Math.sin(theta) * Math.sin(phi),
}
},
最终效果
更多推荐
已为社区贡献1条内容
所有评论(0)