2026 爆火酷炫 3D 粒子交互,AI 3D粒子动态交互,手势跟随,
本人亲测苹果,安卓,电脑全部可行,如果微信打开网址不能跟随换夸克,google浏览器或系统默认浏览器测试.
测试链接: https://dh.dj3c.com//data/Lzjh.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3D手势粒子交互系统</title>
<style>
body { margin: 0; overflow: hidden; background-color: #050505; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; }
canvas { display: block; }
/* 隐藏的视频元素,用于MediaPipe处理 */
#input_video { position: absolute; top: -1000px; left: -1000px; transform: scaleX(-1); }
/* UI 面板 */
#ui-container {
position: absolute;
top: 20px;
right: 20px;
width: min(360px, calc(100vw - 40px));
max-height: calc(100vh - 40px);
overflow: hidden;
background: rgba(30, 30, 30, 0.85);
backdrop-filter: blur(10px);
padding: 16px;
border-radius: 12px;
border: 1px solid rgba(255, 255, 255, 0.1);
color: #fff;
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37);
transition: all 0.3s ease;
z-index: 10;
}
h2 { margin: 0 0 15px 0; font-size: 18px; font-weight: 500; letter-spacing: 1px; border-bottom: 1px solid rgba(255,255,255,0.1); padding-bottom: 10px; }
.control-group { margin-bottom: 14px; }
label { display: block; margin-bottom: 8px; font-size: 12px; color: #aaa; text-transform: uppercase; }
#shape-buttons {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 7px;
}
/* 按钮样式 */
.shape-btn {
display: block;
width: 100%;
min-height: 34px;
padding: 7px 4px;
margin: 0;
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.05);
color: #ddd;
border-radius: 6px;
cursor: pointer;
font-size: 12px;
transition: all 0.2s;
text-align: center;
line-height: 1.2;
}
.shape-btn:hover { background: rgba(255, 255, 255, 0.2); }
.shape-btn.active { background: #00d2ff; color: #000; font-weight: bold; border-color: #00d2ff; }
/* 颜色选择器 */
input[type="color"] {
-webkit-appearance: none;
border: none;
width: 100%;
height: 35px;
border-radius: 6px;
cursor: pointer;
background: none;
}
input[type="color"]::-webkit-color-swatch-wrapper { padding: 0; }
input[type="color"]::-webkit-color-swatch { border: 1px solid rgba(255,255,255,0.2); border-radius: 6px; }
/* 全屏按钮 */
#fullscreen-btn {
width: 100%;
padding: 10px;
background: transparent;
border: 1px solid rgba(255, 255, 255, 0.2);
color: #fff;
border-radius: 6px;
cursor: pointer;
margin-top: 10px;
transition: 0.2s;
}
#fullscreen-btn:hover { background: rgba(255, 255, 255, 0.1); }
/* 状态指示器 */
#status {
position: absolute;
top: 20px;
left: 20px;
color: #00d2ff;
font-size: 14px;
background: rgba(0,0,0,0.6);
padding: 8px 15px;
border-radius: 20px;
pointer-events: none;
}
/* 摄像头预览小窗 (可选,便于调试) */
#webcam-preview {
position: absolute;
bottom: 20px;
left: 20px;
width: 160px;
height: 120px;
background: #000;
border-radius: 8px;
overflow: hidden;
border: 2px solid rgba(255,255,255,0.1);
opacity: 0.7;
transform: scaleX(-1); /* 镜像 */
}
.gesture-guide {
margin-top: 14px;
padding-top: 12px;
border-top: 1px solid rgba(255,255,255,0.1);
display: grid;
gap: 7px;
max-height: min(260px, calc(100vh - 430px));
overflow-y: auto;
padding-right: 4px;
font-size: 12px;
color: rgba(255,255,255,0.76);
}
.gesture-guide::-webkit-scrollbar { width: 5px; }
.gesture-guide::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.22); border-radius: 6px; }
.gesture-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
line-height: 1.35;
}
.gesture-row b {
color: #7df9ff;
font-weight: 600;
white-space: nowrap;
}
</style>
<!-- 引入 Three.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<!-- 引入 MediaPipe Hands -->
<script src="https://cdn.jsdelivr.net/npm/@mediapipe/camera_utils/camera_utils.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/@mediapipe/control_utils/control_utils.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/@mediapipe/drawing_utils/drawing_utils.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/@mediapipe/hands/hands.js" crossorigin="anonymous"></script>
</head>
<body>
<div id="status">正在初始化摄像头与模型...</div>
<video id="input_video"></video>
<canvas id="webcam-preview"></canvas>
<div id="ui-container">
<h2>粒子控制台</h2>
<div class="control-group">
<label>选择模型</label>
<div id="shape-buttons">
<div class="shape-btn active" data-shape="heart">爱心</div>
<div class="shape-btn" data-shape="flower">花朵</div>
<div class="shape-btn" data-shape="saturn">土星</div>
<div class="shape-btn" data-shape="buddha">佛像(禅)</div>
<div class="shape-btn" data-shape="firework">烟花球</div>
<div class="shape-btn" data-shape="portal">星门</div>
<div class="shape-btn" data-shape="sword">剑阵</div>
<div class="shape-btn" data-shape="beam">光柱</div>
<div class="shape-btn" data-shape="spiral">星河</div>
</div>
</div>
<div class="control-group">
<label>粒子颜色</label>
<input type="color" id="color-picker" value="#00d2ff">
</div>
<button id="fullscreen-btn">⛶ 全屏模式</button>
<div class="control-group" style="margin-top:20px; border-top: 1px solid rgba(255,255,255,0.1); padding-top:10px;">
<label>手势数据</label>
<div style="font-size:12px; color:#ddd; display:flex; justify-content:space-between;">
<span>状态: <span id="hand-state" style="color:#aaa;">未检测</span></span>
<span>系数: <span id="scale-val" style="color:#00d2ff;">1.0</span></span>
</div>
<div class="gesture-guide">
<div class="gesture-row"><b>张掌</b><span>当前模型扩散</span></div>
<div class="gesture-row"><b>握拳</b><span>当前模型压缩</span></div>
<div class="gesture-row"><b>捏合</b><span>聚能收束</span></div>
<div class="gesture-row"><b>双指</b><span>锐化展开</span></div>
<div class="gesture-row"><b>拇指</b><span>能量升腾</span></div>
<div class="gesture-row"><b>挥手</b><span>旋转加速</span></div>
<div class="gesture-row"><b>双手靠近</b><span>收束旋涡</span></div>
<div class="gesture-row"><b>双手拉开</b><span>空间展开</span></div>
</div>
</div>
</div>
<script>
// ================= 配置参数 =================
const PARTICLE_COUNT = 25000;
const PARTICLE_SIZE = 0.08;
const TRANSITION_SPEED = 0.16; // 形状变换速度
const HAND_SENSITIVITY = 0.34; // 手势响应速度
// ================= 全局变量 =================
let scene, camera, renderer, particles, geometry, material;
let currentShape = 'heart';
let targetPositions = []; // 存储目标形状的坐标
let basePositions = []; // 存储当前计算出的基础形状坐标(无缩放)
let currentColor = new THREE.Color(0x00d2ff);
// 手势控制变量
let handScaleFactor = 1.0; // 当前应用的缩放因子
let targetHandScale = 1.0; // 目标缩放因子(来自MediaPipe)
let isHandDetected = false;
let lastPalmX = null;
let waveUntil = 0;
let currentGestureName = '待机';
let gestureCandidate = '';
let gestureCandidateCount = 0;
let targetRotationBoost = 0.002;
let rotationBoost = 0.002;
// UI 元素
const statusEl = document.getElementById('status');
const handStateEl = document.getElementById('hand-state');
const scaleValEl = document.getElementById('scale-val');
const previewCanvas = document.getElementById('webcam-preview');
const previewCtx = previewCanvas.getContext('2d');
// ================= Three.js 初始化 =================
function initThree() {
scene = new THREE.Scene();
// 添加一点雾效果增加深度感
scene.fog = new THREE.FogExp2(0x050505, 0.02);
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 25;
camera.position.y = 2;
renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 1.5));
document.body.appendChild(renderer.domElement);
// 创建粒子系统
geometry = new THREE.BufferGeometry();
const positions = new Float32Array(PARTICLE_COUNT * 3);
// 初始位置随机分布
for (let i = 0; i < PARTICLE_COUNT * 3; i++) {
positions[i] = (Math.random() - 0.5) * 50;
}
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
material = new THREE.PointsMaterial({
color: currentColor,
size: PARTICLE_SIZE,
sizeAttenuation: true,
blending: THREE.AdditiveBlending,
depthWrite: false,
transparent: true,
opacity: 0.8
});
particles = new THREE.Points(geometry, material);
scene.add(particles);
// 初始化目标位置数组
targetPositions = new Float32Array(PARTICLE_COUNT * 3);
basePositions = new Float32Array(PARTICLE_COUNT * 3);
// 默认生成爱心
generateShape('heart');
// 监听窗口大小变化
window.addEventListener('resize', onWindowResize, false);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
// ================= 形状生成算法 =================
// 使用数学公式生成不同形状的点云
function getPointOnShape(type, idx, total) {
const u = Math.random();
const v = Math.random();
const theta = Math.random() * Math.PI * 2;
const phi = Math.acos(2 * Math.random() - 1);
let x, y, z;
switch (type) {
case 'heart':
// 3D Heart equation
// \[ x = 16\sin^3(t) \]
// \[ y = 13\cos(t) - 5\cos(2t) - 2\cos(3t) - \cos(4t) \]
// 扩展到3D: 结合层状分布或旋转体积
{
const t = theta; // 0 to 2PI
// 稍微随机化层厚度
const r = 0.5 + Math.random() * 0.5;
// 爱心参数方程
x = 16 * Math.pow(Math.sin(t), 3);
y = 13 * Math.cos(t) - 5 * Math.cos(2*t) - 2 * Math.cos(3*t) - Math.cos(4*t);
z = (Math.random() - 0.5) * 8; // 厚度
// 让粒子填充内部
const scale = Math.cbrt(Math.random());
x *= scale; y *= scale; z *= scale;
// 调整比例
x *= 0.5; y *= 0.5; z *= 0.5;
}
break;
case 'flower':
// 3D Rose / Flower shape
{
const k = 3; // 花瓣数
const r = 10 * Math.cos(k * theta) + 5; // 极坐标半径
const r_vol = r * Math.random(); // 填充内部
x = r_vol * Math.cos(theta);
y = r_vol * Math.sin(theta);
z = (Math.random() - 0.5) * 5 * (1 - r_vol/15); // 中心厚,边缘薄
// 稍微弯曲花瓣
z += Math.cos(theta * k) * 2;
}
break;
case 'saturn':
// Sphere + Ring
if (Math.random() > 0.4) {
// Planet Body (Sphere)
const r = 6 * Math.cbrt(Math.random());
x = r * Math.sin(phi) * Math.cos(theta);
y = r * Math.sin(phi) * Math.sin(theta);
z = r * Math.cos(phi);
} else {
// Ring (Flat disc with hole)
const rInner = 8;
const rOuter = 14;
const r = Math.sqrt(Math.random() * (rOuter*rOuter - rInner*rInner) + rInner*rInner);
x = r * Math.cos(theta);
z = r * Math.sin(theta); // 环在水平面(这里让它倾斜一点)
y = (Math.random() - 0.5) * 0.5; // 薄环
// 倾斜环
const tilt = 0.4; // 弧度
const yt = y * Math.cos(tilt) - z * Math.sin(tilt);
const zt = y * Math.sin(tilt) + z * Math.cos(tilt);
y = yt; z = zt;
}
break;
case 'buddha':
// 简化的禅修人像 (Procedural Composition)
// 头部(球) + 身体(椭球) + 盘腿(圆环/椭圆)
{
const dice = Math.random();
if (dice < 0.15) {
// Head
const r = 2.5 * Math.cbrt(Math.random());
x = r * Math.sin(phi) * Math.cos(theta);
y = r * Math.sin(phi) * Math.sin(theta) + 6; // Lift up
z = r * Math.cos(phi);
} else if (dice < 0.55) {
// Body
const r = 4.0 * Math.cbrt(Math.random());
x = r * Math.sin(phi) * Math.cos(theta);
y = (r * Math.sin(phi) * Math.sin(theta)) * 1.2; // Stretch Y slightly
z = r * Math.cos(phi) * 0.8; // Flatten Z
} else {
// Legs/Base
const r = 5.5 * Math.sqrt(Math.random());
x = r * Math.cos(theta);
z = r * Math.sin(theta) * 0.7;
y = (Math.random() - 1) * 2 - 3; // Bottom area
}
}
break;
case 'firework':
// 爆炸形态 (Burst)
{
const r = 15 * Math.cbrt(Math.random());
// 集中在中心,也有边缘散落
x = r * Math.sin(phi) * Math.cos(theta);
y = r * Math.sin(phi) * Math.sin(theta);
z = r * Math.cos(phi);
// 增加一些射线效果
if (Math.random() > 0.9) {
x *= 1.5; y *= 1.5; z *= 1.5;
}
}
break;
case 'portal':
// 星门:多层椭圆环
{
const ring = Math.floor(Math.random() * 4);
const r = 6 + ring * 2.4 + Math.sin(theta * 6) * 0.5;
x = r * Math.cos(theta);
y = r * Math.sin(theta) * 0.72;
z = (Math.random() - 0.5) * 1.4 + Math.sin(theta * 3) * 0.4;
}
break;
case 'sword':
// 剑阵:多条平行剑光
{
const lane = Math.floor(Math.random() * 7) - 3;
const t = Math.random() * 2 - 1;
x = t * 12;
y = lane * 1.2 + Math.sin(t * Math.PI * 4 + lane) * 0.45;
z = (Math.random() - 0.5) * 2.4;
if (Math.random() > 0.88) {
y += 2.8;
x *= 0.72;
}
}
break;
case 'beam':
// 光柱:竖向能量束
{
const h = Math.random() * 18 - 9;
const radius = 0.6 + Math.pow(Math.random(), 2) * 3.4;
x = Math.cos(theta) * radius;
z = Math.sin(theta) * radius;
y = h + Math.sin(h * 2.2) * 0.4;
}
break;
case 'spiral':
// 星河:双螺旋飞掠
{
const arm = Math.random() > 0.5 ? 1 : -1;
const t = Math.random() * Math.PI * 5;
const r = 0.8 + t * 0.85;
x = Math.cos(t * arm) * r;
z = Math.sin(t * arm) * r;
y = (Math.random() - 0.5) * 5 + Math.sin(t) * 1.2;
}
break;
default:
x = y = z = 0;
}
return { x, y, z };
}
function generateShape(shapeType) {
currentShape = shapeType;
for (let i = 0; i < PARTICLE_COUNT; i++) {
const p = getPointOnShape(shapeType, i, PARTICLE_COUNT);
basePositions[i * 3] = p.x;
basePositions[i * 3 + 1] = p.y;
basePositions[i * 3 + 2] = p.z;
}
// 当切换模型时,我们重置一下基础位置,但在动画循环中会应用手势缩放
// 目标位置的更新逻辑主要在 animate 函数中结合手势系数实时计算
}
// ================= MediaPipe Hands 设置 =================
const videoElement = document.getElementById('input_video');
function dist(a, b) {
const dx = a.x - b.x;
const dy = a.y - b.y;
return Math.sqrt(dx * dx + dy * dy);
}
function fingerOpen(landmarks, tip, pip) {
return landmarks[tip].y < landmarks[pip].y - 0.018;
}
function thumbOpen(landmarks) {
const palmWidth = Math.max(0.001, dist(landmarks[5], landmarks[17]));
return dist(landmarks[4], landmarks[9]) > palmWidth * 0.72 && dist(landmarks[4], landmarks[3]) > palmWidth * 0.18;
}
function analyzeHand(landmarks) {
const thumb = thumbOpen(landmarks);
const index = fingerOpen(landmarks, 8, 6);
const middle = fingerOpen(landmarks, 12, 10);
const ring = fingerOpen(landmarks, 16, 14);
const pinky = fingerOpen(landmarks, 20, 18);
const openCount = [thumb, index, middle, ring, pinky].filter(Boolean).length;
const palmWidth = Math.max(0.001, dist(landmarks[5], landmarks[17]));
const pinch = dist(landmarks[4], landmarks[8]) < palmWidth * 0.42;
return {
openCount,
pinch,
fist: openCount === 0,
openPalm: openCount >= 4,
twoFinger: index && middle && !ring && !pinky,
thumbUp: thumb && !index && !middle && !ring && !pinky
};
}
function setActiveShape(shape) {
if (shape === currentShape) return;
generateShape(shape);
document.querySelectorAll('.shape-btn').forEach(btn => {
btn.classList.toggle('active', btn.getAttribute('data-shape') === shape);
});
}
function applyGesture(name, scale, spin = 0.002, stableFrames = 1) {
if (name !== gestureCandidate) {
gestureCandidate = name;
gestureCandidateCount = 1;
if (stableFrames > 1) return;
} else {
gestureCandidateCount++;
if (gestureCandidateCount < stableFrames) return;
}
currentGestureName = name;
targetHandScale = scale;
targetRotationBoost = spin;
handStateEl.innerText = name;
}
function onHandsResults(results) {
// 更新预览 Canvas
previewCanvas.width = videoElement.videoWidth;
previewCanvas.height = videoElement.videoHeight;
previewCtx.save();
previewCtx.clearRect(0, 0, previewCanvas.width, previewCanvas.height);
previewCtx.drawImage(results.image, 0, 0, previewCanvas.width, previewCanvas.height);
if (results.multiHandLandmarks && results.multiHandLandmarks.length > 0) {
isHandDetected = true;
statusEl.innerText = "已检测到手势 - 可尝试张掌/握拳/捏合/双指/拇指/双手";
statusEl.style.color = "#00ff00";
// 绘制骨架(可选,为了性能只绘制第一只手)
drawConnectors(previewCtx, results.multiHandLandmarks[0], HAND_CONNECTIONS, {color: '#00FF00', lineWidth: 2});
// --- 识别大手势并触发形态 ---
const landmarks = results.multiHandLandmarks[0];
const now = performance.now();
if (results.multiHandLandmarks.length >= 2) {
const leftPalm = results.multiHandLandmarks[0][9];
const rightPalm = results.multiHandLandmarks[1][9];
const handGap = dist(leftPalm, rightPalm);
if (handGap < 0.24) {
applyGesture('双手靠近:收束旋涡', 0.52, 0.024, 1);
} else if (handGap > 0.46) {
applyGesture('双手拉开:空间展开', 2.35, 0.012, 1);
}
} else {
const signal = analyzeHand(landmarks);
const palmX = landmarks[9].x;
if (lastPalmX !== null && Math.abs(palmX - lastPalmX) > 0.11) {
waveUntil = now + 560;
}
lastPalmX = palmX;
if (now < waveUntil) {
applyGesture('横向挥手:飞掠加速', 2.05, 0.032, 1);
} else if (signal.pinch && !signal.openPalm) {
applyGesture('捏合:聚能收缩', 0.36, 0.008, 1);
} else if (signal.thumbUp) {
applyGesture('拇指:能量升腾', 1.62, 0.014, 1);
} else if (signal.twoFinger) {
applyGesture('双指:锐化展开', 1.55, 0.02, 1);
} else if (signal.fist) {
applyGesture('握拳:核心压缩', 0.28, 0.028, 1);
} else if (signal.openPalm) {
applyGesture('张掌:星云扩散', 2.45, 0.007, 1);
}
}
scaleValEl.innerText = targetHandScale.toFixed(2);
} else {
isHandDetected = false;
lastPalmX = null;
statusEl.innerText = "未检测到手势,请在摄像头前举起单手";
statusEl.style.color = "#00d2ff";
handStateEl.innerText = "未检测";
// 如果没检测到手,缓慢恢复到默认大小
targetHandScale = 1.0;
targetRotationBoost = 0.002;
}
previewCtx.restore();
}
const hands = new Hands({locateFile: (file) => {
return `https://cdn.jsdelivr.net/npm/@mediapipe/hands/${file}`;
}});
hands.setOptions({
maxNumHands: 2,
modelComplexity: 0,
minDetectionConfidence: 0.55,
minTrackingConfidence: 0.55
});
hands.onResults(onHandsResults);
// 开启摄像头
const cameraUtils = new Camera(videoElement, {
onFrame: async () => {
await hands.send({image: videoElement});
},
width: 320, // 低分辨率处理以提高性能
height: 240
});
// 启动处理(需在此之后初始化)
cameraUtils.start().catch(err => {
statusEl.innerText = "摄像头访问失败,请检查权限。";
statusEl.style.color = "red";
});
// ================= UI 交互逻辑 =================
// 形状切换
document.getElementById('shape-buttons').addEventListener('click', (e) => {
if (e.target.classList.contains('shape-btn')) {
// UI 更新
document.querySelectorAll('.shape-btn').forEach(b => b.classList.remove('active'));
e.target.classList.add('active');
// 逻辑更新
const shape = e.target.getAttribute('data-shape');
generateShape(shape);
}
});
// 颜色切换
const colorPicker = document.getElementById('color-picker');
colorPicker.addEventListener('input', (e) => {
currentColor.set(e.target.value);
if (material) material.color = currentColor;
});
// 全屏切换
document.getElementById('fullscreen-btn').addEventListener('click', () => {
if (!document.fullscreenElement) {
document.documentElement.requestFullscreen();
} else {
if (document.exitFullscreen) {
document.exitFullscreen();
}
}
});
// ================= 动画循环 =================
function animate() {
requestAnimationFrame(animate);
// 1. 平滑手势缩放系数 (Lerp)
// 延迟 <= 100ms 意味着我们需要较快的响应速度
// simple lerp: current += (target - current) * speed
handScaleFactor += (targetHandScale - handScaleFactor) * HAND_SENSITIVITY;
// 更新UI显示数值
scaleValEl.innerText = handScaleFactor.toFixed(2);
// 2. 更新粒子位置
const positions = particles.geometry.attributes.position.array;
// 缓慢旋转整体,手势只改变当前模型的互动强度,不切换模型
rotationBoost += (targetRotationBoost - rotationBoost) * 0.2;
particles.rotation.y += rotationBoost;
// 如果是土星,稍微倾斜一点旋转
if (currentShape === 'saturn') {
particles.rotation.z = 0.3;
} else {
particles.rotation.z += (0 - particles.rotation.z) * 0.05; // 复位
}
for (let i = 0; i < PARTICLE_COUNT; i++) {
const ix = i * 3;
const iy = i * 3 + 1;
const iz = i * 3 + 2;
// 获取基础形状的目标位置
const bx = basePositions[ix];
const by = basePositions[iy];
const bz = basePositions[iz];
// 应用手势缩放
// 扩散效果:位置 * 缩放系数
const tx = bx * handScaleFactor;
const ty = by * handScaleFactor;
const tz = bz * handScaleFactor;
// 粒子插值移动 (Morphing transition)
// 这里同时处理了 "形状切换的过渡" 和 "手势缩放的实时性"
// positions[ix] 是当前渲染位置
positions[ix] += (tx - positions[ix]) * TRANSITION_SPEED;
positions[iy] += (ty - positions[iy]) * TRANSITION_SPEED;
positions[iz] += (tz - positions[iz]) * TRANSITION_SPEED;
}
particles.geometry.attributes.position.needsUpdate = true;
renderer.render(scene, camera);
}
// 启动
initThree();
animate();
</script>
</body>
</html>
AI 3D粒子动态交互,codex,gamini,提示词
- 创建一个基本的3D场景,包括相机、光源和渲染器。
- 创建粒子系统:使用Three.js的粒子系统功能,生成大量粒子,并为每个粒子设置位置、颜色和大小等属性。
- 实现手势控制:结合手势识别技术,允许用户通过手势来控制粒子的行为,例如改变粒子的运动方向或大小。
- 渲染和动画:使用动态循环,不断更新粒子的位置和状态,以实现动态效果。
------本页内容已结束,喜欢请分享------
感谢您的来访,获取更多精彩文章请收藏本站。
-
TOP1
AI 3D粒子动态交互,手势操作
-
TOP2
2026.06.01 GitHub热点·今日必看十大开源项目
-
TOP3
2026.06.02 GitHub热点·今日必看十大开源项目
-
TOP4
2026.06.03 GitHub热点·今日必看十大开源项目
-
TOP5
GitHub 升星最快 TOP10 AI 量化交易系统
-
TOP6
2026.06.04 GitHub热点·今日必看十大开源项目
-
TOP7
2026.06.04 GitHub热点·今日必看开源项目
-
TOP8
2026.07.05 GitHub每日热点·精选十大开源项目
-
TOP9
2026.07.06 GitHub每日热点·精选十大开源项目
-
TOP10
2026.07.07 GitHub每日热点·精选十大开源项目
微信扫一扫分享
打开微信「扫一扫」,扫描二维码分享给好友或朋友圈
二维码生成失败,已为你复制链接,请在微信中粘贴分享。



