耗时 2 小时!我复刻了全网超火的通透 3D 水晶球动效,Vue3+Three.js 做出高级视觉特效

之前做的3D文本效果# 别再写死静态文字了!Vue3+Three.js 实现超酷3D流光旋转文字科技感拉满!【附完整源码】有兄弟表示效果太单一,其实那个效果能做的非常炫酷。

核心就是材质上要把握好,重点其实不在技术,而在调色

简单搞一个3D的水晶球弹跳效果,具备一定的物理效果。

需求实现

球体效果相对比较简单,直接使用SphereGeometry创建即可。

主要是重力弹跳的物理效果实现起来比较麻烦,落地回弹的效果通过控制球体高度的正负实现。

另外就是阴影部分,阴影跟随球体的高度进行变化。

最后就是旋转视角和窗口自适应,还是用OrbitControlswindow.resize实现。

物体实现代码

灯光部分拆分成三个部分:环境光、平行光、点光源。

js 复制代码
function addLights() {
    // 环境光:照亮整个场景,无阴影
    const ambient = new THREE.AmbientLight(0xffffff, 0.4)
    scene.add(ambient)

    // 平行光:太阳光效果,能投射阴影
    const dirLight = new THREE.DirectionalLight(0xffffff, 1.3)
    dirLight.position.set(4, 6, 3)    // 光源位置
    dirLight.castShadow = true        // 开启投影
    dirLight.shadow.mapSize.set(2048, 2048) // 阴影清晰度
    dirLight.shadow.radius = 10       // 阴影柔和度
    scene.add(dirLight)

    // 蓝色氛围点光源
    const blueLight = new THREE.PointLight(0x639bff, 1.6, 12)
    blueLight.position.set(-5, 3, 4)
    scene.add(blueLight)

    // 紫色氛围点光源
    const purpleLight = new THREE.PointLight(0xc563ff, 1.4, 12)
    purpleLight.position.set(5, -1, 4)
    scene.add(purpleLight)
}

但是只有光,没有地面无法正常显示物体在光下的投影,所以需要增加地面。

js 复制代码
function createGround() {
    const geo = new THREE.PlaneGeometry(25, 25) // 地面大小
    const mat = new THREE.MeshStandardMaterial({
        color: 0x1e2238,    // 地面颜色
        roughness: 0.75,    // 粗糙度
        metalness: 0.05    // 金属感
    })
    ground = new THREE.Mesh(geo, mat)
    ground.rotation.x = -Math.PI / 2  // 平放地面
    ground.position.y = groundHeight  // 地面位置
    ground.receiveShadow = true       // 允许接收阴影
    scene.add(ground)
}

除此之外就是创建水晶球了,这部分直接使用SphereGeometry创建球体。

然后用MeshPhysicalMaterial增加相应的材质即可。

js 复制代码
function createCrystalBall() {
    // 球体几何体(半径,横向分段,纵向分段)
    const geo = new THREE.SphereGeometry(1, 128, 128)

    // 水晶/玻璃材质(超通透质感)
    const mat = new THREE.MeshPhysicalMaterial({
        color: 0xffffff,        // 基础颜色
        transparent: true,      // 开启透明
        transmission: 0.95,     // 透光率(1=完全透明)
        opacity: 1,            // 不透明度
        roughness: 0,          // 表面光滑度(0=镜面)
        metalness: 0,          // 金属感
        ior: 1.58,             // 折射率(水晶标准值)
        thickness: 1.8,        // 物体厚度
        envMapIntensity: 2.2,  // 环境光反射强度
        clearcoat: 1,          // 表面清漆(更亮)
        clearcoatRoughness: 0  // 清漆光滑度
    })

    ball = new THREE.Mesh(geo, mat)
    ball.castShadow = true    // 允许投射阴影
    ball.receiveShadow = true // 允许接收阴影
    ball.position.y = 3       // 初始高度(从空中落下)
    scene.add(ball)
}

物理弹跳效果

核心代码是通过控制小球的高度变化,实现弹跳效果。

通过控制其下落的速度不断增加,实现重力加速效果。

落地碰撞主要是通过检测小球高度和地面高度,当相等的时候,就认为已经落地了。

js 复制代码
unction updateBallBounce() {
    // 1. 重力效果:速度不断增加
    velocity += gravity

    // 2. 根据速度更新小球 Y 轴位置
    ball.position.y += velocity

    // 3. 落地碰撞检测 + 回弹
    // 小球最低位置 = 地面高度 + 小球半径(防止陷进地里)
    const minHeight = groundHeight + ballRadius
    if (ball.position.y <= minHeight) {
        ball.position.y = minHeight // 重置位置
        velocity = -velocity * bounce // 反向速度 × 弹性(回弹)
    }

    // 4. 小球自动旋转
    ball.rotation.y += 0.005

    // 5. 阴影同步效果:
    // 跳得越高 → 越小越淡
    // 离地面越近 → 越大越浓
    const height = ball.position.y - minHeight
    const shadowScale = THREE.MathUtils.clamp(1.2 - height * 0.15, 0.5, 1.2)
    ball.scale.set(shadowScale, shadowScale, shadowScale)
}

总结

其实场景的搭建非常简单,鼠标操作也是用的封装好的东西。

重点是在物理弹跳效果上,通过控制速度,间接控制小球的高度。

以及小球高度与地面高度的对比实现落地反弹效果。

还有就是模拟真实世界的重力衰减效果,随着不断地反弹落地,最终小球高度完全等于地面高度。

相关推荐
铁皮饭盒1 小时前
今天你会学到这些关键词
前端·后端
oil欧哟1 小时前
🤔 很长时间没写文章了,分享一下最近的一些思考
前端·后端
Hello--_--World2 小时前
Vue指令:v-if vs v-show、v-if 与 v-for 的优先级冲突、自定义指令
前端·javascript·vue.js
神の愛2 小时前
ReactHooks
前端·javascript·react.js
蝎子莱莱爱打怪2 小时前
用好CC,事半功倍!Claude Code 命令大全,黄金命令推荐、多模型配置、实践指南、Hooks 和踩坑记录大全
前端·人工智能·后端
本末倒置1832 小时前
VS Code 这次稳了!CSS Anchor Positioning 彻底终结 WebView 定位卡顿
前端
MonkeyKing71553 小时前
Flutter状态管理实战:全局、局部、页面状态拆分指南
前端·flutter
Panzer_Jack3 小时前
Copiwaifu:一个和 Claude Code、Codex、Copilot 等 AI 编程工具联动的 Live2D 桌宠[特殊字符]
前端·人工智能·copilot·web·live2d·pixi.js·easy-live2d
开源情报局4 小时前
从小红书评论区挖需求:我准备用 opencode 写一个 Chrome 插件
前端·javascript·chrome