zoukankan      html  css  js  c++  java
  • three.js cannon.js物理引擎之制作拥有物理特性的汽车

    今天郭先生说一说使用cannon.js的车辆辅助类让我们的汽车模型拥有物理特性。效果图如下,在线案例请点击博客原文

    下面我们说一下今天要使用的两个类,并简单的看看他们的物理意义

    1. RaycastVehicle类

    这是车辆辅助类,将光线从车轮位置投射到地面并施加力。它决定车的位置,角度,质量等信息。下面是它的构造函数

    RaycastVehicle ( [options] )

    options一共有四个参数,并且比较好理解,

    • chassisBody – 表示车身的刚体
    • indexForwardAxis – 前轴索引0 = x,1 = y,2 = z
    • indexRightAxis – 前轴索引0 = x,1 = y,2 = z
    • indexUpAxis – 前轴索引0 = x,1 = y,2 = z

    后面的三个参数要决定了车辆哪个方向是前面,,哪个是右面,哪个是上面。比如说我们在three.js中一般以y轴作为向上的方向,因此我们就要将indexUpAxis设置成1,indexRightAxis设置成2。如果有特别的要求,three.js的视图以z轴作为up的方向,这是我们就要将indexUpAxis设置成2,indexRightAxis设置成1(cannon的默认值就是将z轴的方向作为up的方向的)。RaycastVehicle就先说到这,它的一些属性和方向请查看文档。

    2. WheelInfo类

    这个是车轮类,里面包含了十分丰富的信息,包括车轮相对于车的位置,车轮半径,滚动影响,转弯滑动等等信息,下面我们看一下构造函数

    WheelInfo ( [options] )

    这个options就很复杂了,可以在我的例子中手动调试。下面我们还是通过案例代码来学习这两个类。

    3. 案例代码

    先看看物理引擎的部分

    var carBodySize = new THREE.Vector3(4.52, 2.26, 1.08);
    var wheelRadius = 0.5;
    initCannon() {
            //初始物理里世界
        world = new CANNON.World();
        world.quatNormalizeSkip = 0;
        world.quatNormalizeFast = false;
        world.gravity.set(0, 0, -9.8);
        world.broadphase = new CANNON.NaiveBroadphase();
        world.solver.iterations = 10;
        world.defaultContactMaterial.friction = 0;
            //定义车体形状
        var chassisShape;
            //车体为一个矩形
        chassisShape = new CANNON.Box(new CANNON.Vec3(carBodySize.x/2, carBodySize.y/2, carBodySize.z/2));
            //定义车体刚体
        var chassisBody = new CANNON.Body({mass: 150, material: new CANNON.Material({friction: 0, restitution: 0})})
            //刚体中添加形状
        chassisBody.addShape(chassisShape);
            //初始化刚体的位置
        chassisBody.position.set(0, 0, 5);
            //设置一个初始的角速度
        chassisBody.angularVelocity.set(0, 0, 0.5);
            //初始化车辆引擎
        vehicle = new CANNON.RaycastVehicle({
            chassisBody: chassisBody, indexForwardAxis: 0, indexRightAxis: 1, indexUpAxis: 2
        });
    
        var options = {
            radius: wheelRadius,
            directionLocal: new CANNON.Vec3(0, 0, -wheelRadius * 2),
            suspensionStiffness: 30,
            suspensionRestLength: 0.3,
            frictionSlip: 5,
            dampingRelaxation: 2.3,
            dampingCompression: 4.4,
            maxSuspensionForce: 100000,
            rollInfluence:  0.01,
            axleLocal: new CANNON.Vec3(0, 1, 0),
            chassisConnectionPointLocal: new CANNON.Vec3(1, 1, 0),
            maxSuspensionTravel: 0.3,
            customSlidingRotationalSpeed: -30,
            useCustomSlidingRotationalSpeed: true
        };
        //设置第一个轮的位置,并将轮子信息添加到车辆类中
        options.chassisConnectionPointLocal.set(1.13, 0.95, -0.1);
        vehicle.addWheel(options);
            //设置第二个轮的位置,并将轮子信息添加到车辆类中
        options.chassisConnectionPointLocal.set(1.13, -0.95, -0.1);
        vehicle.addWheel(options);
            //设置第三个轮的位置,并将轮子信息添加到车辆类中
        options.chassisConnectionPointLocal.set(-1.47, 0.95, -0.05);
        vehicle.addWheel(options);
            //设置第四个轮的位置,并将轮子信息添加到车辆类中
        options.chassisConnectionPointLocal.set(-1.47, -0.95, -0.05);
        vehicle.addWheel(options);
            //通过addToWorld方法将将车辆及其约束添加到世界上。
        vehicle.addToWorld(world);
            //高度场的方法,上节已经了解了,不多说
        var matrix = [];
        for (var i = 0; i < size; i++) {
            matrix.push([]);
            for (var j = 0; j < size; j++) {
                var height = Math.cos(i / size * Math.PI * (size / 10)) * Math.cos(j / size * Math.PI * (size / 10)) / 2;
                matrix[i].push(height)
            }
        }
        var hfShape = new CANNON.Heightfield(matrix, {
            elementSize: 1
        });
        var hfBody = new CANNON.Body({ mass: 0, material: new CANNON.Material({friction: 0.5, restitution: 0})});
        hfBody.addShape(hfShape, new CANNON.Vec3(-size / 2, - size / 2, 0), new CANNON.Quaternion());
        world.addBody(hfBody);
    },

    接下来是操作小汽车的一些代码

    document.onkeydown = this.handler;
    document.onkeyup = this.handler;
    handler(event) {
        var up = (event.type == 'keyup');
        if(!up && event.type !== 'keydown'){
            return;
        }
    
        vehicle.setBrake(0, 0);
        vehicle.setBrake(0, 1);
        vehicle.setBrake(0, 2);
        vehicle.setBrake(0, 3);
    
        switch(event.keyCode){
            case 38: // 按下向前键时,通过applyEngineForce方法,设置车轮力以在每个步骤中施加在后车轮上
                vehicle.applyEngineForce(up ? 0 : -params.maxForce, 2);
                vehicle.applyEngineForce(up ? 0 : -params.maxForce, 3);
                break;
    
            case 40: // 同上
                vehicle.applyEngineForce(up ? 0 : params.maxForce, 2);
                vehicle.applyEngineForce(up ? 0 : params.maxForce, 3);
                break;
    
            case 66: // 刹车键b,通过setBrake方法,设置四个车轮的制动力
                vehicle.setBrake(brakeForce, 0);
                vehicle.setBrake(brakeForce, 1);
                vehicle.setBrake(brakeForce, 2);
                vehicle.setBrake(brakeForce, 3);
                break;
    
            case 39: // 按下右键,通过setSteeringValue方法,设置前轮转向值
                vehicle.setSteeringValue(up ? 0 : -maxSteerVal, 0);
                vehicle.setSteeringValue(up ? 0 : -maxSteerVal, 1);
                break;
    
            case 37: // 同上
                vehicle.setSteeringValue(up ? 0 : maxSteerVal, 0);
                vehicle.setSteeringValue(up ? 0 : maxSteerVal, 1);
                break;
            }
    },

    好的这就是主要代码,小车是在THREE的官方demo上面下载的。

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

  • 相关阅读:
    触发器
    变量
    Python 3.6 抓取微博m站数据
    Linux cp/rm/mv 强制覆盖
    Oracle的CLOB大数据字段类型
    4、NameNode启动过程详解
    2、HDFS交互式Shell
    1、HDFS 架构、启动过程
    11、 Hadoop 2.x各个服务组件如何配置在那台服务器运行并测试
    10、Hadoop组件启动方式和SSH无密码登陆
  • 原文地址:https://www.cnblogs.com/vadim-web/p/14355895.html
Copyright © 2011-2022 走看看