当前位置: 首页 > news >正文

Three.js 飞线效果教程

飞线效果 ·Fly Line· ▶ 在线运行案例

  • 案例合集:三维可视化功能案例(threehub.cn)
  • 开源仓库github地址:https://github.com/z2586300277/three-cesium-examples
  • 400个案例代码:网盘链接

你将学到什么

  • ShaderMaterial 自定义着色器实现核心视觉效果
  • OrbitControls 相机轨道交互
  • THREE.Points 粒子点渲染
  • CubicBezierCurve3 三次贝塞尔曲线
  • BufferGeometry 自定义顶点/索引数据
  • requestAnimationFrame渲染循环与resize自适应

效果说明

本案例演示飞线效果效果:基于 WebGL 实现「飞线效果」可视化效果,附完整可运行源码;核心用到 ShaderMaterial、OrbitControls、THREE.Points。建议先打开文首在线案例查看动态画面,再对照下方源码逐步理解。

核心概念

  • Scene / Camera / WebGLRenderer构成最小渲染闭环;大场景可开logarithmicDepthBuffer缓解 Z-fighting。
  • ShaderMaterial通过uniforms+ 自定义 GLSL 控制逐像素/逐点效果;透明粒子常配合depthTest: false
  • OrbitControls提供轨道旋转/缩放;开启enableDamping后需在 animate 中controls.update()
  • THREE.Points将每个顶点渲染为可控大小的粒子;可用自定义 attribute(如u_index)驱动片元/顶点动画。
  • 曲线类getPoints(n)将贝塞尔/样条离散为路径点,再写入 BufferGeometry 驱动飞线或路径动画。

