[SOLVED] How to properly Setup btgeneric6dofconstraint

var Hinge6dof = pc.createScript('hinge6dof');

Hinge6dof.attributes.add('slot', {
    type: 'entity'
});

Hinge6dof.attributes.add('base', {
    type: 'entity'
});

Hinge6dof.attributes.add('linearLowerLimits', {
    title: 'Linear Lower Limits',
    description: 'Linear limits of the constraint.',
    type: 'vec3',
    default: [-1, -1, -1]
});

Hinge6dof.attributes.add('linearUpperLimits', {
    title: 'Linear Upper Limits',
    description: 'Linear limits of the constraint.',
    type: 'vec3',
    default: [1, 1, 1]
});

Hinge6dof.attributes.add('angularLowerLimits', {
    title: 'Angula Lower Limits',
    description: 'Angular limits of the constraint.',
    type: 'vec3',
    default: [-1, -1, -1]
});

Hinge6dof.attributes.add('angularUpperLimits', {
    title: 'Angular Upper Limits',
    description: 'Angular limits of the constraint.',
    type: 'vec3',
    default: [1, 1, 1]
});

Hinge6dof.attributes.add('breakingThreshold', {
    title: 'Break Threshold',
    description: 'Maximum breaking impulse threshold required to break the constraint.',
    type: 'number',
    default: 1e+30
});

Hinge6dof.attributes.add('enableCollision', {
    title: 'Enable Collision',
    description: 'Enable collision between linked rigid bodies.',
    type: 'boolean',
    default: true
});

Hinge6dof.prototype.initialize = function () {
    this.WorkSpaceBVH = pc.WorkSpace.script.workSpaceBvh;
    this.constraint = null;
    this.entity.hasOptions = true;

    this.maxMotorImpulse = this.initMaxMotorImpulse;
    this.softness = this.initsoftness;
    this.biasFactor = this.initbiasFactor;
    this.relaxationFactor = this.initrelaxationFactor;
    this.breakingThreshold = this.initbreakingThreshold;

    this.entityA = null;
    this.entityB = null;

    this.app.on('Hinge:FindConnections', this.findConnections, this);
    this.app.on('Hinge:Deactivate', this.onDeactivate, this);

    this.app.on('Hinge:SetBreakingThreshold', this.setBreakingThreshold, this);


    this.entity.on('destroy', () => {
        this.app.off('Hinge:FindConnections', this.findConnections, this);
        this.app.off('Hinge:Deactivate', this.onDeactivate, this);
        this.destroyConstraint();
    }, this);

};

Hinge6dof.prototype.findConnections = function () {
    var baseConnection = this.scanSlot(this.base);
    var slotConnection = this.scanSlot(this.slot);

    if (baseConnection.length !== 0 && slotConnection.length !== 0) {
        if (baseConnection[0]._guid !== slotConnection[0]._guid) {
            var entityA = baseConnection[0];
            var entityB = slotConnection[0];

            this.connectBodies(entityA, entityB);
            this.activate();

            this.enabledScanners(false);
        }
    }
};

Hinge6dof.prototype.onDeactivate = function () {
    if (this.constraint) {
        this.destroyConstraint();
    }

    this.enabledScanners(true);
}

Hinge6dof.prototype.setBreakingThreshold = function (breakingThreshold) {
    this.breakingThreshold = breakingThreshold;
}

Hinge6dof.prototype.connectBodies = function (rigidBodyA, rigidBodyB) {
    rigidBodyA.addChildAndSaveTransform(this.entity);

    this.entityA = rigidBodyA;
    this.entityB = rigidBodyB;

    var bodyA = rigidBodyA.rigidbody.body;
    var bodyB = rigidBodyB.rigidbody.body;

    var pivotA = this.entity.getPosition().clone().sub(rigidBodyA.getPosition());
    var pivotB = this.entity.getPosition().clone().sub(rigidBodyB.getPosition());

    this.createConstraint(bodyA, bodyB, pivotA, pivotB, this.entity.forward.normalize(), this.entity.forward.normalize());

}

