threejs地球、星空、世界轮廓绘制、飞线、坐标涟漪 、旋转动画(上篇)
废话不多说,老规矩先让干货。
3D 地球成果展示
github仓库地址:https://github.com/RainManGO/3d-earth
npm:https://www.npmjs.com/package/3d-earth
支持vue/react/html 嵌入简单。
是不是有点干,咽不下去了。
前言
头一阵子B站,抖音都被 陶大宇大哥的倒转地球刷屏了,终于热度下去了,不用倒转头七了。
真的和地球扛上了,公司的大屏项目需要科技感的地球、飞线图。
为什么不用echarts
公司数据分类项目和大屏项目使用echart 比较多,对echart使用不能说是手到擒来,也是比较熟练地。
个人比较倾向于它,最重要的配置型,找到个案例复制粘贴完事。
于是和设计商量下做了一版,最终还是被客户否决了。
原因如下:
- 加载慢
- 不漂亮
饿,echarts 灵活度没有那么高,只能想别的办法了,最后定位ThreeJs。ThreeJs需要一定的计算机视图知识,从来没有学过,必定是场恶战。
实现过程
做完了,回头看来,一些东西看似简单,还是需要细细品味分解。把总体过程分解一一说来。因为涉及代码过多,不全部贴出来说明,具体查看github 仓库源码。直说结构过程。
目标设计样子:
实现步骤分解:
- ThreeJS环境初始化
- 星空背景
- 添加带纹理的地球
- 世界地图轮廓边界绘制
- 地球光晕
- 添加地球云层
- 城市位置标注和涟漪效果
- 添加飞线B样条
- 地球自转和镜头缩放动画
初始化
初始化列表:
- webgl渲染器(WebGLRenderer)和css2d 渲染器(CSS2DRenderer)
- 透视投影相机 (PerspectiveCamera)
- 场景(scene)
- 轨道控制器(OrbitControls)
- 多种灯光
渲染器初始化
这个库和外界需要一个接口,可以通过id选择器拿到dom节点,从而获取到宽高。轨道控制器需要一个2D 渲染器所以一起初始化。
this.renderer = initRender(this.width, this.height);this.renderer2d = initRender2D(this.width, this.height);
WebGLRenderer初始化
export const initRender = (width:number,height:number)=>{let renderer = new WebGLRenderer({antialias: true,alpha: true});renderer.shadowMap.enabled = false;renderer.shadowMap.type = PCFShadowMap;renderer.setSize(width,height)return renderer
}
CSS2DRenderer初始化
export const initRender2D = (width:number,height:number)=>{const renderer2d = new CSS2DRenderer();renderer2d.setSize(width,height)renderer2d.domElement.style.position = "absolute";renderer2d.domElement.style.top = "0px";renderer2d.domElement.tabIndex = 0;renderer2d.domElement.className = "coreInnerRenderer2d";return renderer2d
}
相机和场景初始化没有什么特别的就不多说了,见代码。
轨道控制器初始化
注意点是用的2d 渲染器
const orbitControl = new OrbitControls(this.camera,this.renderer2d.domElement);orbitControl.minZoom = controlConfig.minZoom;orbitControl.maxZoom = controlConfig.maxZoom;orbitControl.minPolarAngle = controlConfig.minPolarAngle;orbitControl.maxPolarAngle = controlConfig.maxPolarAngle;orbitControl.update();
灯光添加
灯光有多种,主要是:
- 平行光
- 点光
- 半球光
地球的贴图是这种发光材质,需要光照来打效果。
export const initLight = (scene:Scene)=>{/*** 光源设置*/// 平行光var directionalLight = new DirectionalLight(0x80b5ff, 1);directionalLight.position.set(-250, 250, 100);scene.add(directionalLight);// 点光var pointLight = new PointLight(0x80d4ff, 1);pointLight.position.set(-250, 250, 100);scene.add(pointLight);// 半球光var hemisphereLight = new HemisphereLight(0xffffff, 0x3d6399, 1);hemisphereLight.position.set(-250, 250, 100);scene.add(hemisphereLight);//环境光var ambient = new AmbientLight(0x002bff, 0.8);scene.add(ambient);
}
星空背景
星空背景主要是点光源,主要思路是随机位置和颜色大小等
效果如下:
代码:
export const starBackground = () => {const positions = [];const colors = [];const geometry = new BufferGeometry();for (var i = 0; i < 10000; i++) {var vertex = new Vector3();vertex.x = Math.random() * 2 - 1;vertex.y = Math.random() * 2 - 1;vertex.z = Math.random() * 2 - 1;positions.push(vertex.x, vertex.y, vertex.z);var color = new Color();color.setHSL(Math.random() * 0.2 + 0.5, 0.55, Math.random() * 0.25 + 0.55);colors.push(color.r, color.g, color.b);}geometry.setAttribute("position", new Float32BufferAttribute(positions, 3));geometry.setAttribute("color", new Float32BufferAttribute(colors, 3));var textureLoader = new TextureLoader();var texture = textureLoader.load(starPng); //加载纹理贴图var starsMaterial = new PointsMaterial({map: texture,size: 1,transparent: true,opacity: 1,vertexColors: true, //true:且该几何体的colors属性有值,则该粒子会舍弃第一个属性--color,而应用该几何体的colors属性的颜色blending: AdditiveBlending,sizeAttenuation: true,});let stars = new Points(geometry, starsMaterial);stars.scale.set(300, 300, 300);return stars
};
添加3d地球对象
因为地球元素比较多,且需要转动,所以是一个3dobject对象,添加多个mesh。
var object3D = new Object3D();let earthMesh = createEarthImageMesh(earthRadius);
创建一个地球:
export const createEarthImageMesh = (radius: number) => {// TextureLoader创建一个纹理加载器对象,可以加载图片作为纹理贴图var textureLoader = new TextureLoader();//加载纹理贴图var texture = textureLoader.load(earthTexture);//创建一个球体几何对象var geometry = new SphereGeometry(radius, 96, 96);//材质对象Material// MeshLambertMaterial MeshBasicMaterialvar material = new MeshLambertMaterial({map: texture, //设置地球0颜色贴图map});var mesh = new Mesh(geometry, material); //网格模型对象Meshreturn mesh;
};
现在是这个样子了,光秃秃的缺少了点什么:
世界地图轮廓边界绘制
刚才光秃秃的地球,需要加上点轮廓。
threejs 通过 LineLoop 和世界点数据,可以绘制多边形。利用这个原理绘制国家边界。
LineLoop和Line功能一样,区别在于首尾顶点相连,轮廓闭合,但是绘制条数太多会用性能问题,LineSegments 是一条线绘制,提高性能,需要复制顶点。
把计算好的数据,放到data里。
然后使用LineSegments绘出来,代码如下:
/** @Author: ZY* @Date: 2021-12-31 15:47:59* @LastEditors: ZY* @LastEditTime: 2022-01-05 10:15:57* @FilePath: /3d-earth/lib/src/earth/countryPolygon.ts* @Description: 世界轮廓*/
import {BufferGeometry,BufferAttribute,LineBasicMaterial,LineSegments
} from "three";
//引入国家边界数据
import pointArr from "../data/world";
import { countryLineColor } from "../config/index";
// R:球面半径
function countryLine(R:number) {var geometry = new BufferGeometry(); //创建一个Buffer类型几何体对象//类型数组创建顶点数据var vertices = new Float32Array(pointArr);// 创建属性缓冲区对象var attribute = new BufferAttribute(vertices, 3); //3个为一组,表示一个顶点的xyz坐标// 设置几何体attributes属性的位置属性geometry.attributes.position = attribute;// 线条渲染几何体顶点数据var material = new LineBasicMaterial({color: countryLineColor, //线条颜色}); //材质对象var line = new LineSegments(geometry, material); //间隔绘制直线line.scale.set(R, R, R); //lineData.js对应球面半径是1,需要缩放R倍return line;
}export { countryLine };
地球光晕
地球光晕其实是一个精灵贴图,这里放了两层,下面放一张看下。
大气层光晕代码:
/** @Author: ZY* @Date: 2021-12-31 16:40:30* @LastEditors: ZY* @LastEditTime: 2022-01-05 14:53:18* @FilePath: /3d-earth/lib/src/earth/glow.ts* @Description: 大气层光环效果*/import { TextureLoader, SpriteMaterial,Sprite} from "three";
export const earthGlow = (radius:number,img:any,scale:number) =>{// TextureLoader创建一个纹理加载器对象,可以加载图片作为纹理贴图var textureLoader = new TextureLoader();var texture = textureLoader.load(img); //加载纹理贴图// 创建精灵材质对象SpriteMaterialvar spriteMaterial = new SpriteMaterial({map: texture, //设置精灵纹理贴图transparent: true, //开启透明// opacity: 0.5,//可以通过透明度整体调节光圈});// 创建表示地球光圈的精灵模型var sprite = new Sprite(spriteMaterial);sprite.scale.set(radius * scale, radius * scale, 1); //适当缩放精灵return sprite
};
添加地球云层
云层效果不是一个精灵,它是相当于在地球上又套了一个圆球,半径比地球大一点。
云层图:
添加之后的效果:
还有飞线、动画和涟漪效果本篇内容过长,下篇奉上。
【星宇大前端】公众号,专注于技术,爱好造轮子,绝对干货,需要喝着茶看,不然咽不下去。
threejs地球、星空、世界轮廓绘制、飞线、坐标涟漪 、旋转动画(上篇)相关推荐
- canvas绘制飞线效果
在我们做的可视化大屏项目中,经常会遇到飞线的效果. 在我们的大屏编辑器中,可以通过拖拽+配置参数的方式很快就能够实现.下面是我们使用大屏编辑器实现的一个项目效果: 中间地图就有飞线的效果. 抛开编辑器 ...
- THREE.JS 绘制飞线 攻击线 迁移线 拓扑图动画线条等
THREE.JS 绘制飞线 攻击线 迁移线 拓扑图动画线条等 在THREE中如何绘制飞线:使用的是Points+Shader封装的一个飞线方法:可以用于攻击线路,指向效果等:显卡GT730 6000根 ...
- html怎么绘制飞线,绘制飞线,echarts迁徙图原理
其实是在元素上绘制了一条线,然后利用canvas 的createLinearGradient函数不断移动线段的样式位置来实现. 因此首先绘制线段 ctx.beginPath(); ctx.moveTo ...
- 如何用css绘制一个五角星并添加旋转动画
关于三角形的绘制,大家已经贡献过诸如将五角星切割成三个三角形来绘制等的更加标准简洁的画法,这篇文章权当抛砖引玉,为大家贡献一些不一样的思路吧,当然这个五角星的完成度也不是特别完美,有任何意见也欢迎大佬 ...
- mapbox-gl添加threejs飞线
文章目录 前言 飞线实现 1 初始化地图并加载three图层 2 绘制飞线几何体 将几何体正确定位在mapbox上 正确操作BufferGeometry几何体 3 tween实现动画 全部代码 总结 ...
- 百度地图可视化之实现飞线动画
此文章最终实现的效果如下图: 使用mapv和mapvgl两个框架来实现百度地图的可视化. Mapv 是一款地理信息可视化开源库,可以用来展示大量地理信息数据,点.线.面的数据,每种数据也有不 ...
- shader飞线改进版
项目github地址:https://github.com/ecojust/flyline 前面写过一个飞线(基于THREE.Line进行的颜色变化),只是简单地将可视区片元颜色的alpha通道值设为 ...
- d3.js-V3制作简单的飞线图
d3.js制作简单的飞线图 简介 期末的一个小作业,放上来分享一下.若有不懂的地方欢迎在评论区提问~ 最终效果图: 使用工具 d3.js (V3版本) 步骤简介 准备好数据. 绘制一个中国地图. 绘制 ...
- echarts飞线图
简介 在可视化大屏中碰到要绘制飞线图的需求,采用Echarts来实现,但是Echarts的世界地图数据会缺失部分数据,引入其他来源的话在网速不好的情况下地图瓦片加载又会很慢,体验感极差:最终通过改造E ...
最新文章
- java 判断页面刷新_如何判断一个网页是刷新还是关闭的方法
- Oracle数据加载之sqlldr工具的介绍
- 检索 COM 类工厂中 CLSID 为 {10020200-E260-11CF-AE68-00AA004A34D5} 的组件时失败,解决方法如下:...
- 广告基本知识-广告的目的和效果
- drtek收音机使用说明_一百年前的便携式矿石收音机长啥样?这台1919年产品给你答案...
- 【转载】[BetterExplained]为什么你应该(从现在开始就)写博客
- ubuntu下安装Qt的过程以及遇到的问题和解决方案
- PyInstaller用法
- 不同平台下 sleep区别用法
- eclipse maven项目 class类部署不到tomcat下_Servlet tomcat部署
- linux操作实例,linux下的一些文档操作实例 | Soo Smart!
- 【ResNet】Deep Residual Learning for Image Recognition (2015) 全文翻译
- 麒麟下适配mellanox网卡驱动
- Blender骨骼动画记录
- [Evolutionary Algorithm] 进化算法简介
- 片上总线Wishbone 学习(七)总线周期之握手协议
- 第3章第10节:如何压缩幻灯片中的图片素材 [PowerPoint精美幻灯片实战教程]
- Java进阶04-动态代理、类加载
- BUPT-CSAPP 期末复习书后参考题节选及评注
- 服务应用执行可疑命令
热门文章
- 网页短信系统模块平台搭建后台通道分类|移讯云短信系统
- React 前端面试宝典
- 用Python转换华氏度与摄氏度
- java数组中删除元素或一个数组元素
- 开源应用中心 | Wordpress、Discuz! Q等应用免代码,极速开通
- Netty源码学习-LengthFieldBasedFrameDecoder
- python输出方格_使用Python实现LBM(格子法)方腔驱动流
- linux+电音制作软件,电音制作入门:读懂全球最受欢迎的软件合成器Serum㈦
- 在x86服务器上 搭建基于docker的arm64程序编译和运行环境
- 计网 —— internet、Internet、协议等重要概念