实现步骤

  • 搭建 Scene、PerspectiveCamera、WebGLRenderer,挂载 canvas 并处理resize
  • 定义 uniforms / onBeforeCompile 或 ShaderMaterial,编写 GLSL 与材质参数
  • 用曲线离散点构建 BufferGeometry,写入自定义 attribute 驱动动画
  • 创建 OrbitControls(及 Raycaster 等交互控件,若源码包含)
  • requestAnimationFrame循环中更新状态并 render(Cesium 为viewer.render或自动渲染)
  • 代码要点

    import * as THREE from 'three';

    import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js' import Stats from 'three/examples/jsm/libs/stats.module.js';

    var renderer,clock,scene,camera; function initRender() { clock = new THREE.Clock(); renderer = new THREE.WebGLRenderer({antialias: true,alpha:true}); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); }

    function initCamera() { camera = new THREE.PerspectiveCamera(85, window.innerWidth / window.innerHeight, 0.1, 1000); camera.position.set(-200, 250, 350); camera.lookAt(new THREE.Vector3(0, 0, 0)); }

    function initScene() { scene = new THREE.Scene();

    }

    function initLight() { var hemisphereLight1 = new THREE.HemisphereLight(0xffffff, 0x444444, 2); hemisphereLight1.position.set(0, 200, 0); scene.add(hemisphereLight1); }

    var linegroup = []; function addflyline(minx,maxx,colorf,colort){ var colorf = colorf||{ r:0.0, g:0.0, b:0.0 }; var colort = colort||{ r:1.0, g:1.0, b:1.0 }; var curve = new THREE.CubicBezierCurve3( new THREE.Vector3( minx, 0, minx ), new THREE.Vector3( minx/2, maxx % 70 + 100, maxx/2 ), new THREE.Vector3( maxx/2, maxx % 70 + 70, maxx/2 ), new THREE.Vector3( maxx, 0, maxx ) ); var points = curve.getPoints( (maxx - minx) * 5 ); var geometry = new THREE.BufferGeometry().setFromPoints( points ); var material = createMaterial(); var flyline = new THREE.Points( geometry, material ); flyline.material.uniforms.time.value = minx; flyline.material.uniforms.colorf = { type:'v3', value:new THREE.Vector3(colorf.r,colorf.g,colorf.b) }; flyline.material.uniforms.colort = { type:'v3', value:new THREE.Vector3(colort.r,colort.g,colort.b) };

    flyline.minx = minx; flyline.maxx = maxx; linegroup.push(flyline); scene.add(flyline); }

    // 添加地球 var globeMesh; function addglobe() { var axesHelper = new THREE.AxesHelper( 400 ); scene.add( axesHelper ); var globeTextureLoader = new THREE.TextureLoader(); globeTextureLoader.load(FILE_HOST + 'threeExamples/application/flyLine/earth.jpeg', function (texture1) { console.log(texture1) var globeGgeometry = new THREE.SphereGeometry(60, 100, 100); var globeMaterial = new THREE.MeshStandardMaterial({map: texture1}); globeMesh = new THREE.Mesh(globeGgeometry, globeMaterial); scene.add(globeMesh); }); }

    //创建ShaderMaterial纹理的函数 function createMaterial() { var vertShader =uniform float time; uniform float size; varying vec3 iPosition;

    void main(){ iPosition = vec3(position); float pointsize = 1.; if(position.x > time && position.x < (time + size)){ pointsize = (position.x - time) / size; } gl_PointSize = pointsize * 3.0; gl_Position = projectionMatrixmodelViewMatrixvec4(position,1.0); }var fragShader =uniform float time; uniform float size; uniform vec3 colorf; uniform vec3 colort;

    varying vec3 iPosition;

    void main( void ) { float end = time + size; vec4 color; if(iPosition.x > end || iPosition.x < time){ discard; //color = vec4(0.213,0.424,0.634,0.3); }else if(iPosition.x > time && iPosition.x < end){ float step = fract((iPosition.x - time)/size);

    float dr = abs(colort.x - colorf.x); float dg = abs(colort.y - colorf.y); float db = abs(colort.z - colorf.z);

    float r = colort.x > colorf.x?(drstep+colorf.x):(colorf.x -drstep); float g = colort.y > colorf.y?(dgstep+colorf.y):(colorf.y -dgstep); float b = colort.z > colorf.z?(dbstep+colorf.z):(colorf.z -dbstep);

    color = vec4(r,g,b,1.0); } float d = distance(gl_PointCoord, vec2(0.5, 0.5)); if(abs(iPosition.x - end) < 0.2 || abs(iPosition.x - time) < 0.2){ if(d > 0.5){ discard; } } gl_FragColor = color; }

    //配置着色器里面的attribute变量的值 var attributes = {}; //配置着色器里面的uniform变量的值 var uniforms = { time: {type: 'f', value: -70.0}, size:{type:'f',value:25.0}, };

    var meshMaterial = new THREE.ShaderMaterial({ uniforms: uniforms, defaultAttributeValues : attributes, vertexShader: vertShader, fragmentShader: fragShader, transparent: true });

    return meshMaterial; }

    //初始化性能插件 var stats; function initStats() { stats = new Stats(); document.body.appendChild(stats.dom); } //用户交互插件 鼠标左键按住旋转,右键按住平移,滚轮缩放 var controls; function initControls() { controls = new OrbitControls(camera, renderer.domElement); // 如果使用animate方法时,将此函数删除 //controls.addEventListener( 'change', render ); // 使动画循环使用时阻尼或自转 意思是否有惯性 controls.enableDamping = true; //动态阻尼系数 就是鼠标拖拽旋转灵敏度 //controls.dampingFactor = 0.25; //是否可以缩放 controls.enableZoom = true; //是否自动旋转 controls.autoRotate = false; controls.autoRotateSpeed = 3; //设置相机距离原点的最远距离 controls.minDistance = 1; //设置相机距离原点的最远距离 controls.maxDistance = 200; //是否开启右键拖拽 controls.enablePan = true; } function render() { var delta = clock.getDelta(); if(globeMesh){ globeMesh.rotation.x += 0.01; globeMesh.rotation.y += 0.02; }

    if(linegroup.length){ for(var i = 0;i flyline.maxx){ flyline.material.uniforms.time.value = flyline.minx - size; } flyline.material.uniforms.time.value += 1.0; } } } renderer.render(scene, camera); } function animate() { //更新控制器 render(); //更新性能插件 stats.update(); controls.update(); requestAnimationFrame(animate); }

    function randomNum(minNum,maxNum){ switch(arguments.length){ case 1: return parseInt(Math.random()*minNum+1,10); break; case 2: return parseInt(Math.random()*(maxNum-minNum+1)+minNum,10); break; default: return 0; break; } } function draw() { initScene(); initCamera(); initLight(); initRender(); initControls(); initStats(); for(var j = 0;j< 200;j++){ var start = randomNum(-3000,-700)/10; var end = randomNum(700,3000)/10;

    var fr = randomNum(100,1000)/1000; var fg = randomNum(100,1000)/1000; var fb = randomNum(100,1000)/1000;

    var tr = randomNum(100,1000)/1000; var tg = randomNum(100,1000)/1000; var tb = randomNum(100,1000)/1000;

    addflyline(start,end,{r:fr,g:fg,b:fb},{r:tr,g:tg,b:tb}); } addglobe();

    animate(); } draw();

    完整源码:GitHub

    小结

    • 本文提供飞线效果完整 Three.js 源码与在线 Demo,建议先运行案例再改 uniform/参数做二次实验
    • 更多 Three.js 实战案例见 three-cesium-examples 合集 与 GitHub 开源仓库
http://www.jsqmd.com/news/1213392/

相关文章:

  • 2026玻璃机械客户认可吗 口碑推荐零套路价格透明 - mypinpai
  • 从技术视角拆解优质青春剧创作:真实感构建与叙事框架创新
  • 亨得利苏州直营售后中心指南|最新网点地址及官方热线公示(2026年7月最新) - 亨得利中国服务中心
  • Android网络请求实战:OkHttp与Retrofit黄金组合
  • Python办公自动化实战:Excel/Word/PDF高效处理
  • RPG Maker MV/MZ资源解密终极指南:5分钟解锁游戏素材的完整解决方案
  • 超低温干货|文献全梳理:R134a/R23 单机自复叠最优配比 + 全套实操注意事项
  • 深入解析TI EDMA控制器:三维传输、PaRAM与高效数据搬运实践
  • 网盘直链下载助手完整指南:九大平台一键获取真实下载地址
  • 【MyBatis-Plus】源码级吃透 MyBatis 与 MyBatis-Plus:两阶段架构、插件机制与底层增强全解析
  • 采购岗位可以考什么证书 - 众智商学院职业教育
  • 使用QEMU搭建ARM开发环境完整指南
  • 亨得利福州区官方维保核验指南|全网正规售后信息权威更新(2026年7月最新) - 亨得利中国服务中心
  • 重庆能源工业技师学院 - 学习招生
  • DFT笔记79
  • 别踩2026年做培训视频总结的常见成本误区,过来人分享实操经验
  • 2026岳阳制冷设备冷库空气能回收公司TOP5测评 - LYL仔仔
  • Cursor写测试用例实战手册(从Chat界面到CI通过的完整链路)
  • 浪琴中国区官方售后服务中心|官网认证地址及电话全新启用(2026年7月最新) - 浪琴中国服务中心
  • Java开发中避免数组越界与空指针异常的实战指南
  • 南京西路梧桐树下的“时光守望”:百年亨得利,镌刻上海海派风华的岁月长歌 - 亨得利官方维修中心
  • LVDS/CSI-2数据流控制:链路列表与FIFO阈值配置实战
  • 西安正规黄金回收门店测评:收的顶资质优势 + 详细地址一览400-867-6661(24小时在线) - 日常比对手册
  • 浪琴重庆官方售后服务中心|官方门店地址及客服电话全新公告(2026年7月最新) - 浪琴中国服务中心
  • 深入解析Windows蓝屏模拟器:从原理到实践的完整开发指南
  • 亨得利重庆维保网点资质攻略|官方公示正规维修服务渠道(2026年7月最新) - 亨得利中国服务中心
  • 浪琴中国区官方售后服务中心|官方网站权威公告(2026年7月最新) - 浪琴中国服务中心
  • 沈阳卖黄金白银铂金别乱找!6 家实体门店可企业长期合作,同步大盘无套路,地址电话全公开 - 不晚生活号
  • DNN Baseline模型
  • 如何用3分钟让你的Royal TSX变成纯中文界面:免费完整汉化指南