Threejs实现滴滴官网首页地球动画功能

偶然翻滴滴官网看到首页下翻第六栏(大概)有个绚丽的地球的三维动画,试着用there.js实现了下,基本实现了动画效果,不过还是有些问题;这个动画看似简单,但也用到好的绘制方法和计算,这里先写一下主要功能的实现;

先看示例:http://39.106.166.212:8080/webgl/t4(由于是写dome的一个项目,内容较多没做优化,第一次加载会会比较慢,需多等待几秒)

(lice这个截图工具也是很不好用,每次都截到一半 ╮(╯﹏╰)╭)

一、 3d绘制场景的构建

绘制一个3d程序首先需要添加 渲染器,场景,照相机 这些元素,这里补充一个灯光;

1、渲染器

首先创建一个渲染器,参数为页面中的canvas元素,

渲染器的作用就是把3d场景的内容结合照相机渲染到页面中,

最后将画布背景设为白色。

const renderer = new Three.WebGLRenderer({canvas: this.$refs.thr});
renderer.setClearColor(0x000000);

2、场景

场景顾名思义,就是添加一个你发挥(绘制)的场地,后面所有绘制的元素都要添加到场景中;

cosnt scene = new Three.Scene();

3、照相机

照相机就像人的视觉或说从什么角度去看场景,看场景的位置和视线的方向决定了渲染到页面的内容。故一般需要设置两个参数相机位置position、视线方向lookAt,,在webgl其实是需要三组参数视点,观察点,和上方向。thresjs中好像是默认Y轴为上方向了,这里使用透视相机。

const camera = new THREE.PerspectiveCamera(45, 500 / 500, 1, 1500);
camera.position.set(100, 100, 1000);
camera.lookAt(new THREE.Vector3(0, 0, 0));
scene.add(this.camera);

 4、灯光

这里使用THREE.HemisphereLight光,可以更加贴近自然的户外光照效;

let light = new THREE.HemisphereLight(0xffffff);
light.position.set(0, 0, 200);
scene.add(light)

以上我们基本的绘制要素已添加完成,下面开始绘制各个几何体内容;

几何体的绘制有三部:创建几何体,创建材料,添加网格模型;

二、地球的绘制

threejs中提供了球体的绘制,我们只需创建一个球体,材料使用纹理贴图方式添加地图;

贴图图片资源是我从官网上找的

const geometry = new THREE.SphereGeometry(this.radius, 100, 100); // 球体
const textureLoader = new THREE.TextureLoader(); // 创建纹理贴图
const texture = textureLoader.load(require("@/assets/map.jpg"),texture => {
 let material = new THREE.MeshLambertMaterial({map: texture,transparent: true,});
 let mesh = new THREE.Mesh(geometry, material);
 scene.add(mesh);
});

由于图片加载是异步的 ,这里需等图片加载完成后才能创建材质;

这里我们就创建好了一个地球模型,接着还要让其转动起来;(中间为xyz坐标轴)

threejs提供了几何体的基本3d变换,直接使用rotateY(angleChange)根据时间设置其绕y轴(绿色轴)旋转角度即可;

三、球面坐标点的绘制

1、在绘制球面位置点时,需先前先看下球坐标系,确定点的位置,webgl中坐标方向与下图不一致,但是对点的表示方法是一致的;

球面上任意点可以用r,θ,φ表示,也可通过以下公式转化到直角坐标系中

x=rsinθcosφ.
y=rsinθsinφ.
z=rcosθ

但实际中地球位置我们一般也会使用经纬度表示。。。 下面写个经纬度转坐标的方法。

threejs提供了THREE.Math.degToRad方法可以将经纬度转化为θ,φ,转化方法如下,这里为了方便后面使用,我直接返回一个3维向量;

getPosition(longitude, latitude, radius = this.radius) {  // 经度,纬度转换为坐标
 let lg = THREE.Math.degToRad(longitude);
 let lt = THREE.Math.degToRad(latitude);  // 获取x,y,z坐标
 let temp = radius * Math.cos(lt);
 let x = temp * Math.sin(lg);
 let y = radius * Math.sin(lt);
 let z = temp * Math.cos(lg);
 return new THREE.Vector3(x, y, z);
}

