2

私は Physijs を使用して、メッシュ間の静的衝突を決定しています。どのサーフェスが交差しているかを知る必要があるためです。

動作するように見える簡単なデモをハックしました。

現在、重力を使用するようにシーンを構成する必要があります。これにより、メッシュが落下または浮遊し始めるときに、メッシュを任意の y 位置に配置できなくなります。

シミュレーションから重力を取り除き、メッシュ衝突検出だけを使用する簡単な方法はありますか?

--更新--- 各メッシュの質量を空白ではなく 0 に明示的に設定する必要がありました。mass=0 の場合、重力は影響しません。すごい!

ただし、メッシュは衝突を報告していません。私が間違っているアイデアはありますか?

ありがとう

-lp

4

1 に答える 1

2

Physijs を衝突検出だけに使用することはできません。ammo.js ライブラリに基づくリアルタイムの物理シミュレーションが完全に装備されています。メッシュの質量を に設定すると、メッシュは0静的になりました。それらは、衝突応答 (つまり、衝突が検出された後にメッシュに適用される速度の変化) や重力などの外力に応答しませんでした。また、互いにオーバーラップする 2 つのスタティック メッシュは衝突イベントを発生させません。

解決策 A: ammo.js を直接使用する

Bullet Physicsから移植されたこのライブラリは、物理シミュレーションを生成したり、定義された形状間の衝突を検出したりするために必要なツールを提供します (Physijs はこれを私たちに見せたくないのです)。2 つの剛体球の間の衝突を検出するためのスニペットを次に示します。

var bt_collision_configuration;
var bt_dispatcher;
var bt_broadphase;
var bt_collision_world;

var scene_size = 500;
var max_objects = 10; // Tweak this as needed

bt_collision_configuration = new Ammo.btDefaultCollisionConfiguration();
bt_dispatcher = new Ammo.btCollisionDispatcher(bt_collision_configuration);

var wmin = new Ammo.btVector3(-scene_size, -scene_size, -scene_size);
var wmax = new Ammo.btVector3(scene_size, scene_size, scene_size);

// This is one type of broadphase, Ammo.js has others that might be faster
bt_broadphase = new Ammo.bt32BitAxisSweep3(
        wmin, wmax, max_objects, 0, true /* disable raycast accelerator */);

bt_collision_world = new Ammo.btCollisionWorld(bt_dispatcher, bt_broadphase, bt_collision_configuration);

// Create two collision objects
var sphere_A = new Ammo.btCollisionObject();
var sphere_B = new Ammo.btCollisionObject();

// Move each to a specific location
sphere_A.getWorldTransform().setOrigin(new Ammo.btVector3(2, 1.5, 0));
sphere_B.getWorldTransform().setOrigin(new Ammo.btVector3(2, 0, 0));

// Create the sphere shape with a radius of 1
var sphere_shape = new Ammo.btSphereShape(1);

// Set the shape of each collision object
sphere_A.setCollisionShape(sphere_shape);
sphere_B.setCollisionShape(sphere_shape);

// Add the collision objects to our collision world
bt_collision_world.addCollisionObject(sphere_A);
bt_collision_world.addCollisionObject(sphere_B);

// Perform collision detection
bt_collision_world.performDiscreteCollisionDetection();

var numManifolds = bt_collision_world.getDispatcher().getNumManifolds();

// For each contact manifold
for(var i = 0; i < numManifolds; i++){
    var contactManifold = bt_collision_world.getDispatcher().getManifoldByIndexInternal(i);
    var obA = contactManifold.getBody0();
    var obB = contactManifold.getBody1();
    contactManifold.refreshContactPoints(obA.getWorldTransform(), obB.getWorldTransform());
    var numContacts = contactManifold.getNumContacts();

    // For each contact point in that manifold
    for(var j = 0; j < numContacts; j++){

        // Get the contact information
        var pt = contactManifold.getContactPoint(j);
        var ptA = pt.getPositionWorldOnA();
        var ptB = pt.getPositionWorldOnB();
        var ptdist = pt.getDistance();

        // Do whatever else you need with the information...
    }
}

// Oh yeah! Ammo.js wants us to deallocate
// the objects with 'Ammo.destroy(obj)'

この C++ コードを、同等の JSコードに変換しました。いくつかの構文が欠落している可能性があるため、Ammo.js API バインディングの変更を確認して、機能しないものがないか確認してください。

解決策 B: THREE のレイ キャスターを使用する

レイ キャスターは精度が低くなりますが、シェイプに追加の頂点数を追加することで精度を上げることができます。2 つのボックス間の衝突を検出するコードを次に示します。

// General box mesh data
var boxGeometry = new THREE.CubeGeometry(100, 100, 20, 1, 1, 1);
var boxMaterial = new THREE.MeshBasicMaterial({color: 0x8888ff, wireframe: true});

// Create box that detects collision
var dcube = new THREE.Mesh(boxGeometry, boxMaterial);

// Create box to check collision with
var ocube = new THREE.Mesh(boxGeometry, boxMaterial);

// Create ray caster
var rcaster = new THREE.Raycaster(new THREE.Vector3(0, 0, 0), new THREE.Vector3(0, 1, 0));

// Cast a ray through every vertex or extremity
for(var vi = 0, l = dcube.geometry.vertices.length; vi < l; vi++){      
    var glovert = dcube.geometry.vertices[vi].clone().applyMatrix4(dcube.matrix);

    var dirv = glovert.sub(dcube.position);

    // Setup ray caster
    rcaster.set(dcubeOrigin, dirv.clone().normalize());

    // Get collision result
    var hitResult = rcaster.intersectObject(ocube);

    // Check if collision is within range of other cube
    if(hitResult.length && hitResult[0].distance < dirv.length()){ 
        // There was a hit detected between dcube and ocube
    }
}

詳細については、次のリンクを参照してください (およびそのソース コードも参照してください)。

于 2016-10-10T19:41:07.680 に答える