1.项目介绍
JS+HTML实现绕地球飞行的3D飞行线动画效果,且3D地球可以随意拖动和滑动缩放,画面中心是蓝色地球,地球表面上的两点连线之间有光电随机出现沿着抛物线轨迹3D飞行,可使用较好的浏览器打开,如microsoft edge打开,效果如下图所示:
2.html源码如下所示
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Threejs 实现环绕地球飞行的3D飞行线</title>
<style>
html,
body {
width: 100%;
height: 100%;
margin: 0;
overflow: hidden;
}
</style>
</head>
<body>
<div id="container"></div>
<script src="js/three.103.min.js"></script>
<script src="js/OrbitControls.js"></script>
<script id="vertex-shader" type="x-shader/x-vertex">
varying vec3 vPosition;
varying vec4 vColor;
void main() {
vPosition = position;
vColor = vec4(color, 1.0);
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
uniform vec3 targetPos; // 目标位置
uniform float vLength; // 距离
uniform float time;
varying vec3 vPosition;
varying vec4 vColor;
void main() {
float dist = distance(vPosition, targetPos);
vec4 color = vec4(vColor);
float p = dist/vLength * 6.0 + time * 1.0;
if (p < 3.1415926/2.0){
p = 0.0;
}
if (p > 3.1415926*2.0){
p = 0.0;
}
float a = sin(p);
color.a = a;
gl_FragColor = color;
}
</script>
<script>
var container = document.getElementById('container');
var scene, camera, renderer;
var globeMesh = undefined;
var groupDots, groupLines, groupAnimDots;
var animateDots = []; // 小球运动点轨迹
var controls;
// 配置参数
var params = {
pointsLength: 20, // 点数
globeRadius: 100 // 地球半径
}
var vertexShader = document.getElementById('vertex-shader').innerHTML;
var fragmentShader = document.getElementById('fragment-shader').innerHTML;
const PI2 = Math.PI * 2; // 弧度的取值为0-2π
var timer = -PI2;
// 预制件
var Prefab = {
Sphere: (function() {
var instance;
return function(clone = true) {
if (!instance) {
instance = new createSphere();
}
if (clone) return instance.clone();
else return instance;
}
})()
}
init();
update();
function init() {
// 场景
scene = new THREE.Scene();
groupDots = new THREE.Group();
groupLines = new THREE.Group();
groupAnimDots = new THREE.Group();
scene.add(groupDots, groupLines, groupAnimDots);
// 相机
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.x = -200;
camera.position.y = 200;
camera.position.z = -200;
camera.lookAt(scene.position);
// 渲染器
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
container.appendChild(renderer.domElement);
// 光
var light = new THREE.HemisphereLight(0xffffff, 0xffffff, 1);
scene.add(light);
// 控制器
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.minDistance = 200;
controls.maxDistance = 400;
controls.rotateSpeed = 0.5;
controls.enableDamping = true;
controls.enablePan = false;
initGlobe();
initLines();
window.addEventListener('resize', onWindowResize, false);
}
function update() {
requestAnimationFrame(update);
renderer.render(scene, camera);
timer += 0.02;
if (timer > Math.PI * 1.5) {
timer = -Math.PI * 1.5;
}
groupLines.children.forEach(function(item) {
item.material.uniforms.time.value = timer;
});
// console.log(globeMesh.material.map.offset.x)
controls.update();
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function initGlobe() {
// 地球
var geo = new THREE.SphereGeometry(params.globeRadius, 32, 32);
var texture = new THREE.TextureLoader().load('img/earth.jpg');
texture.minFilter = THREE.LinearFilter;
var material = new THREE.MeshPhongMaterial({
map: texture,
// wireframe: true
});
globeMesh = new THREE.Mesh(geo, material);
scene.add(globeMesh);
}
// 地球飞线和点
function initLines() {
// 球面随机点
for (let i = 0; i < params.pointsLength; i++) {
addPoints(groupDots, params.globeRadius);
}
// 曲线
groupDots.children.forEach(function(elem, index) {
// 从第一个点到其它点
if (elem != groupDots.children[0]) {
var line = addLines(groupDots.children[index - 1].position, elem.position);
animateDots.push(line.curve.getPoints(100));
}
});
}
// 3d球面取点
function getEarthPos(radius, a, b) {
var x = radius * Math.sin(a) * Math.cos(b);
var y = radius * Math.sin(a) * Math.sin(b);
var z = radius * Math.cos(a);
return {
x, y, z
};
}
// 添加随机点
function addPoints(group, radius) {
var mesh = new Prefab.Sphere();
var pos = getEarthPos(radius, PI2 * Math.random(), PI2 * Math.random());
mesh.position.set(pos.x, pos.y, pos.z);
group.add(mesh);
}
function addLines(v0, v3) {
var angle = v0.angleTo(v3);
var vtop = v0.clone().add(v3);
vtop = vtop.normalize().multiplyScalar(params.globeRadius);
var n;
if (angle <= 1) {
n = params.globeRadius / 5 * angle;
} else if (angle > 1 && angle < 2) {
n = params.globeRadius / 5 * Math.pow(angle, 2);
} else {
n = params.globeRadius / 5 * Math.pow(angle, 1.5);
}
var v1 = v0.clone().add(vtop).normalize().multiplyScalar(params.globeRadius + n);
var v2 = v3.clone().add(vtop).normalize().multiplyScalar(params.globeRadius + n);
// addLineHelper(globeMesh.position, v1);
// addLineHelper(globeMesh.position, v2);
// addLineHelper(globeMesh.position, vtop)
// 三维三次贝塞尔曲线(v0起点,v1第一个控制点,v2第二个控制点,v3终点)
var curve = new THREE.CubicBezierCurve3(v0, v1, v2, v3);
var points = curve.getPoints(50);
var vertices = [],
colors = [];
points.forEach(function(item, index) {
vertices.push(item.x, item.y, item.z);
colors.push(index / points.length, index / points.length, index / points.length);
});
var geometry = new THREE.BufferGeometry();
geometry.attributes.position = new THREE.Float32BufferAttribute(vertices, 3)
var material = createLineMaterial(v0, v3);
var lineMesh = new THREE.Line(geometry, material);
groupLines.add(lineMesh);
return {
curve: curve,
lineMesh: lineMesh
};
}
function createLineMaterial(myPos, targetPos) {
var uniforms = {
targetPos: {
value: targetPos
},
vLength: {
value: myPos.distanceTo(targetPos)
},
time: {
value: timer
}
};
var material = new THREE.ShaderMaterial({
uniforms: uniforms,
vertexShader: vertexShader,
fragmentShader: fragmentShader,
transparent: true,
vertexColors: THREE.VertexColors
});
return material;
}
function createSphere() {
var geometry = new THREE.SphereBufferGeometry(1);
var material = new THREE.MeshBasicMaterial({
color: 0x00ffff
});
var mesh = new THREE.Mesh(geometry, material);
return mesh;
}
function addPointHelper(pos) {
var mesh = new Prefab.Sphere();
mesh.material = new THREE.MeshBasicMaterial({
color: 0xff0000
});
mesh.position.copy(pos);
scene.add(mesh);
}
function addLineHelper(pos1, pos2) {
var material = new THREE.LineBasicMaterial({
color: 0x0000ff
});
var geometry = new THREE.Geometry();
geometry.vertices.push(pos1, pos2);
var line = new THREE.Line(geometry, material);
scene.add(line);
}
</script>
</body>
</html>
3.JS部分代码由于代码量较大这里就不黏贴了
4.文件目录如下
5.浏览器要支持HTML5与CSS3才有效果。
整个项目源码下载地址:https://download.csdn.net/download/xipengbozai/16595841
所有评论(0)