2、知道了位置的表示方法后开始绘制表示位置的点
根据示例位置点的由点和一个圆环组成,我们先绘制一个二维平面内的点和圆弧,在通过设置其位置和旋转方式移动到目标坐标位置点;

(这里也可以绘制几何小球体来模拟)

(1)点的绘制

THREE.Shape是用来绘制二维平面内的形状的,设置其形状为圆弧,即可实现一个原点;

let shapePoint = new THREE.Shape();
shapePoint.absarc(0, 0, r - 4, 0, 2 * Math.PI, false);
let arcGeometry = new THREE.ShapeGeometry(shapePoint);
let arcMaterial = new THREE.MeshBasicMaterial({ color: 0x008080 });
let point = new THREE.Mesh(arcGeometry, arcMaterial);

(2)圆弧的绘制

let geometryLine = new THREE.Geometry();
let arc = new THREE.ArcCurve(0, 0, r, 0, 2 * Math.PI);
let points = arc.getPoints(40);
geometryLine.setFromPoints(points);
let LineMateri = new THREE.LineBasicMaterial({ color: 0x20b2aa });
let line = new THREE.Line(geometryLine, LineMateri);

(3)位置的设置

position.set(pos.x, pos.y, pos.z);

(4)二维图形旋转至球面
THREE.Spherical()方法 ,可将坐标点转化为坐标点转化回球坐标系的偏移角度;

let spherical = new THREE.Spherical();
spherical.setFromCartesianCoords(pos.x, pos.y, pos.z);

设置位置点旋转

Point.rotateX(spherical.phi - Math.PI / 2);
Point.rotateY(spherical.theta);

这里为什么要 - Math.PI / 2 是因为开始我们绘制时,平面是垂直于y轴的平面,参考下面这幅图;

四、接着绘制链接球面两点间的连线

连接两点的曲线需在球面上方,

两点间可以坐出无数条曲线,那么如何确定曲线,我们需自己再选择合适的参数来确定;

首先想的是二阶贝塞尔曲线,取两点的中点为控制点,但如果链接两点刚好位于球面的两个对称端点(两点间连线为直径)时,控制点需在无穷远处;

故考虑使用三阶贝塞尔曲线,连接球面两点和球心,三点确定的一个平面如下图,

链接v1 v1,取中点c,链接oc,做一条射线,在射线取一点p,链接v1p,v2p,在v1,v2上取两点作为控制点;

求两点的中点

getVCenter(v1, v2) {
 let v = v1.add(v2);
 return v.divideScalar(2);
}

获取两点间指定比例位置坐标

getLenVcetor(v1, v2, len) {
 let v1v2Len = v1.distanceTo(v2);
 return v1.lerp(v2, len / v1v2Len);
}

获取贝塞尔控制点

getBezierPoint(v0, v3) {
 let angle = (v0.angleTo(v3) * 180) / Math.PI; // 0 ~ Math.PI  // 计算向量夹角
 let aLen = angle * 2.5,
  hLen = angle * angle * 50;
 let p0 = new THREE.Vector3(0, 0, 0);  // 法线向量
 let rayLine = new THREE.Ray(p0, this.getVCenter(v0.clone(), v3.clone()));  // 顶点坐标
 let vtop = rayLine.at(hLen / rayLine.at(1).distanceTo(p0), vtop); // 位置
 // 控制点坐标
 let v1 = this.getLenVcetor(v0.clone(), vtop, aLen);
 let v2 = this.getLenVcetor(v3.clone(), vtop, aLen);
 return {
 v1: v1,
 v2: v2
 };
},

绘制三次贝塞尔曲线

drawLine(longitude, latitude, longitude2, latitude2) {
 let geometry = new THREE.Geometry(); //声明一个几何体对象Geometry
 let v0 = this.getPosition(longitude, latitude, this.radius);
 let v3 = this.getPosition(longitude2, latitude2, this.radius);
 let { v1, v2 } = this.getBezierPoint(v0, v3); // 三维二次贝赛尔曲线
 let curve = new THREE.CubicBezierCurve3(v0, v1, v2, v3);
 let curvePoints = curve.getPoints(100);
 geometry.setFromPoints(curvePoints);
 let material = new THREE.LineBasicMaterial({
 color: 0xff7e41
 });
 let line = new THREE.Line(geometry, material);
 this.group.add(line);
 this.sport(curvePoints);
},

