three案例 Three.js波纹效果演示

在这里插入图片描述
波纹效果,在智慧城市可视化开发中经常用到,这里分享一个比较好玩的案例
以下是详细的步骤:

初始化部分:设置 Three.js 环境,包括场景、相机、渲染器和控制器
几何体和纹理:创建平面几何体并加载波纹纹理
着色器材质:使用自定义着色器实现波纹效果,包括顶点着色器和片段着色器
波纹算法:核心是 circleWave 函数,通过计算距离和时间来生成向外扩散的波纹
颜色混合:根据波纹强度混合两种颜色,形成视觉层次感
交互控制:使用 GUI 工具允许用户实时调整波纹颜色
动画循环:通过不断更新时间变量来驱动波纹动画
浏览地址:https://aivogenx.github.io/threejs-cesium-webgpu-vue-js/#/codeMirror?navigation=Three.js%E6%A1%88%E4%BE%8B&classify=shader&id=circleWave
代码

<!DOCTYPE html>
<html lang="zh-CN"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Three.js波纹效果演示</title><!-- 这里可以添加CSS样式文件 -->
</head><body><!-- 导入模块映射,配置Three.js依赖路径 --><script type="importmap">{"imports": {"three": "./threejs/build/three.module.js","three/addons/": "./threejs/examples/jsm/"}}</script><script type="module">// 导入Three.js核心库和辅助工具import * as THREE from 'three'import { OrbitControls } from "three/addons/controls/OrbitControls.js"; import { GUI } from "three/addons/libs/lil-gui.module.min.js";// 获取渲染容器,使用整个body元素const box = document.body;// 创建Three.js场景,作为所有3D对象的容器const scene = new THREE.Scene()// 创建透视相机,参数依次为:视野角度、宽高比、近裁剪面、远裁剪面const camera = new THREE.PerspectiveCamera(50, box.clientWidth / box.clientHeight, 0.1, 1000)// 设置相机位置,从(1,1,1)的位置观察场景camera.position.set(1, 1, 1)// 创建WebGL渲染器,启用抗锯齿、透明背景和对数深度缓冲区const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true, logarithmicDepthBuffer: true })// 设置渲染器尺寸为容器大小renderer.setSize(box.clientWidth, box.clientHeight)// 将渲染器的DOM元素添加到页面中box.appendChild(renderer.domElement)// 创建轨道控制器,允许用户通过鼠标交互旋转和缩放场景const controls = new OrbitControls(camera, renderer.domElement)// 启用阻尼效果,使相机移动更平滑controls.enableDamping = true// 窗口大小变化时的响应函数,保持渲染内容适配窗口window.onresize = () => {// 更新渲染器尺寸renderer.setSize(box.clientWidth, box.clientHeight)// 更新相机的宽高比camera.aspect = box.clientWidth / box.clientHeight// 更新相机投影矩阵camera.updateProjectionMatrix()}// 创建平面几何体,作为波纹效果的载体const geometry = new THREE.PlaneGeometry(2, 2);// 加载波纹纹理,这是实现波纹效果的基础纹理// 注意:FILE_HOST变量需要在实际使用时替换为真实的资源路径const texture = new THREE.TextureLoader().load(FILE_HOST + 'images/channels/wave.png')// 设置纹理在水平和垂直方向上重复texture.wrapS = THREE.RepeatWrappingtexture.wrapT = THREE.RepeatWrapping// 创建自定义着色器材质,实现波纹效果的核心部分const material = new THREE.ShaderMaterial({side: THREE.DoubleSide,          // 双面渲染transparent: true,             // 启用透明度blending: THREE.AdditiveBlending, // 添加混合模式让效果更亮uniforms: {uTime: { value: 0.0 },           // 时间变量,控制波纹动画uScanTex: { value: texture },    // 波纹纹理uScanColor: { value: new THREE.Color(0x00ffff) },    // 主要扫描颜色uScanColorDark: { value: new THREE.Color(0x0088ff) } // 暗部扫描颜色},// 顶点着色器:处理几何体顶点,传递纹理坐标和位置信息给片段着色器vertexShader: `varying vec2 vUv;         // 传递给片段着色器的纹理坐标varying vec3 vPosition;   // 传递给片段着色器的顶点位置void main() {vUv = uv;vPosition = position;gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);}`,// 片段着色器:计算每个像素的颜色,实现波纹效果的核心逻辑fragmentShader: `// 波纹原点和波纹扩展速度常量#define uScanOrigin vec3(0.0, 0.0, 0.0)#define uScanWaveRatio1 3.2#define uScanWaveRatio2 2.8uniform float uTime;           // 时间变量uniform sampler2D uScanTex;    // 波纹纹理uniform vec3 uScanColor;       // 波纹主颜色uniform vec3 uScanColorDark;   // 波纹暗部颜色varying vec2 vUv;              // 从顶点着色器传递的纹理坐标varying vec3 vPosition;        // 从顶点着色器传递的顶点位置// 计算圆形波纹效果float circleWave(vec3 p, vec3 origin, float distRatio) {float t = uTime;float dist = distance(p, origin) * distRatio;  // 计算到原点的距离并应用缩放float radialMove = fract(dist - t);            // 创建随时间移动的波纹float fadeOutMask = 1.0 - smoothstep(1.0, 3.0, dist); // 波纹随距离衰减radialMove *= fadeOutMask;float cutInitialMask = 1.0 - step(t, dist);    // 控制波纹从中心向外扩展return radialMove * cutInitialMask;}// 根据位置和纹理计算波纹颜色vec3 getScanColor(vec3 worldPos, vec2 uv, vec3 col) {// 从纹理采样,获取波纹基础图案float scanMask = texture2D(uScanTex, uv).r;// 计算两种不同速度的波纹效果,形成层次感float cw = circleWave(worldPos, uScanOrigin, uScanWaveRatio1);float cw2 = circleWave(worldPos, uScanOrigin, uScanWaveRatio2);// 为第一种波纹创建遮罩,控制波纹的显示范围和强度float mask1 = smoothstep(0.3, 0.0, 1.0 - cw);mask1 *= (1.0 + scanMask * 0.7);  // 结合纹理增强效果// 为第二种波纹创建遮罩float mask2 = smoothstep(0.07, 0.0, 1.0 - cw2) * 0.8;mask1 += mask2;// 创建波纹边缘高亮效果float mask3 = smoothstep(0.09, 0.0, 1.0 - cw) * 1.5;mask1 += mask3;// 根据遮罩强度混合两种颜色,形成波纹的颜色变化vec3 scanCol = mix(uScanColorDark, uScanColor, mask1);return scanCol * mask1; // 返回最终的波纹颜色}void main() {vec3 col = vec3(0.0);// 计算波纹颜色,纹理坐标乘以10.0增强波纹密度col = getScanColor(vPosition, vUv * 10.0, col);// 根据颜色强度计算透明度,使波纹边缘更柔和float alpha = length(col);gl_FragColor = vec4(col, alpha);}`});// 创建网格对象,将几何体和材质组合,并添加到场景中const mesh = new THREE.Mesh(geometry, material);// 将平面旋转90度,使其水平放置mesh.rotation.x = Math.PI / 2scene.add(mesh);// 创建图形界面控制器,允许用户交互调整参数const gui = new GUI()const params = {uScanColor: '#00ffff',         // 波纹主颜色uScanColorDark: '#0088ff'      // 波纹暗部颜色}// 添加颜色控制器,允许用户修改波纹主颜色gui.addColor(params, 'uScanColor').onChange((value) => {material.uniforms.uScanColor.value.set(value)})// 添加颜色控制器,允许用户修改波纹暗部颜色gui.addColor(params, 'uScanColorDark').onChange((value) => {material.uniforms.uScanColorDark.value.set(value)})// 动画循环函数,驱动整个场景的渲染和更新animate()function animate() {// 请求下一帧动画requestAnimationFrame(animate)// 更新控制器状态controls.update()// 渲染场景renderer.render(scene, camera)// 更新时间变量,驱动波纹动画material.uniforms.uTime.value += 0.005;}</script>
</body></html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/88154.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/88154.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Flutter-详解布局

