学习threejs,使用Physijs物理引擎,通过控制重力,实现多米诺骨牌效果

👨‍⚕️ 主页: gis分享者
👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅!
👨‍⚕️ 收录于专栏:threejs gis工程师



一、🍀前言

本文详细介绍如何基于threejs在三维场景中使用Physijs物理引擎,通过控制重力,实现多米诺骨牌效果,亲测可用。希望能帮助到您。一起学习,加油!加油!

1.1 ☘️Physijs 物理引擎

Three.js 的 Physi.js 是一个基于 Physijs 的物理引擎插件,用于为 Three.js 场景添加物理模拟(如碰撞检测、重力、刚体动力学等)。

1.1.1 ☘️代码示例

// 初始化 Physi.js 场景
const scene = new Physijs.Scene();

// 创建带有物理效果的立方体
const box = new Physijs.BoxMesh(
  new THREE.BoxGeometry(1, 1, 1),
  new THREE.MeshBasicMaterial({ color: 0xff0000 })
);
scene.add(box);

// 监听碰撞事件
box.addEventListener('collision', (otherObject) => {
  console.log('发生碰撞!', otherObject);
});

// 在动画循环中更新物理
function animate() {
  requestAnimationFrame(animate);
  scene.simulate(); // 更新物理模拟
  renderer.render(scene, camera);
}
animate();

1.1.2 ☘️方法/属性

Physijs.Scene
创建支持物理的 Three.js 场景。

mesh.setLinearVelocity()
设置物体的线性速度(移动速度)。

mesh.setAngularVelocity()
设置物体的角速度(旋转速度)。

mesh.addEventListener()
监听碰撞事件(如 ‘collision’)。

new Physijs.BoxMesh()
创建带有长方体碰撞体的物体。

new Physijs.SphereMesh()
创建带有球体碰撞体的物体。

scene.simulate()
在渲染循环中调用,更新物理模拟。

Physijs.createMaterial(material, friction, restitution)
创建物理材质,影响摩擦力和弹性。
参数:
material:Three.js 材质(如 THREE.MeshPhongMaterial)。
friction:摩擦系数(默认 0.8)。
restitution:弹性系数(默认 0)。

二、🍀使用Physijs物理引擎,通过控制重力,实现多米诺骨牌效果

1. ☘️实现思路

  • 1、引入‘physi.js’,创建Physijs物理引擎三维场景scene,设置scene场景重力信息。
  • 2、初始化camera相机,定义相机位置 camera.position.set,设置相机方向camera.lookAt,场景scene添加camera。
  • 3、创建THREE.SpotLight聚光灯光源light,设置light位置,scene场景加入light。
  • 4、加载几何模型:定义createGround方法,使用‘wood-2.jpg’贴图创建二维平面网格对象,用于模拟木质地面,限制物理引擎影像范围。定义controls方法,内部加载环状布局立方体碰撞对象,定义gravityX、gravityY、gravityZ用于控制Physijs物理引擎的重力属性。调用createGround方法。定义render方法,进行三维场景的渲染。具体代码参考下面代码样例。
  • 5、加入gui控制。加入stats监控器,监控帧数信息。

2. ☘️代码样例

<!DOCTYPE html>
<html>
<style>
    body {
        margin: 0;
        overflow: hidden;
    }
</style>

