一、先看看效果

二、实现方法:

1.飞线的相关配置数据准备

// 飞线效果的相关配置数据
const flyData = [{start: {  //起始点位置x: 0,y: 0,z: 0},end: { // 结束点位置x: -250,y: 0,z: 0},range: 180, // 飞线长度height: 120, // 轨迹的高度color: '#e4393c', // 颜色speed: 1, // 速度size: 10 // 飞线点点的大小},{start: {  //起始点位置x: 0,y: 0,z: 0},end: { // 结束点位置x: 250,y: 0,z: 0},range: 180, // 飞线长度height: 180, // 轨迹的高度color: '#ff0000', // 颜色speed: 1, // 速度size: 10 // 飞线点点的大小}]

2. 创建飞线的函数

function initFly(options) {// 接收传入的参数const {start,end,height,size,color,range,speed} = options;// 起点位置const _start = new THREE.Vector3(start.x, start.y, start.z);// 结束点位置const _end = new THREE.Vector3(end.x, end.y, end.z);// 计算中建点位置/* lerp方法的用法: 在该向量与传入的向量v之间的线性插值,alpha是沿着线的长度的百分比 —— alpha = 0 时表示的是当前向量,alpha = 1 时表示的是所传入的向量v。此处传入 0.5 返回得是中间点位置**/const _center = _start.clone().lerp(_end, 0.5);// 把中间点的位置沿着y轴方向向上移动 height 距离_center.y += height;// 计算起点到终点间点的个数const number = parseInt(_start.distanceTo(_center) + _end.distanceTo(_center));// 创建一条平滑的三维 二次贝塞尔曲线, 由起点、终点和一个控制点所定义const curve = new THREE.QuadraticBezierCurve3(_start,_center,_end);// 将curve分成 number-1 段;得到number个点;存入数组points 中const points = curve.getPoints(number);// 申明变量用于存点的信息const positions = [];// 申明变量用于存点的索引信息const current = [];// 遍历点数组,将索引存入current, 将点的x,y,z展开,存入positions数组points.forEach((item, index) => {positions.push(item.x,item.y,item.z);current.push(index);});// 创建BufferGeometry 并把positions和current传给对应的attribute属性,供顶点着色器使用const geometry = new THREE.BufferGeometry();geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));geometry.setAttribute('current', new THREE.Float32BufferAttribute(current, 1));// 创建shader材质const material = new THREE.ShaderMaterial({transparent: true,depthWrite: false,depthTest: false,blending: THREE.AdditiveBlending,uniforms: {uSize: { // 点的大小value: size},uTime: ratio, // 时间uColor: { // 颜色value: new THREE.Color(color)},uRange: { // 飞线长度value: range},uTotal: { // 轨迹总长度,(点的总个数)value: number},uSpeed: { // 飞行速度value: speed}},vertexShader,fragmentShader});// 创建并添加到场景中const flyPoints = new THREE.Points(geometry, material);scene.add(flyPoints);
}

3、调用方法,创建飞线

// 创建飞线
flyData.forEach(item => {initFly(item);});

4、render函数中更新time

let next = 0;
render();
function render () {next += 0.01ratio.value = next;requestAnimationFrame(render);renderer.render(scene, camera);
}

5、着色器部分(核心代码)

// 顶点着色器
const vertexShader =  `// 接收js传入的attribute值,会经过线性插值attribute float current;// 接收js传入的uniform值uniform float uSize;uniform float uTime;uniform vec3 uColor;uniform float uRange;uniform float uTotal;uniform float uSpeed;// 向片元着色器传值颜色和透明度varying vec3 vcolor;varying float vopacity;void main () {float size = uSize;// 根据时间确定当前飞线的位置, 以结束点为准float currentEnd = uTotal * fract(uTime * uSpeed);// 判断当前像素点是否在飞线范围内,如果在范围内设置尺寸和透明度if (current < currentEnd && current > currentEnd - uRange) {// 设置渐变的尺寸,头大尾小float sizePct = (uRange - (currentEnd - current)) / uRange;size *= sizePct;vopacity = 1.0;} else {vopacity = 0.0;}// 将颜色传递给片元着色器vcolor = uColor;// 设置点的大小gl_PointSize = size * 0.4;gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);}`;// 片元着色器const fragmentShader =  `precision mediump float;// 接收顶点着色器传入的值varying float vopacity;varying vec3 vcolor;void main () {// 设置颜色gl_FragColor = vec4(vcolor, vopacity);}`;

三、实例代码

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>飞线效果</title><style>body {height: 100vh;overflow: hidden;}</style><script src="./lib/three.js"></script><script src="./lib/OrbitControls.js"></script>
</head>
<body>
<script>let scene, camera, renderer, controls, mixer, tubeCurve, AgvCar;let width = window.innerWidth;let height = window.innerHeightlet ratio = {value: 0}// 飞线效果的相关配置数据const flyData = [{start: {  //起始点位置x: 0,y: 0,z: 0},end: { // 结束点位置x: -250,y: 0,z: 0},range: 180, // 飞线长度height: 120, // 轨迹的高度color: '#e4393c', // 颜色speed: 1, // 速度size: 10 // 飞线点点的大小},{start: {  //起始点位置x: 0,y: 0,z: 0},end: { // 结束点位置x: 250,y: 0,z: 0},range: 180, // 飞线长度height: 180, // 轨迹的高度color: '#ff0000', // 颜色speed: 1, // 速度size: 10 // 飞线点点的大小}]function init () {// 场景scene = new THREE.Scene();let helper = new THREE.AxesHelper(100, 100);scene.add(helper);// 环境光let light = new THREE.AmbientLight(0xadadad); // soft white lightscene.add(light);// 平行光源const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);directionalLight.position.set(100, 100, 0);scene.add(directionalLight); // 相机camera = new THREE.PerspectiveCamera(45, width / height, 1, 10000)camera.position.set(30, 32, 260)scene.add(camera)// 渲染器renderer = new THREE.WebGLRenderer();renderer.setSize(width, height)renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));renderer.setClearColor(new THREE.Color('#32373E'), 1);document.body.appendChild(renderer.domElement);const vertexShader =  `// 接收js传入的attribute值,会经过线性插值attribute float current;// 接收js传入的uniform值uniform float uSize;uniform float uTime;uniform vec3 uColor;uniform float uRange;uniform float uTotal;uniform float uSpeed;// 向片元着色器传值颜色和透明度varying vec3 vcolor;varying float vopacity;void main () {float size = uSize;// 根据时间确定当前飞线的位置, 以结束点为准float currentEnd = uTotal * fract(uTime * uSpeed);// 判断当前像素点是否在飞线范围内,如果在范围内设置尺寸和透明度if (current < currentEnd && current > currentEnd - uRange) {// 设置渐变的尺寸,头大尾小float sizePct = (uRange - (currentEnd - current)) / uRange;size *= sizePct;vopacity = 1.0;} else {vopacity = 0.0;}// 将颜色传递给片元着色器vcolor = uColor;// 设置点的大小gl_PointSize = size * 0.4;gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);}`;const fragmentShader =  `precision mediump float;// 接收顶点着色器传入的值varying float vopacity;varying vec3 vcolor;void main () {// 设置颜色gl_FragColor = vec4(vcolor, vopacity);}`;// 创建飞线flyData.forEach(item => {initFly(item);});function initFly(options) {// 接收传入的参数const {start,end,height,size,color,range,speed} = options;// 起点位置const _start = new THREE.Vector3(start.x, start.y, start.z);// 结束点位置const _end = new THREE.Vector3(end.x, end.y, end.z);// 计算中建点位置/* lerp方法的用法: 在该向量与传入的向量v之间的线性插值,alpha是沿着线的长度的百分比 —— alpha = 0 时表示的是当前向量,alpha = 1 时表示的是所传入的向量v。此处传入 0.5 返回得是中间点位置**/const _center = _start.clone().lerp(_end, 0.5);// 把中间点的位置沿着y轴方向向上移动 height 距离_center.y += height;// 计算起点到终点间点的个数const number = parseInt(_start.distanceTo(_center) + _end.distanceTo(_center));// 创建一条平滑的三维 二次贝塞尔曲线, 由起点、终点和一个控制点所定义const curve = new THREE.QuadraticBezierCurve3(_start,_center,_end);// 将curve分成 number-1 段;得到number个点;存入数组points 中const points = curve.getPoints(number);// 申明变量用于存点的信息const positions = [];// 申明变量用于存点的索引信息const current = [];// 遍历点数组,将索引存入current, 将点的x,y,z展开,存入positions数组points.forEach((item, index) => {positions.push(item.x,item.y,item.z);current.push(index);});// 创建BufferGeometry 并把positions和current传给对应的attribute属性,供顶点着色器使用const geometry = new THREE.BufferGeometry();geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));geometry.setAttribute('current', new THREE.Float32BufferAttribute(current, 1));// 创建shader材质const material = new THREE.ShaderMaterial({transparent: true,depthWrite: false,depthTest: false,blending: THREE.AdditiveBlending,uniforms: {uSize: { // 点的大小value: size},uTime: ratio, // 时间uColor: { // 颜色value: new THREE.Color(color)},uRange: { // 飞线长度value: range},uTotal: { // 轨迹总长度,(点的总个数)value: number},uSpeed: { // 飞行速度value: speed}},vertexShader,fragmentShader});// 创建并添加到场景中const flyPoints = new THREE.Points(geometry, material);scene.add(flyPoints);}let next = 0;render();function render () {next += 0.01ratio.value = next;requestAnimationFrame(render);renderer.render(scene, camera);}controls = new THREE.OrbitControls(camera, renderer.domElement);}window.onload = init
</script></body>
</html>

shader实现飞线效果(three.js练习)相关推荐

  1. echart实现3d地图_3D飞线效果——让线“飞”起来的秘密

    在城市规划.统计.交通等行业,地图可视化已成为最直接也最吸引眼球的一种表达方式.例如人群迁徙.人口流动.OD出行.职住分析.客流来源等众多场景都需要用到飞线效果呈现. 2D飞线效果图 随着可视化技术的 ...

  2. canvas绘制飞线效果

    在我们做的可视化大屏项目中,经常会遇到飞线的效果. 在我们的大屏编辑器中,可以通过拖拽+配置参数的方式很快就能够实现.下面是我们使用大屏编辑器实现的一个项目效果: 中间地图就有飞线的效果. 抛开编辑器 ...

  3. Echarts实现3d 地图实现飞线效果

    Echarts实现3d 地图实现飞线效果 注意:重点关注data中的数据格式 在lines3D中symbol不能设置指定样式,echarts官网也没有这个参数,所以对于lines3D飞线如何实现飞机航 ...

  4. web端的shader Threejs飞线

    目标 之前想用粒子来实现一下飞线的效果,看到很多大佬的代码发现使用粒子会是一个不错的选择,因为粒子的渲染比较省性能,之前看到有人使用圆形的粒子 后来发现其实普通的正方形的粒子就行,因为在线的粗度比较小 ...

  5. 纯shader实现雷达扫描效果(three.js实战13)

    1. demo效果 2. 实现要点 2.1 绘制雷达边框 这一步其实就是绘制一个圆,输入一个屏幕坐标st,原型坐标还有半径,使用distance求出坐标上任意点到圆心的距离,将这个距离接近圆半径的点绘 ...

  6. AMap + echarts、google map + d3.js分别实现数据可视化中的飞线图(迁徙图)

    首先肯定是给出demo啦: 演示demo 直接到左侧选择框中选择View taxi flow里面随便选个日期 总体介绍 最近由于工作室项目需要做一个数据可视化平台,这个平台最终是交由国外人使用的.而国 ...

  7. 高德地图+echarts实现飞线图

    下面是vue实现: 前期准备: 引入amap.echarts.echarts-amap依赖,vue的话需要npm安装一下 By using script tag <!--引入高德地图JSAPI ...

  8. html怎么绘制飞线,绘制飞线,echarts迁徙图原理

    其实是在元素上绘制了一条线,然后利用canvas 的createLinearGradient函数不断移动线段的样式位置来实现. 因此首先绘制线段 ctx.beginPath(); ctx.moveTo ...

  9. Allegro如何打开和关闭飞线操作指导

    Allegro如何打开和关闭飞线操作指导 Allegro可以打开和关闭飞线,下面介绍如何打开和关闭飞线,具体操作如下 选择display-show rats-all.打开所有nets的飞线 如下图 如 ...

最新文章

  1. 低耗时、高精度,微软提基于半监督学习的神经网络结构搜索算法
  2. X64 Linux 无法从本地字符界面登陆。
  3. [我给Unity官方视频教程做中文字幕]beginner Graphics – Lessons系列之材质了解Materials...
  4. uni-app定时器清除问题
  5. C# 的Delegate(委托)
  6. python解压加密zip文件_Python:解压缩前检测一个zip文件否为加密,两种算法。
  7. 命令提示符下对用户的操作
  8. JavaEE学习03--Servlet
  9. android webview权限申请_android中使用WebView请求网页
  10. 推贴B2B/B2C订货商城系统 V3.0版
  11. 如何搭建个人网站(详细完整,附阿里云视频教程推荐)
  12. MOSFET的特性曲线及特性方程
  13. 初夏小谈:浅谈字节序,TCP,UDP协议
  14. outlook qr码在哪里_条码生成软件如何批量生成DPM码
  15. Java程序员转行可以做什么?程序员
  16. css多媒体竖屏,css3 媒体查询方向:横屏竖屏教程
  17. vue的axios两种写法(不知道对不对,仅供参考)
  18. 电脑管理android手机版下载安装,airdroid下载
  19. Win7(老PC)Python环境搭建实战
  20. Java 复习之多线程

热门文章

  1. 当当网超级优惠券,别错过!(限时限量)
  2. js修改服务器域名,春哥详解:业务域名 JS接口安全域名 网页授权域名
  3. OpenCV可以识别文字吗?
  4. 大数据如何改变我们的国庆假期?
  5. PaddleClas高效实现口红检测识别
  6. Qt在设计ui界面时,在控件中输入中文,会自动变成英文字母,解决方案
  7. 随笔-关系抽取(三) — Dependency-based Models
  8. GitHub Actions 快速入门
  9. maven 使用本地库
  10. [ctf.show.reverse] 月饼杯 re1_西北望乡、re2_归心、re3_若无月