上一章我们详细的学习了 Flutter 中的Widget&#xff0c;这一章我们将要学习 Flutter 的布局&#xff0c; 在上一章我们了解到了&#xff1a;Everything is a widget&#xff0c;在 Flutter 中几乎所有的对象都是一个 Widget &#xff0c;当然也包括布局&#xff0c;Flutter 的…

EPLAN 电气制图:建立自己的部件库,添加部件-加SQL Server安装教程(三)上

在智能电气设计领域&#xff0c;EPLAN 作为主流的设计软件&#xff0c;其部件库的完善程度直接影响项目设计的效率与质量。本文将从实际操作出发&#xff0c;详细讲解如何在 EPLAN 中建立专属部件库并添加部件&#xff0c;为电气设计奠定坚实基础。一、部件库&#xff1a;电气设…

静态路由进阶实战全解

一、项目背景二、项目拓扑图三、设备命名与IP地址规划设备名接口编号IP地址规划R1GE0/0192.168.1.1/24GE0/1172.16.1.1/24R2GE0/0192.168.1.2/24GE0/1192.168.2.2/24R3GE0/0192.168.2.3/24GE0/1192.168.3.3/24GE0/2192.168.4.3/24R4GE0/0192.168.3.4/24GE0/1192.168.4.4/24GE0/…