Hinge6dof.prototype.createConstraint = function (bodyA, bodyB, pcPivotA, pcPivotB, pcAxisA, pcAxisB) {
    if (this.constraint) {
        this.destroyConstraint();
    }

    var v1 = new pc.Vec3();
    var v2 = new pc.Vec3();
    var q = new pc.Quat();
    var m = new pc.Mat4();

    var pivotA = new Ammo.btVector3(pcPivotA.x, pcPivotA.y, pcPivotA.z);

    Utils.getOrthogonalVectors(pcAxisA, v1, v2);
    m.set([
        v1.x, v1.y, v1.z, 0,
        v2.x, v2.y, v2.z, 0,
        pcAxisA.x, pcAxisA.y, pcAxisA.z, 0,
        0, 0, 0, 1
    ]);
    q.setFromMat4(m);

    var quatA = new Ammo.btQuaternion(q.x, q.y, q.z, q.w);
    var frameA = new Ammo.btTransform(quatA, pivotA);

    var pivotB = new Ammo.btVector3(pcPivotB.x, pcPivotB.y, pcPivotB.z);

    Utils.getOrthogonalVectors(pcAxisB, v1, v2);
    m.set([
        v1.x, v1.y, v1.z, 0,
        v2.x, v2.y, v2.z, 0,
        pcAxisB.x, pcAxisB.y, pcAxisB.z, 0,
        0, 0, 0, 1
    ]);
    q.setFromMat4(m);

    var quatB = new Ammo.btQuaternion(q.x, q.y, q.z, q.w);
    var frameB = new Ammo.btTransform(quatB, pivotB);

    this.constraint = new Ammo.btGeneric6DofConstraint(bodyA, bodyB, frameA, frameB, false);

    //Linear
    var lowerLil = new Ammo.btVector3(this.linearLowerLimits.x, this.linearLowerLimits.y, this.linearLowerLimits.z);
    var upperLil = new Ammo.btVector3(this.linearUpperLimits.x, this.linearUpperLimits.y, this.linearUpperLimits.z);

    this.constraint.setLinearLowerLimit(lowerLil);
    this.constraint.setLinearUpperLimit(upperLil);

    //Angular
    var lowerAng = new Ammo.btVector3(this.angularLowerLimits.x, this.angularLowerLimits.y, this.angularLowerLimits.z);
    var upperAng = new Ammo.btVector3(this.angularUpperLimits.x, this.angularUpperLimits.y, this.angularUpperLimits.z);

    this.constraint.setAngularLowerLimit(lowerAng);
    this.constraint.setAngularUpperLimit(upperAng);

    this.constraint.setBreakingImpulseThreshold(this.breakingThreshold);

    console.log(this.linearLowerLimits, this.linearUpperLimits);
    console.log(this.angularLowerLimits, this.angularUpperLimits);

    Ammo.destroy(lowerLil);
    Ammo.destroy(upperLil);
    Ammo.destroy(lowerAng);
    Ammo.destroy(upperAng);

    Ammo.destroy(frameA);
    Ammo.destroy(quatA);
    Ammo.destroy(pivotA);

    Ammo.destroy(frameB);
    Ammo.destroy(quatB);
    Ammo.destroy(pivotB);

    var dynamicsWorld = this.app.systems.rigidbody.dynamicsWorld;
    dynamicsWorld.addConstraint(this.constraint, !this.enableCollision);
};

Hinge6dof.prototype.activate = function () {
    this.entityA.rigidbody.activate();
    this.entityB.rigidbody.activate();
};

Hinge6dof.prototype.destroyConstraint = function () {
    if (this.constraint) {
        var dynamicsWorld = this.app.systems.rigidbody.dynamicsWorld;
        dynamicsWorld.removeConstraint(this.constraint);
        Ammo.destroy(this.constraint);
        this.constraint = null;
    }
};

Hinge6dof.prototype.enabledScanners = function (state) {
    var scanners = this.entity.findByTag('Scanner');
    scanners.forEach((s) => {
        s.enabled = state;
    });
}

Hinge6dof.prototype.scanSlot = function (slot) {
    var scanners = slot.findByTag('Scanner');
    var connectedSet = new Set();

    for (var s = 0; s < scanners.length; s++) {
        var scanner = scanners[s];
        var aabb = scanner.render.meshInstances[0].aabb;

        // Create AABB region
        var region = createAABB(aabb.center, aabb.halfExtents);

        // Query the BVH for nearby entities, filtering directly
        var nEntities = this.WorkSpaceBVH.query('AABB', region, (nEntity) => { return nEntity._guid !== this.entity._guid });

        // Add parent entities to the connected set
        for (var i = 0; i < nEntities.length; i++) {
            connectedSet.add(nEntities[i].parent);
        }
    }

    // Convert the set to an array for final output if needed
    var connected = Array.from(connectedSet);
    return connected;
};


Hinge6dof.prototype.update = function (dt) {

};

What I’m doing wrong ? it just fell off from joint I set All upper and lower limits to vec3(0, 0, 0)

it working fine if I use normal Hinge Constraint

@will might know

1 Like

Here is an example:

https://playcanvas.com/project/1301252/overview/hinge6dof-constraint

Note, I didn’t handle cleaning up allocations to keep example short.

2 Likes

wow thank you !

Edit: It’s Working !!! thanks again !

1 Like