马黑黑 发表于 2025-5-7 20:20

Threejs幼儿园几何体喷泉动画代码

代码:

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
        <meta charset="utf-8" />
        <title>ThreeJS示例:方块体和球体运动</title>
</head>
<body style="margin: 0;">

<!-- threejs 模块导入映射目录结构, 里面不能有其它任何多余的东西 -->
<script type="importmap">
        {
                "imports": {
                "three": "https://esm.sh/three@0.176.0?target=es2022",
                "three/addons/": "https://esm.sh/three@0.176.0/addons/"
        }
}
</script>

<script type="module">

// 导入 three 相关模块
import * as THREE from 'three'; // 主库
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; // 相机控制库
import { RapierPhysics } from 'three/addons/physics/RapierPhysics.js'; // 物理引擎库

let camera, scene, renderer; // 相机、场景、渲染器变量
let physics, position; // 物理模拟对象实例话对象、位置向量变量
let boxes, spheres; // 方块体、球体变量

init(); // 运行程序主函数

// 主函数 :异步运行
async function init() {
        // 引入RapierPhysics库并初始化
        physics = await RapierPhysics();
        // 用于设置物体位置的向量
        position = new THREE.Vector3();

        // 初始化场景、相机和渲染器
        camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 100);
        camera.position.set(- 1, 1.5, 2);
        camera.lookAt(0, 0.5, 0);
        scene = new THREE.Scene();
        scene.background = new THREE.Color(0x666666); // 场景背景色

        // 添加光源
        const hemiLight = new THREE.HemisphereLight(); // 半球光
        scene.add(hemiLight);
        const dirLight = new THREE.DirectionalLight(0xffffff, 3); // 方向光
        dirLight.position.set(5, 5, 5); // 方向光位置
        dirLight.castShadow = true; // 允许产生阴影
        dirLight.shadow.camera.zoom = 2; // 阴影缩放
        scene.add(dirLight);

        // 添加地板
        const floor = new THREE.Mesh(
                new THREE.BoxGeometry(10, 5, 10),
                new THREE.ShadowMaterial({color: 0x444444})
        );
        floor.position.y = - 2.5;
        floor.receiveShadow = true;
        floor.userData.physics = {mass: 0}; // 质量为 0
        scene.add(floor);

        // 初始化材质
        const material = new THREE.MeshLambertMaterial();
        const matrix = new THREE.Matrix4();
        const color = new THREE.Color();

        // 初始化盒子实例化网格
        const geometryBox = new THREE.BoxGeometry(0.075, 0.075, 0.075);
        boxes = new THREE.InstancedMesh(geometryBox, material, 400);
        boxes.instanceMatrix.setUsage(THREE.DynamicDrawUsage); // 每帧更新
        boxes.castShadow = true;
        boxes.receiveShadow = true;
        boxes.userData.physics = {mass: 1}; // 质量为 1
        scene.add(boxes);

        // 随机生成盒子的位置和颜色
        for (let i = 0; i < boxes.count; i ++) {
                matrix.setPosition( Math.random() - 0.5, Math.random() * 2, Math.random() - 0.5 );
                boxes.setMatrixAt(i, matrix);
                boxes.setColorAt(i, color.setHex( 0xffffff * Math.random() ));
        }

        // 初始化球体实例化网格
        const geometrySphere = new THREE.IcosahedronGeometry(0.05, 4);
        spheres = new THREE.InstancedMesh(geometrySphere, material, 400);
        spheres.instanceMatrix.setUsage(THREE.DynamicDrawUsage); // 每帧更新
        spheres.castShadow = true;
        spheres.receiveShadow = true;
        spheres.userData.physics = {mass: 1}; // 质量为 1
        scene.add(spheres);

        // 随机生成球体的位置和颜色
        for (let i = 0; i < spheres.count; i ++ ) {
                matrix.setPosition(Math.random() - 0.5, Math.random() * 2, Math.random() - 0.5);
                spheres.setMatrixAt(i, matrix);
                spheres.setColorAt(i, color.setHex( 0xffffff * Math.random() ));
        }

        // 将场景添加到物理引擎
        physics.addScene(scene);

        // 初始化渲染器和性能监控
        renderer = new THREE.WebGLRenderer({antialias: true });
        renderer.setPixelRatio(window.devicePixelRatio);
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.setAnimationLoop(animate); // 循环调用动画函数
        renderer.shadowMap.enabled = true;
        document.body.appendChild(renderer.domElement );

        // 初始化控制器
        const controls = new OrbitControls(camera, renderer.domElement);
        controls.target.y = 0.5;
        controls.update();

        // 每隔1/60秒随机改变盒子和球体的位置
        setInterval( () => {
                let index = Math.floor(Math.random() * boxes.count);
                position.set(0, Math.random() + 1, 0);
                physics.setMeshPosition(boxes, position, index);
                index = Math.floor(Math.random() * spheres.count);
                position.set(0, Math.random() + 1, 0);
                physics.setMeshPosition(spheres, position, index);
        }, 1000 / 60);
}