stm32hal模块驱动(3)ssd1305 oled驱动

SD1305 OLED 驱动芯片详细介绍SSD1305 是 Solomon Systech 公司生产的一款 OLED 显示控制器/驱动器&#xff0c;专为 128x64 或 128x32 点阵的 OLED 显示屏设计。下面我将从多个方面详细介绍这款驱动芯片。一、SSD1305 基本特性显示分辨率&#xff1a;最大支持 128 segments 6…

安全为先:如何在 Python 中安全处理数据库连接与敏感信息

安全为先:如何在 Python 中安全处理数据库连接与敏感信息 引言:Python 与安全的数据库交互 自 1991 年诞生以来,Python 凭借其简洁优雅的语法和强大的生态系统,成为 Web 开发、数据科学、人工智能和数据库交互的首选语言。作为“胶水语言”,Python 不仅让开发者能够快速…

服务器经常出现蓝屏是什么原因导致的?如何排查和修复?

服务器出现蓝屏&#xff08;BSOD&#xff0c;Blue Screen of Death&#xff09;是一个严重的问题&#xff0c;通常表明系统内核或硬件发生了不可恢复的错误。蓝屏不仅会导致服务器宕机&#xff0c;还可能对业务运行造成重大影响。要有效解决蓝屏问题&#xff0c;需要先找到根本…

为什么elementui的<el-table-column label=“名称“ prop=“name“ label不用写成:label

在 Vue.js 中&#xff0c;label 和 prop 是 el-table-column 组件的普通属性&#xff0c;而不是动态绑定的表达式。因此&#xff0c;不需要使用 : 来绑定它们。 1. Vue.js 中的属性绑定 在 Vue.js 中&#xff0c;属性绑定有两种方式&#xff1a; 静态属性绑定&#xff1a;直接写…

分布式光纤传感:为储能安全保驾护航

储能系统是指一种能够将电能、化学能、动能等形式的能量进行转化、储存和释放的装置&#xff0c;广泛应用于可再生能源发电、智能电网、电动车等领域。储能行业这几年得到了稳步发展&#xff0c;受到政府机构、行业协会、大型能源企业、电网公司、系统集成商、检测认证机构等业…

从历史航拍图像中去除阴影

在光学遥感中&#xff0c;阴影是影响土地覆盖制图精度和分辨率的一个因素&#xff0c;无论是历史影像&#xff08;黑白影像&#xff09;还是近期影像&#xff08;全彩影像&#xff09;。阴影的产生取决于太阳光照&#xff08;太阳方位角和天顶角&#xff09;、相机视点&#xf…

UE material advance 学习笔记

如何体现轮胎速度的快速感&#xff1a;就是增加一个radial blur&#xff0c;会让视觉效果感觉轮胎已经转冒烟了&#xff0c;但是上面两个轮胎的转速其实是相同的这种磨砂的感觉&#xff0c;可以用上ditherAA来实现只看法线这一块&#xff0c;ditherAA就是让他的表面颜色有大量的…

Vue--2、Vue2 项目配置与组件化开发

