shader实现飞线效果(three.js练习)
一、先看看效果
二、实现方法:
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练习)相关推荐
- echart实现3d地图_3D飞线效果——让线“飞”起来的秘密
在城市规划.统计.交通等行业,地图可视化已成为最直接也最吸引眼球的一种表达方式.例如人群迁徙.人口流动.OD出行.职住分析.客流来源等众多场景都需要用到飞线效果呈现. 2D飞线效果图 随着可视化技术的 ...
- canvas绘制飞线效果
在我们做的可视化大屏项目中,经常会遇到飞线的效果. 在我们的大屏编辑器中,可以通过拖拽+配置参数的方式很快就能够实现.下面是我们使用大屏编辑器实现的一个项目效果: 中间地图就有飞线的效果. 抛开编辑器 ...
- Echarts实现3d 地图实现飞线效果
Echarts实现3d 地图实现飞线效果 注意:重点关注data中的数据格式 在lines3D中symbol不能设置指定样式,echarts官网也没有这个参数,所以对于lines3D飞线如何实现飞机航 ...
- web端的shader Threejs飞线
目标 之前想用粒子来实现一下飞线的效果,看到很多大佬的代码发现使用粒子会是一个不错的选择,因为粒子的渲染比较省性能,之前看到有人使用圆形的粒子 后来发现其实普通的正方形的粒子就行,因为在线的粗度比较小 ...
- 纯shader实现雷达扫描效果(three.js实战13)
1. demo效果 2. 实现要点 2.1 绘制雷达边框 这一步其实就是绘制一个圆,输入一个屏幕坐标st,原型坐标还有半径,使用distance求出坐标上任意点到圆心的距离,将这个距离接近圆半径的点绘 ...
- AMap + echarts、google map + d3.js分别实现数据可视化中的飞线图(迁徙图)
首先肯定是给出demo啦: 演示demo 直接到左侧选择框中选择View taxi flow里面随便选个日期 总体介绍 最近由于工作室项目需要做一个数据可视化平台,这个平台最终是交由国外人使用的.而国 ...
- 高德地图+echarts实现飞线图
下面是vue实现: 前期准备: 引入amap.echarts.echarts-amap依赖,vue的话需要npm安装一下 By using script tag <!--引入高德地图JSAPI ...
- html怎么绘制飞线,绘制飞线,echarts迁徙图原理
其实是在元素上绘制了一条线,然后利用canvas 的createLinearGradient函数不断移动线段的样式位置来实现. 因此首先绘制线段 ctx.beginPath(); ctx.moveTo ...
- Allegro如何打开和关闭飞线操作指导
Allegro如何打开和关闭飞线操作指导 Allegro可以打开和关闭飞线,下面介绍如何打开和关闭飞线,具体操作如下 选择display-show rats-all.打开所有nets的飞线 如下图 如 ...
最新文章
- 低耗时、高精度,微软提基于半监督学习的神经网络结构搜索算法
- X64 Linux 无法从本地字符界面登陆。
- [我给Unity官方视频教程做中文字幕]beginner Graphics – Lessons系列之材质了解Materials...
- uni-app定时器清除问题
- C# 的Delegate(委托)
- python解压加密zip文件_Python:解压缩前检测一个zip文件否为加密,两种算法。
- 命令提示符下对用户的操作
- JavaEE学习03--Servlet
- android webview权限申请_android中使用WebView请求网页
- 推贴B2B/B2C订货商城系统 V3.0版
- 如何搭建个人网站(详细完整,附阿里云视频教程推荐)
- MOSFET的特性曲线及特性方程
- 初夏小谈:浅谈字节序,TCP,UDP协议
- outlook qr码在哪里_条码生成软件如何批量生成DPM码
- Java程序员转行可以做什么?程序员
- css多媒体竖屏,css3 媒体查询方向:横屏竖屏教程
- vue的axios两种写法(不知道对不对,仅供参考)
- 电脑管理android手机版下载安装,airdroid下载
- Win7(老PC)Python环境搭建实战
- Java 复习之多线程
热门文章
- 当当网超级优惠券,别错过!(限时限量)
- js修改服务器域名,春哥详解:业务域名 JS接口安全域名 网页授权域名
- OpenCV可以识别文字吗?
- 大数据如何改变我们的国庆假期?
- PaddleClas高效实现口红检测识别
- Qt在设计ui界面时,在控件中输入中文,会自动变成英文字母,解决方案
- 随笔-关系抽取(三) — Dependency-based Models
- GitHub Actions 快速入门
- maven 使用本地库
- [ctf.show.reverse] 月饼杯 re1_西北望乡、re2_归心、re3_若无月