<head>
    <title>学习threejs,使用Physijs物理引擎,通过控制重力,实现多米诺骨牌效果</title>
    <script type="text/javascript" src="../libs/three.js"></script>
    <script type="text/javascript" src="../libs/stats.js"></script>
    <script type="text/javascript" src="../libs/physi.js"></script>
    <script type="text/javascript" src="../libs/chroma.js"></script>
    <script type="text/javascript" src="../libs/dat.gui.js"></script>
    <script type="text/javascript">

        'use strict';

        var scale = chroma.scale(['green', 'white']);

        Physijs.scripts.worker = '../libs/physijs_worker.js';
        Physijs.scripts.ammo = '../libs/ammo.js';

        var initScene, render, applyForce, setMousePosition, mouse_position,
                ground_material, box_material,
                renderer, render_stats, scene, ground, light, camera, box, boxes = [];

        initScene = function () {

            renderer = new THREE.WebGLRenderer({antialias: true});
            renderer.setSize(window.innerWidth, window.innerHeight);

            renderer.setClearColor(new THREE.Color(0x000000));
            document.getElementById('viewport').appendChild(renderer.domElement);

            render_stats = new Stats();
            render_stats.domElement.style.position = 'absolute';
            render_stats.domElement.style.top = '1px';
            render_stats.domElement.style.zIndex = 100;
            document.getElementById('viewport').appendChild(render_stats.domElement);

            scene = new Physijs.Scene;
            scene.setGravity(new THREE.Vector3(0, -50, 0));

            camera = new THREE.PerspectiveCamera(
                    35,
                    window.innerWidth / window.innerHeight,
                    1,
                    1000
            );
            camera.position.set(50, 30, 50);
            camera.lookAt(new THREE.Vector3(10, 0, 10));
            scene.add(camera);

            // 创建聚光灯光源light,设置light的位置,scene添加light
            light = new THREE.SpotLight(0xFFFFFF);
            light.position.set(20, 100, 50);


            scene.add(light);

            createGround();

            var points = getPoints();
            var stones = [];


            requestAnimationFrame(render);

            var controls = new function () {
                this.gravityX = 0;
                this.gravityY = -50;
                this.gravityZ = 0;


                this.resetScene = function () {

                    scene.setGravity(new THREE.Vector3(controls.gravityX, controls.gravityY, controls.gravityZ));
                    stones.forEach(function (st) {
                        scene.remove(st)
                    });
                    stones = [];


                    points.forEach(function (point) {
                        var stoneGeom = new THREE.BoxGeometry(0.6, 6, 2);

                        var stone = new Physijs.BoxMesh(stoneGeom, Physijs.createMaterial(new THREE.MeshPhongMaterial(
                                {
                                    color: scale(Math.random()).hex(),
                                    transparent: true, opacity: 0.8
                                })));
                        console.log(stone.position);
                        stone.position.copy(point);
                        stone.lookAt(scene.position);
                        stone.__dirtyRotation = true;
                        stone.position.y = 3.5;

                        scene.add(stone);
                        stones.push(stone);

                    });

                    // let the first one fall down
                    stones[0].rotation.x = 0.2;
                    stones[0].__dirtyRotation = true;

                };
            };

            var gui = new dat.GUI();
            gui.add(controls, 'gravityX', -100, 100);
            gui.add(controls, 'gravityY', -100, 100);
            gui.add(controls, 'gravityZ', -100, 100);
            gui.add(controls, 'resetScene');

            controls.resetScene();
        };

        var stepX;

        render = function () {
            requestAnimationFrame(render);
            renderer.render(scene, camera);
            render_stats.update();
            scene.simulate(undefined, 1);
        };

        function getPoints() {
            var points = [];
            var r = 27;
            var cX = 0;
            var cY = 0;
            var circleOffset = 0;
            for (var i = 0; i < 1000; i += 6 + circleOffset) {
                circleOffset = 4.5 * (i / 360);
                var x = (r / 1440) * (1440 - i) * Math.cos(i * (Math.PI / 180)) + cX;
                var z = (r / 1440) * (1440 - i) * Math.sin(i * (Math.PI / 180)) + cY;
                var y = 0;
                points.push(new THREE.Vector3(x, y, z));
            }

            return points;
        }

        function createGround() {
            var ground_material = Physijs.createMaterial(
                    new THREE.MeshPhongMaterial({map: THREE.ImageUtils.loadTexture('../assets/textures/general/wood-2.jpg')}),
                    .9, .3);

            var ground = new Physijs.BoxMesh(new THREE.BoxGeometry(60, 1, 60), ground_material, 0);

            var borderLeft = new Physijs.BoxMesh(new THREE.BoxGeometry(2, 3, 60), ground_material, 0);
            borderLeft.position.x = -31;
            borderLeft.position.y = 2;
            ground.add(borderLeft);

            var borderRight = new Physijs.BoxMesh(new THREE.BoxGeometry(2, 3, 60), ground_material, 0);
            borderRight.position.x = 31;
            borderRight.position.y = 2;
            ground.add(borderRight);

            var borderBottom = new Physijs.BoxMesh(new THREE.BoxGeometry(64, 3, 2), ground_material, 0);
            borderBottom.position.z = 30;
            borderBottom.position.y = 2;
            ground.add(borderBottom);

            var borderTop = new Physijs.BoxMesh(new THREE.BoxGeometry(64, 3, 2), ground_material, 0);
            borderTop.position.z = -30;
            borderTop.position.y = 2;
            ground.add(borderTop);
            scene.add(ground);
        }

        window.onload = initScene;

    </script>
</head>

<body>
<div id="viewport"></div>
</body>

</html>

效果如下:
在这里插入图片描述

内容概要:本文档《opencv高频面试题.docx》涵盖了OpenCV的基础概念、图像处理操作、特征提取与匹配、目标检测与机器学习、实际编程题、性能优化以及进阶问题。首先介绍了OpenCV作为开源计算机视觉库,支持图像/视频处理、目标检测、机器学习等领域,应用于安防、自动驾驶、医学影像、AR/VR等方面。接着详细讲述了图像的存储格式(如Mat类)、通道的概念及其转换方法。在图像处理部分,讲解了图像灰度化、二值化、边缘检测等技术。特征提取方面,对比了Harris和Shi-Tomasi角点检测算法,以及SIFT、SURF、ORB的特征提取原理和优缺点。目标检测部分介绍了Haar级联检测原理,并阐述了如何调用深度学习模型进行目标检测。文档还提供了几个实际编程题示例,如读取并显示图像、图像旋转、绘制矩形框并保存等。最后,探讨了性能优化的方法,如使用cv2.UMat(GPU加速)、减少循环等,以及相机标定、光流等进阶问题。 适合人群:对计算机视觉有一定兴趣,具备一定编程基础的学习者或从业者。 使用场景及目标:①帮助学习者掌握OpenCV的基本概念和技术;②为面试准备提供参考;③为实际项目开发提供技术指导。 阅读建议:由于内容涵盖广泛,建议读者根据自身需求有选择地深入学习相关章节,并结合实际编程练习加深理解。
评论 55
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gis分享者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值