一、Vue2 项目环境搭建1. 环境准备安装 Node.js&#xff1a;推荐使用 nvm 管理多版本 Node# 安装Node 16.20.2 nvm install 16.20.2 # 切换至指定版本 nvm use 16.20.2 # 验证安装 node -v && npm -v安装 Vue CLI 脚手架&#xff1a;# 国内镜像源安装 npm install --re…

虚幻基础:函数的返回节点

能帮到你的话&#xff0c;就给个赞吧 &#x1f618; 文章目录函数的返回节点&#xff1a;返回执行后的值返回执行后的值若不执行第一次 返回参数的默认值第二次 返回上一次执行值示例函数的返回节点&#xff1a;返回执行后的值 返回执行后的值 若不执行 第一次 返回参数的默…

FFmpeg 升级指北

近期我参与了部门底层库依赖的 FFmpeg 从 3.4 升级至 7.0.2 的工作&#xff0c;在此分享一些经验和遇到的 API 变动。 将 FFmpeg 升级到高版本后&#xff0c;编译过程中遇到大量报错是常态。这些错误通常源于 API 接口变更或结构体字段调整。此时不必惊慌&#xff0c;核心解决…

RISCV Linux 虚拟内存精讲系列三 -- setup_vm()

在 Linux 使用虚拟地址前&#xff0c;需要先配置页表&#xff0c;这就是 setup_vm() 的作用。然而&#xff0c;Linux 的页表配置&#xff0c;并不是一次过完成的&#xff0c;分了两个阶段&#xff0c;如下&#xff1a;在 setup_vm() 中&#xff0c;主要初始化了&#xff1a;1. …

创客匠人:解析创始人 IP 打造的底层逻辑与知识变现路径

在数字经济时代&#xff0c;创始人 IP 的价值被不断放大&#xff0c;而知识变现作为 IP 商业闭环的核心环节&#xff0c;正成为无数创业者探索的方向。创客匠人深耕知识付费领域多年&#xff0c;见证了大量创始人从 0 到 1 打造 IP 并实现变现的全过程&#xff0c;其背后的逻辑…

Visual Studio 2022 MFC Dialog 添加Toolbar及Tips提示

主要步骤&#xff1a;在主框架类中添加消息处理函数声明在 OnCreate 函数中启用工具栏提示在消息映射中注册 TTN_NEEDTEXT 消息使用 OnToolTipText 函数实现自定义提示文本1.在主程序的.h文件中加入afx_msg BOOL OnToolTipText(UINT id, NMHDR* pNMHDR, LRESULT* pResult); 2.在…

2025Q2大模型更新汇总(大语言模型篇)

摘要 2025年Q2大语言模型更新汇总&#xff1a; Qwen3&#xff0c;Deepseek-R1-0528&#xff0c;Doubao-Seed-1.6, MiniMax-M1, GPT4.1/O3/O4&#xff0c;Claude4/Gemini2.5 Qwen3 • 开源MOE模型&#xff0c; • MOE模型&#xff1a;Qwen3-235B-A22B&#xff0c;Qwen3-30B-…

【STM32】定时器中断 + 含常用寄存器和库函数配置(提供完整实例代码)

通用定时器基础知识 参考资料:STM32F1xx官方资料:《STM32中文参考手册V10》-第14章通用定时器 通用定时器工作过程: 时钟选择 计数器时钟可以由下列时钟源提供: ① 内部时钟(CK_INT) ② 外部时钟模式1:外部输入脚(TIx) ③ 外部时钟模式2:外部触发输入(ETR) ④ 内部触…

集群Redis

文章目录前言一、Redis主从复制配置1.1.配置文件redis_master.conf,redis_slave.conf1.2.启动服务1.3.检查成果二、Redis集群配置2.1.服务器40.240.34.91集群配置2.2.其它服务器xxx.92,xxx.93集群配置2.3.启动服务2.3.启动集群服务2.4.检查成果三、优劣四、结束前言 提示&…

ORA-600 kokiasg1故障分析---惜分飞

故障总结:客户正常关闭数据库,然后启动报ORA-600 kokiasg1错误,通过对启动分析确认是由于IDGEN1$序列丢失导致,修复该故障之后,数据库启动成功,但是后台大量报ORA-600 12803,ORA-600 15264等错误,业务用户无法登录.经过深入分析,发现数据库字典obj$中所有核心字典的序列全部被删…