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