// 运行动画函数
function animate() {
        renderer.render(scene, camera);
}

</script>

</body>
</html>以上代码可以存为本地 .html 文档,然后用浏览器打开。也可以到我网站的 简易编辑器 运行以查看效果。

代码注释凭我个人理解添加,不一定准确,仅供参考。

花飞飞 发表于 2025-5-7 21:29

画布缩小到一定程度,可以看到球体到透明玻璃地板边缘后下落的场景,宇宙也是有尽头的{:4_173:}

花飞飞 发表于 2025-5-7 21:30

我就看看你写的中文字。。{:4_173:}

杨帆 发表于 2025-5-7 21:54

震撼的演示效果,谢谢老师大佬级分享{:4_191:}

红影 发表于 2025-5-7 22:17

这个好,可以不仅在幼儿园做喷泉了,还能在动物园做{:4_173:}

红影 发表于 2025-5-7 22:18

这个解说真仔细,黑黑辛苦了{:4_187:}

马黑黑 发表于 2025-5-7 23:19

红影 发表于 2025-5-7 22:18
这个解说真仔细,黑黑辛苦了

{:4_190:}

梦江南 发表于 2025-5-8 09:23

很神奇,这就是老师的代码。{:4_190:}

马黑黑 发表于 2025-5-8 12:36

梦江南 发表于 2025-5-8 09:23
很神奇,这就是老师的代码。

这是 three.js 官方代码,我只是略作修改和注释

红影 发表于 2025-5-9 17:30

马黑黑 发表于 2025-5-7 23:19


谢大咖{:4_187:}

马黑黑 发表于 2025-5-9 18:20

红影 发表于 2025-5-9 17:30
谢大咖

{:4_203:}

红影 发表于 2025-5-9 20:45

马黑黑 发表于 2025-5-9 18:20


{:4_187:}

马黑黑 发表于 2025-5-9 21:23

红影 发表于 2025-5-9 20:45


谢花

红影 发表于 2025-5-9 22:44

马黑黑 发表于 2025-5-9 21:23
谢花

不客气{:4_173:}

马黑黑 发表于 2025-5-9 22:50

红影 发表于 2025-5-9 22:44
不客气

应该的

红影 发表于 2025-5-10 10:33

马黑黑 发表于 2025-5-9 22:50
应该的

应该出了那么多效果,星星、战马、喷泉。。。{:4_173:}

马黑黑 发表于 2025-5-10 11:26

红影 发表于 2025-5-10 10:33
应该出了那么多效果,星星、战马、喷泉。。。

{:4_196:}

红影 发表于 2025-5-10 13:40

马黑黑 发表于 2025-5-10 11:26


{:4_187:}

马黑黑 发表于 2025-5-10 14:17

红影 发表于 2025-5-10 13:40

谢花

红影 发表于 2025-5-10 15:07

马黑黑 发表于 2025-5-10 14:17
谢花

别谢,开着的更好{:4_173:}
页: [1] 2 3 4 5
查看完整版本: Threejs幼儿园几何体喷泉动画代码