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

 

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