three.js绘制地球、飞机与轨迹的效果⽰例⾸先我们来看下要实现的效果
这个缩⼩后的图⽚,下⾯我们来看下近距离的动态效果。。
效果⽐较简陋,需要后期再处理。。。
下⾯进⼊主题,代码篇。。
HTML部分:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>全球航班</title>
<style>
html{overflow: hidden;}
body { margin: 0;}
</style>
<script src="js/jquery.min.js"></script>
</head>
<body>
<!-- 地国 -->
<div id="zh_globe_container"></div> <!-- 容器 -->
<script src="js/threejs/Detector.js"></script> <!-- webGL浏览器⽀持检测 -->
<script src="js/threejs/three.min.js"></script> <!-- 核⼼js -->
<script src="js/threejs/stats.min.js"></script> <!-- 性能测试 -->
<script src="js/threejs/OrbitControls.js"></script> <!-- 地球控制 -->
<script src="js/socketio-1.4.5.js"></script> <!-- socket -->
<script src="js/globe.js"></script> <!-- -->
</body>
</html>
JS部分(globe.js)
1、实现地球
地球贴图(可以在⽹上下载)
// 地球
function globe() {
var globeTextureLoader = new THREE.TextureLoader();
globeTextureLoader.load('images/textures/earth.jpg', function (texture) {
var globeGgeometry = new THREE.SphereGeometry(200, 100, 100);
var globeMaterial = new THREE.MeshStandardMaterial({map: texture});
var globeMesh = new THREE.Mesh(globeGgeometry, globeMaterial);
group.add(globeMesh);
});
}
2、添加球⾯光源(这⾥使⽤的是半球光)
// 光
function lights() {
var hemisphereLight = new THREE.HemisphereLight(0xffffff, 0x333333, 2);
hemisphereLight.position.x = 0;
hemisphereLight.position.y = 0;
hemisphereLight.position.z = -200;
group.add(hemisphereLight);
}
// 星点
function stars() {
var starsGeometry = new THREE.Geometry();
for (var i = 0; i < 2000; i ++) {
var starVector = new THREE.Vector3(
THREE.Math.randFloatSpread(2000),
THREE.Math.randFloatSpread(2000),
THREE.Math.randFloatSpread(2000)
);
starsGeometry.vertices.push(starVector);
}
var starsMaterial = new THREE.PointsMaterial({color: 0x888888})
var starsPoint = new THREE.Points(starsGeometry, starsMaterial);
group.add(starsPoint);
}
4、添加飞机
这⾥需要我们把经纬度坐标转成 xyz 坐标
// 获取position
function getPosition(lng, lat, alt) {
var phi = (90-lat)*(Math.PI/180),
theta = (lng+180)*(Math.PI/180),
radius = alt+200,
x = -(radius * Math.sin(phi) * s(theta)),
z = (radius * Math.sin(phi) * Math.sin(theta)),
y = (radius * s(phi));
return {x: x, y: y, z: z};
}
画飞机
// 飞机形状(不想画的,可以下载个飞机模型使⽤加载器加载进来)
var planeShape = new THREE.Shape();
planeShape.lineTo(0.2, -0.2);
planeShape.lineTo(0.2, -1.3);
planeShape.lineTo(1.6,-2.7);
planeShape.lineTo(1.6,-3);
planeShape.lineTo(0.2, -2.1);
planeShape.lineTo(0.2, -3);
planeShape.lineTo(0.5, -3.4);
planeShape.lineTo(0.5, -3.7);
planeShape.lineTo(0, -3.3);
planeShape.lineTo(-0.5, -3.7);
planeShape.lineTo(-0.5, -3.4);
planeShape.lineTo(-0.2, -3);
planeShape.lineTo(-0.2, -2.1);
planeShape.lineTo(-1.6,-3);
planeShape.lineTo(-1.6,-2.7);
代码运行js特效planeShape.lineTo(-0.2, -1.3);
planeShape.lineTo(-0.2, -0.2);
var planeGeometry = new THREE.ShapeGeometry(planeShape);
// 飞机材质
var planeMaterial = new THREE.MeshPhongMaterial({color: 0x0FB4DD, side: THREE.DoubleSide, depthTest: true}); depthTest作⽤是能否透过球体看到飞机,如果是false则旋转到球体另⼀⾯也能看到飞机
添加飞机
// 添加飞机
function addPlane(item) {
if(item.anum && item.lng && item.lat) {
var plane = new THREE.Mesh(planeGeometry, planeMaterial);
// 旋转
// 定位
var position = getPosition(item.lng, item.lat, 5);
plane.position.set(position.x, position.y, position.z);
// 显⽰/隐藏
// plane.visible = false;
// 保存
planeMarkers[item.anum] = plane;
// 添加到场景
// 绘制历史轨迹
drawHistoryTrack(item.anum);
}
}
绘制轨迹(使⽤socket来获取的飞⾏轨迹经纬度坐标点)
// 时间段
var curTime = Date.parse(new Date())/1000;
var depTime = curTime - 30*60;
// 轨迹线质
var trackMaterial = new THREE.LineBasicMaterial({color : 0x1B94B1});
// 绘制历史轨迹
function drawHistoryTrack(anum) {
if(status) {
var dLength = data.length;
if(dLength>=2) {
var trackCoordArr = [];
for(var i=0; i<dLength; i++) {
if(data[i].lng && data[i].alt) {
trackCoordArr.push({lng: data[i].lng, lat: data[i].lat});
}
}
var tcaLength = trackCoordArr.length;
if(tcaLength>=2) {
var tcaHalfLength = il(tcaLength/2),
vertexArr = [];
// 这⾥只取了三个点(起点、中点、终点)
var p1 = getPosition(trackCoordArr[0].lng, trackCoordArr[0].lat, 0),
p2 = getPosition(trackCoordArr[tcaHalfLength].lng, trackCoordArr[tcaHalfLength].lat, tcaLength*0.01), p3 = getPosition(trackCoordArr[tcaLength-1].lng, trackCoordArr[tcaLength-1].lat, 0);
var trackCurve = new THREE.CatmullRomCurve3([
new THREE.Vector3(p1.x, p1.y, p1.z),
new THREE.Vector3(p2.x, p2.y, p2.z),
new THREE.Vector3(p3.x, p3.y, p3.z)
]);
var trackGeometry = new THREE.Geometry(),
verticesArr = Points(tcaLength);
trackGeometry.vertices = verticesArr;
var trackLine = new THREE.Line(trackGeometry, trackMaterial);
group.add(trackLine);
// 动画点
addLightPoint(p1, tcaLength, verticesArr);
}
}
}
});
}
如果要绘制所有点,且头尾是在球⾯上的曲线,则需要两次循环
var tcaRemainLength = tcaLength-tcaHalfLength
for(var j=0; j<tcaHalfLength; j++) { // 前⼀半
var p1 = getPosition(trackCoordArr[j].lng, trackCoordArr[j].lat, j*0.05);
vertexArr.push(new THREE.Vector3(p1.x, p1.y, p1.z));
}
for(var k=tcaRemainLength; k>0; k--) { // 后⼀半
var p2 = getPosition(trackCoordArr[tcaLength-k].lng, trackCoordArr[tcaLength-k].lat, k*0.05);
vertexArr.push(new THREE.Vector3(p2.x, p2.y, p2.z));
}
var trackCurve = new THREE.CatmullRomCurve3(vertexArr);
这个部分看看就⾏了。。
光点动画
var pointGeometry = new THREE.SphereGeometry(0.2, 20, 20);
var pointMaterial = new THREE.MeshBasicMaterial({color: 0x40E0D0});
function addLightPoint(pos, coordsNum ,verArr) {
var pointMesh = new THREE.Mesh(pointGeometry, pointMaterial);
pointMesh.position.set(pos.x, pos.y, pos.z);
group.add(pointMesh);
var index = 0;
function pointAnimate() {
index++;
if(index>coordsNum) {
index = 0;
}
pointMesh.position.set(verArr[index].x, verArr[index].y, verArr[index].z);
requestAnimationFrame(pointAnimate);
}
pointAnimate();
}
这个点使⽤的是sphere,,当然也可以⽤顶点来实现,如下
var geometry = new THREE.Geometry();
geometry.vertices.push(new THREE.Vector3(0, 0, 0))
var material = new THREE.PointsMaterial({size: 1, vertexColors: THREE.VertexColors, opacity: 0.75, sizeAttenuation: true, transparent: true}); var point = new THREE.Points(geometry, material);
point.position.set(x, y, z);
group.add(point);
另外不想⽤光点动画的话,也可以⽤线动画,实现原理是不断更新顶点坐标,如下
var curveGeometry = new THREE.Geometry();
var curveData = new THREE.CatmullRomCurve3(verArr.slice(0, 10));
curveGeometry.vertices = Points(10);
var curveMaterial = new THREE.LineBasicMaterial({color: 0x40E0D0});
var curveLine = new THREE.Line(curveGeometry, curveMaterial);
group.add(curveLine);
var index = 0;
function lineAnimate() {
index++;
if(index>coordsNum-10) {
index = 0;
}
var offsetData = verArr.slice(index, 10+index);
if(offsetData.length > 0) {
curveData = new THREE.CatmullRomCurve3(offsetData);
}
requestAnimationFrame(lineAnimate);
}
lineAnimate();
最后就是布置场景和事件了
// 初始化
function init() {
container = ElementById('zh_globe_container');
scene = new THREE.Scene();
var bgTexture = new THREE.TextureLoader().load("images/textures/starfield.jpg");
scene.background = bgTexture;
camera = new THREE.PerspectiveCamera(50, winWth/winHgt, 1, 2000);
camera.up.x = 0;
camera.up.y = 1;
camera.up.z = 0;
camera.position.x = 0;
camera.position.y = 0;
camera.position.z = 400;
camera.lookAt(0,0,0);
scene.add(group);
// 地球
globe();
// 飞机
plane();
// 星点
stars();
// 半球光
lights();
// 渲染器
renderer = new THREE.WebGLRenderer({antialias: true, preserveDrawingBuffer: true}); renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(winWth, winHgt);
container.appendChild(renderer.domElement);
// 盘旋控制
var orbitControl = new THREE.OrbitControls(camera, renderer.domElement);
orbitControl.minDistrance = 20;
orbitControl.maxDistrance = 50;
orbitControl.maxPolarAngle = Math.PI/2;
// 性能测试
stats = new Stats();
container.appendChild(stats.dom);
// resize事件
window.addEventListener('resize', onWindowResize, false);
}
// 窗⼝⼤⼩改变
function onWindowResize() {
camera.aspect = window.innerWidth/window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
// 渲染
function render() {
}
// 动画
function animate() {
requestAnimationFrame(animate);
render();
stats.update();
}
init();
animate();
完整代码:
var log = console.log.bind(console);
var globeObj = (function() {
'use strict';
// 判断浏览器是否⽀持webgl
if(!Detector.webgl) Detector.addGetWebGLMessage();
var container, stats;
var camera, scene, renderer;
var group;
var mouseX = 0, mouseY = 0;
var winWth = window.innerWidth, winHgt = window.innerHeight;
// 获取position
function getPosition(lng, lat, alt) {
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论