五、小球的运动轨迹

小球的动画我们使用three的帧动画,路径可以直接使用上一步中的曲线;

1、绘制小球

drawSportPoint(position, name) {
 let box = new THREE.SphereGeometry(6, 6, 6);
 let material = new THREE.MeshLambertMaterial({
 color: 0x00bfff
 });  //材质对象
 let mesh = new THREE.Mesh(box, material);
 mesh.name = name;
 mesh.position.set(position.x, position.y, position.z);
 this.groupBall.add(mesh);
 this.group.add(this.groupBall);
 return mesh;
}

2、让小球动起来

sport(curvePoints, index) {
 const Ball = this.drawSportPoint(curvePoints[0]);
 let arr = Array.from(Array(101), (v, k) => k);  // 生成一个时间序列
 let times = new Float32Array(arr);
 let posArr = [];
 curvePoints.forEach(elem => {
 posArr.push(elem.x, elem.y, elem.z);
 });  // 创建一个和时间序列相对应的位置坐标系列
 let values = new Float32Array(posArr); // 创建一个帧动画的关键帧数据,曲线上的位置序列对应一个时间序列
 let posTrack = new THREE.KeyframeTrack("Ball.position", times, values);
 let duration = 101;
 let clip = new THREE.AnimationClip("default", duration, [posTrack]);
 this.mixer = new THREE.AnimationMixer(Ball);
 let AnimationAction = this.mixer.clipAction(clip);
 AnimationAction.timeScale = 20;
 AnimationAction.play();
}

3、在requestAnimationFrame中添加触发动画

this.mixer.update(this.clock.getDelta());

