JS實現環繞地球飛行的3D飛行線動畫效果(JS+HTML)

1.項目介紹

JS+HTML實現繞地球飛行的3D飛行線動畫效果,且3D地球可以隨意拖動和滑動縮放,畫面中心是藍色地球,地球表面上的兩點連線之間有光電隨機出現沿着拋物線軌跡3D飛行,可使用較好的瀏覽器打開,如microsoft edge打開,效果如下圖所示:

 

2.html源碼如下所示

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "//www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="//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才有效果。

 整個項目源碼下載地址://download.csdn.net/download/xipengbozai/16595841