扩散圈 · Ripple Circle · ▶ 在线运行案例
案例合集: 三维可视化功能案例(threehub.cn)
开源仓库github地址: https://github.com/z2586300277/three-cesium-examples
**400个案例代码: ** 网盘链接

你将学到什么
- Sprite 始终面向相机的 billboard 用法
- 用 scale + opacity 模拟雷达/定位扩散圈
depthWrite: false避免透明精灵深度冲突
效果说明
一张圆形 PNG 贴图作为 Sprite,周期性放大并淡出,形成从中心向外扩散的波纹,常见于地图定位、雷达扫描 UI。
核心概念
Sprite vs Mesh
| Sprite | Mesh Plane | |
|---|---|---|
| 朝向 | 永远面向相机 | 固定朝向 |
| 用途 | 光点、标注、扩散圈 | 地面贴花 |
const material = new THREE.SpriteMaterial({
map: texture,
transparent: true,
depthWrite: false, // 透明叠加时不写深度
});
const sprite = new THREE.Sprite(material);
脉冲动画逻辑
let circle_n = 0;
function animate() {
circle_n = circle_n > 10 ? 0 : circle_n + 0.2;
const scale = 0.1 * circle_n + 0.1;
sprite.scale.set(scale, scale, scale);
sprite.material.opacity = Math.max(1 - circle_n * 0.05, 0.2);
}
circle_n 0→10 循环:scale 从小到大,opacity 从 1 到 0.2,然后重置。
代码要点
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
// 初始化场景
const scene = new THREE.Scene();
const box = document.getElementById('box');
// 初始化透视相机(添加lookAt确保朝向场景中心)
const camera = new THREE.PerspectiveCamera(75, box.clientWidth / box.clientHeight, 0.1, 1000);
camera.position.set(5, 5, 5);
camera.lookAt(0, 0, 0); // 确保相机朝向场景中心
// 初始化渲染器
const renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true,
logarithmicDepthBuffer: true
});
renderer.setSize(box.clientWidth, box.clientHeight);
renderer.setClearColor(0x808080, 1); // 设置背景颜色(与原代码一致)
box.appendChild(renderer.domElement);
// 调试辅助:添加坐标轴辅助器
const axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);
// 初始化纹理加载(添加错误处理)
const textureLoader = new THREE.TextureLoader();
let texture = textureLoader.load(
HOST + "files/images/circle.png",
undefined,
undefined,
(err) => {
console.error('纹理加载失败:', err);
// 加载失败时使用默认材质
texture = new THREE.TextureLoader().load('https://threejs.org/examples/textures/sprites/disc.png');
}
);
// 创建精灵材质
let material = new THREE.SpriteMaterial({
map: texture,
color: 0xff0000,
transparent: true,
opacity: 1,
depthWrite: false
});
// 创建精灵(添加初始位置调试)
const sprite = new THREE.Sprite(material);
sprite.position.set(0, 0, 0); // 初始位置改为场景中心
sprite.scale.set(1, 1, 1); // 初始缩放改为1
scene.add(sprite);
// 添加环境光(增强光照)
const ambientLight = new THREE.AmbientLight(0xffffff, 2); // 增强环境光强度
scene.add(ambientLight);
// 添加轨道控制器(方便调试观察)
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
// 动画参数
let circle_n = 0;
function animate() {
requestAnimationFrame(animate);
// 更新控制器
controls.update();
// 精灵动画逻辑
circle_n = circle_n > 10 ? 0 : circle_n + 0.2;
const scale = 0.1 * circle_n + 0.1;
sprite.scale.set(scale, scale, scale);
// 保持最小透明度防止完全消失
sprite.material.opacity = Math.max(1 - circle_n * 0.05, 0.2);
renderer.render(scene, camera);
}
// 窗口大小调整处理
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
// 启动动画
animate();
// 调试信息输出
setTimeout(() => {
console.log('场景内容:', scene.children);
console.log('相机位置:', camera.position);
console.log('精灵位置:', sprite.position);
}, 1000);
完整源码:GitHub
小结
- 本文提供 扩散圈 完整 Three.js 源码与在线 Demo,建议先运行案例再改 uniform/参数做二次实验
- 更多 Three.js 实战案例见 three-cesium-examples 合集 与 GitHub 开源仓库