到此这篇关于Threejs实现滴滴官网首页地球动画的文章就介绍到这了,更多相关Threejs滴滴官网首页地球动画内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 使用3D引擎threeJS实现星空粒子移动效果

    three.js是JavaScript编写的WebGL第三方库.提供了非常多的3D显示功能.Three.js 是一款运行在浏览器中的 3D 引擎,你可以用它创建各种三维场景,包括了摄影机.光影.材质等各种对象. 下载地址: http://threejs.org/ 首先创建一个HTML文件,引入three.js引擎包. <!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <titl

  • Threejs实现滴滴官网首页地球动画功能

    偶然翻滴滴官网看到首页下翻第六栏(大概)有个绚丽的地球的三维动画,试着用there.js实现了下,基本实现了动画效果,不过还是有些问题:这个动画看似简单,但也用到好的绘制方法和计算,这里先写一下主要功能的实现: 先看示例:http://39.106.166.212:8080/webgl/t4(由于是写dome的一个项目,内容较多没做优化,第一次加载会会比较慢,需多等待几秒) (lice这个截图工具也是很不好用,每次都截到一半 ╮(╯﹏╰)╭) 一. 3d绘制场景的构建 绘制一个3d程序首先需要添

  • 利用vue3+threejs仿iView官网大波浪特效实例

    目录 前言 一.效果图 二.代码 三.背景图片素材 总结 前言 Threejs可以理解为是一个web端三维引擎(渲染模型,数据可视化),如果有接触过UnralEngine 4(虚幻四)等游戏引擎的,应该很容易理解在一个三维场景必备的每一个部件(场景,渲染器,网格模型,材质,光源,色相机).好的,基础知识咱们先跳过,直接上实现的过程 一.效果图 先上最终效果图: 具体效果可参考iview官方界面iView - 一套高质量的UI组件库 大波浪效果,使用的是three.js的官方例子,需要先安装thr

  • jQuery + html + css 实现王者荣耀官网首页效果 附实例代码

    访问地址 reset.css /** * Eric Meyer's Reset CSS v2.0 (http://meyerweb.com/eric/tools/css/reset/) * http://cssreset.com */ html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, cod

  • Vue实现类似Spring官网图片滑动效果方法

    先来看一下Spring官网首页的一个图片滑动显示效果 可以看到, 随着鼠标的滑动,绿色图片和灰色图片可以无缝的在鼠标俩两边切换显示. 显示这样的效果其实很简单,利用固定定位保证两张图片在同一位置下, 我们可以将灰色图片当做背景层图片,然后根据获取到的实时X轴坐标, 动态改变绿色图片的宽度, 隐藏超出X轴坐标的部分, 就可以达到这样的效果, 简单来说, 这效果就是动态改变上层图片的宽度. 实现效果: 我这边选择了两张同样大小的KDA卡莎的图片, 将金色图作为背景图,暗黑图作为左侧图, 用了Vue的

  • Vue官网todoMVC示例代码

    这个示例是模仿官网示例样式和功能用我自己的方式写的,基本上没有看官网的源码,只参考自定义指令.让我们一步步来探讨一下.官网demo 要实现的功能 单条添加todo 单条删除todo 双击编辑todo 单条todo已完成相应样式状态改变 全部todo是已完成相应样式状态改变 清除全部已完成todos 待办todos数量显示 所有todos,已完成todos,未完成todos筛选 单条添加todo <input type="text" class="todos_add&qu

  • js实现兼容性好的微软官网导航下拉菜单效果

    本文实例讲述了js实现兼容性好的微软官网导航下拉菜单效果.分享给大家供大家参考.具体如下: 这是一款微软官网导航菜单,兼容好的下拉菜单,微软官网导航效果,在IE6下没有动画效果,顺便也把IE6的效果给加上,兼容IE6.现在微软的官方网站正在使用,我觉得非常不错. 运行效果截图如下: 在线演示地址如下: http://demo.jb51.net/js/2015/js-microsoft-web-nav-menu-codes/ 具体代码如下: <!DOCTYPE html PUBLIC "-/

  • JavaScript仿小米商城官网完整页面实现流程

    目录 一.首页的制作 1.下载APP的制作 2.导航栏的制作 3.轮播图的制作 二.登录.注册页面的制作 1.盒子布局 2.复选框样式更改 三.页面跳转 不知不觉学习前端已经快4个月啦,之前没学JavaScript之前做的项目都只能看不能玩,小米官网这个页面算上写出的第一个相对完整一点的项目,虽然需要进步的地方还有很多,但是未来可期! 本篇博客主要是针对在书写这个项目时遇到的一些问题,找出对应的方法,记录一下自己在写这个项目时踩过的坑. 一.首页的制作 首页的主要效果有如下几个: 下载APP.购

  • js仿小米官网图片轮播特效

    小米官网给我的感觉是大气.干净.很多特效的加入让人觉得耳目一新,big满满. 看到他们首页的轮播图实现挺有意思,于是自己模仿着写了一个. 大致的感觉出来了,贴个图先: 通过前端神器chrom的F12观察小米官网的html代码,不难看到他们使用5个div包裹图片并使用了定位通过z-index来控制div层级,通过控制每个div的opacity属性和display属性进行元素的显示.隐藏. 截图如下(红框内的opacity属性): 好的,实现的手段知道了,那么页面布局先搞出来. <!DOCTYPE

  • jQuery实现级联菜单效果(仿淘宝首页菜单动画)

    相信初学HTM+DIV+CSSl的同学们肯定也想做出淘宝网首页的菜单动画吧.今天我们就带大家体会一下级联菜单的显示.小编我只是实现了简单地效果,不过总体来说原理是一样的哦,那么先让大家看看效果图吧. 那么要实现这个效果我们当然要使用到的是jQuery,那么我就开始讲解怎么做的了,先上html和css的代码 复制代码 代码如下: <!DOCTYPE html> <html> <head> <title>menu.html</title> <m

  • 详解如何使用koa实现socket.io官网的例子

    socket.io官网中使用express实现了一个最简单的IM即时聊天,今天我们使用koa来实现一下 ### 框架准备 1.确保你本地已经安装好了nodejs和npm,使用koa要求node版本>7.6 2.在你需要的位置新建一个文件夹(官网的简单命名为chat-example) 3.进入项目目录,创建package.json文件: { "name": "socket-chat-example", "version": "0.0

随机推荐