zoukankan      html  css  js  c++  java
  • three.js 之cannon.js物理引擎

    今天郭先生说的是一个物理引擎,它十分小巧并且操作简单,没错他就是cannon.js。这些优点都源自于他是基于js编写的,对于js使用者来说cannon.js拥有其他物理引擎没有的纯粹性。从学习成本来看,cannon.js的学习成本比较低,对于新手来说比较友好,因为它有相对完善的api,学习cannon.js之前我们不妨来看看cannon.js的官方网站以及他的API,对于js学习者来说这是十分必要的。官网上面有一些example,他们十分典型并囊括了大多数的知识点,配合api一起学习是个不错的选择。在线案例请点击博客原文。效果如下图,接下来以一个小案例,简单的介绍一下cannon.js。

    1. 初始化three场景

    创建three场景(或者说three世界)来作为物理世界的载体,这一步很简单,主要就是添加渲染器、场景、相机和网格等three元素,没必要多说。

    scene = new THREE.Scene();//step 1 创建场景
    
    camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 1000 );
    camera.position.y = 30;
    camera.position.z = 20;
    camera.lookAt(0,5,0);
    scene.add( camera ); //step 2 场景中添加相机
    
    scene.add(new THREE.AmbientLight(0x888888));
    const light = new THREE.DirectionalLight(0xbbbbbb, 1);
    light.position.set(6, 30, 6);
    scene.add(light); //step 3 场景中添加另种光源
    
    renderer = new THREE.WebGLRenderer({antialias: true});
    renderer.setSize( window.innerWidth, window.innerHeight );
    renderer.shadowMap.enabled = true;
    renderer.setClearColor(0xbfd1e5);
    this.$refs.box.appendChild(renderer.domElement); //step 4 dom中添加渲染器
    
    let groundGeom = new THREE.BoxBufferGeometry(40, 0.2, 40);
    let groundMate = new THREE.MeshPhongMaterial({color: 0xdddddd, map: texture})
    ground = new THREE.Mesh(groundGeom, groundMate);
    ground.position.y = -0.1;
    ground.receiveShadow = true;
    scene.add(ground); //step 5 添加地面网格

    2. 初始化物理世界

    这里是初始化物理世界,我们详细的讲一下他们的用法。

    initCannon() {
        world = new CANNON.World(); //该方法初始化物理世界,里面包含着物理世界的相关数据(如刚体数据,世界中所受外力等等)
        world.gravity.set(0,-9.8,0); //设置物理世界的重力为沿y轴向上-9.8米每二次方秒
        world.broadphase = new CANNON.NaiveBroadphase();//NaiveBroadphase是默认的碰撞检测方式,该碰撞检测速度比较高
        world.solver.iterations = 5;//解算器的迭代次数,更高的迭代次数意味着更加精确同时性能将会降低
    
        bodyGround = new CANNON.Body({ //创建一个刚体(物理世界的刚体数据)
            mass: 0, //刚体的质量,这里单位为kg
            position: new CANNON.Vec3(0, -0.1, 0), //刚体的位置,单位是米
            shape: new CANNON.Box(new CANNON.Vec3(20, 0.1, 20)), //刚体的形状(这里是立方体,立方体的参数是一个包含半长、半宽、半高的三维向量,具体我们以后会说)
            material: new CANNON.Material({friction: 0.05, restitution: 0}) //材质数据,里面规定了摩擦系数和弹性系数
        });
        ground.userData = bodyGround; //将刚体的数据赋值给地面网格的userData属性
        world.addBody(bodyGround); //物理世界添加地面刚体
    },

    3. 向场景中添加网格并向物理世界中添加刚体数据

    这里我们通过setInterval函数我们定时向场景中添加网格并向物理世界中添加刚体数据,

    interval = setInterval(() => {
        this.createBox(); //创建网格和刚体的方法
    }, 200);

    下面是具体的方法

    createBox() {
        let x = Math.random() * 10 - 5;
        let z = Math.random() * 10 - 5;
        let box = new THREE.Mesh( geometry, this.createRandomMaterial() ); //createRandomMaterial创建随机颜色的材质
        box.position.set(x, 20, z);
        scene.add( box ); //创建box,并添加到场景
    
        let bodyBox = new CANNON.Body({
            mass: 1,
            position: new CANNON.Vec3(x, 20, z),
            shape: new CANNON.Box(new CANNON.Vec3(1,1,1)),
            material: new CANNON.Material({friction: 0.1, restitution: 0})
        });//创建一个质量为1kg,位置为(x,20,z),形状为halfSize为1,1,1的正方形刚体,材质中摩擦系数为0.1,弹性系数为0。
        box.userData = bodyBox;//给box的userData属性添加刚体数据
        world.addBody(bodyBox);//在物理世界中添加该刚体
    
        setTimeout(() => { //10秒钟之后在场景中移除box,并在物理世界中移除该刚体
            scene.remove(box);
            box.material.dispose();
            box.geometry.dispose();
            world.removeBody(bodyBox);
        }, 10000)
    },

    4. 根据物理引擎的数据更新three网格数据

    这一步我们逐帧根据物理引擎的数据渲染three场景

    animation() { //requestAnimationFrame动画中调用render方法
        this.globalID = requestAnimationFrame(this.animation);
        this.render();
    },
    render() { //更新性能插件,根据物理引擎数据更新网格数据,最后渲染场景
        stats.update();
        this.updatePhysics();
        renderer.render( scene, camera );
    },
    updatePhysics() { // world.step
        world.step(timeStep); //第一个参数是以固定步长更新物理世界参数(详情请看api)
        scene.children.forEach(d => {//遍历场景中的子对象,如果对象的isMesh属性为true,我们就将更新改对象的position和quaternion属性(他们对应的刚体数据存在对应的userData中)。
            if(d.isMesh == true) {
                d.position.copy(d.userData.position);
                d.quaternion.copy(d.userData.quaternion);
            }
        })
    }

    这样我们就将cannon.js物理引擎应用到了three中。不出意外的话,接下来我会讲解一下官方的examples。

    转载请注明地址:郭先生的博客

  • 相关阅读:
    《玩转.NET Micro Framework 移植基于STM32F10x处理器》内容介绍
    《玩转.NET Micro Framework 移植基于STM32F10x处理器》前言
    《玩转.NET Micro Framework 移植基于STM32F10x处理器》内容介绍
    《玩转.NET Micro Framework 移植基于STM32F10x处理器》微软中国.NET Micro Framework项目组工程师所作之序
    《玩转.NET Micro Framework 移植基于STM32F10x处理器》资源汇总
    《玩转.NET Micro Framework 移植基于STM32F10x处理器》微软中国.NET Micro Framework项目组工程师所作之序
    《玩转.NET Micro Framework 移植基于STM32F10x处理器》前言
    Windows、Linux、ARM、Android、iOS全平台支持的RTMP推流组件libEasyRTMP库接口调用说明
    简单高效易用Windows/Linux/ARM/Android/iOS平台实现RTMP推送组件EasyRTMPAndroid MediaCodec硬编码流程介绍
    RTSP网络监控摄像头如何实现Windows、Linux、ARM、Android、iOS全平台支持的拉RTSP流推出RTMP直播流?
  • 原文地址:https://www.cnblogs.com/vadim-web/p/14293798.html
Copyright © 2011-2022 走看看