示例#1
0
void
dxJointUniversal::computeInitialRelativeRotations()
{
    if ( node[0].body )
    {
        dVector3 ax1, ax2;
        dMatrix3 R;
        dQuaternion qcross;

        getAxes( ax1, ax2 );

        // Axis 1.
        dRFrom2Axes( R, ax1[0], ax1[1], ax1[2], ax2[0], ax2[1], ax2[2] );
        dRtoQ( R, qcross );
        dQMultiply1( qrel1, node[0].body->q, qcross );

        // Axis 2.
        dRFrom2Axes( R, ax2[0], ax2[1], ax2[2], ax1[0], ax1[1], ax1[2] );
        dRtoQ( R, qcross );
        if ( node[1].body )
        {
            dQMultiply1( qrel2, node[1].body->q, qcross );
        }
        else
        {
            // set joint->qrel to qcross
            for ( int i = 0; i < 4; i++ ) qrel2[i] = qcross[i];
        }
    }
}
示例#2
0
dReal
dxJointUniversal::getAngle2()
{
    if ( node[0].body )
    {
        // length 1 joint axis in global coordinates, from each body
        dVector3 ax1, ax2;
        dMatrix3 R;
        dQuaternion qcross, qq, qrel;

        getAxes( ax1, ax2 );

        // It should be possible to get both angles without explicitly
        // constructing the rotation matrix of the cross.  Basically,
        // orientation of the cross about axis1 comes from body 2,
        // about axis 2 comes from body 1, and the perpendicular
        // axis can come from the two bodies somehow.  (We don't really
        // want to assume it's 90 degrees, because in general the
        // constraints won't be perfectly satisfied, or even very well
        // satisfied.)
        //
        // However, we'd need a version of getHingeAngleFromRElativeQuat()
        // that CAN handle when its relative quat is rotated along a direction
        // other than the given axis.  What I have here works,
        // although it's probably much slower than need be.

        dRFrom2Axes( R, ax2[0], ax2[1], ax2[2], ax1[0], ax1[1], ax1[2] );
        dRtoQ( R, qcross );

        if ( node[1].body )
        {
            dQMultiply1( qq, node[1].body->q, qcross );
            dQMultiply2( qrel, qq, qrel2 );
        }
        else
        {
            // pretend joint->node[1].body->q is the identity
            dQMultiply2( qrel, qcross, qrel2 );
        }

        return - getHingeAngleFromRelativeQuat( qrel, axis2 );
    }
    return 0;
}
示例#3
0
void
dxJointUniversal::getAngles( dReal *angle1, dReal *angle2 )
{
    if ( node[0].body )
    {
        // length 1 joint axis in global coordinates, from each body
        dVector3 ax1, ax2;
        dMatrix3 R;
        dQuaternion qcross, qq, qrel;

        getAxes( ax1, ax2 );

        // It should be possible to get both angles without explicitly
        // constructing the rotation matrix of the cross.  Basically,
        // orientation of the cross about axis1 comes from body 2,
        // about axis 2 comes from body 1, and the perpendicular
        // axis can come from the two bodies somehow.  (We don't really
        // want to assume it's 90 degrees, because in general the
        // constraints won't be perfectly satisfied, or even very well
        // satisfied.)
        //
        // However, we'd need a version of getHingeAngleFromRElativeQuat()
        // that CAN handle when its relative quat is rotated along a direction
        // other than the given axis.  What I have here works,
        // although it's probably much slower than need be.

        dRFrom2Axes( R, ax1[0], ax1[1], ax1[2], ax2[0], ax2[1], ax2[2] );

        dRtoQ( R, qcross );


        // This code is essentialy the same as getHingeAngle(), see the comments
        // there for details.

        // get qrel = relative rotation between node[0] and the cross
        dQMultiply1( qq, node[0].body->q, qcross );
        dQMultiply2( qrel, qq, qrel1 );

        *angle1 = getHingeAngleFromRelativeQuat( qrel, axis1 );

        // This is equivalent to
        // dRFrom2Axes(R, ax2[0], ax2[1], ax2[2], ax1[0], ax1[1], ax1[2]);
        // You see that the R is constructed from the same 2 axis as for angle1
        // but the first and second axis are swapped.
        // So we can take the first R and rapply a rotation to it.
        // The rotation is around the axis between the 2 axes (ax1 and ax2).
        // We do a rotation of 180deg.

        dQuaternion qcross2;
        // Find the vector between ax1 and ax2 (i.e. in the middle)
        // We need to turn around this vector by 180deg

        // The 2 axes should be normalize so to find the vector between the 2.
        // Add and devide by 2 then normalize or simply normalize
        //    ax2
        //    ^
        //    |
        //    |
        ///   *------------> ax1
        //    We want the vector a 45deg
        //
        // N.B. We don't need to normalize the ax1 and ax2 since there are
        //      normalized when we set them.

        // We set the quaternion q = [cos(theta), dir*sin(theta)] = [w, x, y, Z]
        qrel[0] = 0;                // equivalent to cos(Pi/2)
        qrel[1] = ax1[0] + ax2[0];  // equivalent to x*sin(Pi/2); since sin(Pi/2) = 1
        qrel[2] = ax1[1] + ax2[1];
        qrel[3] = ax1[2] + ax2[2];

        dReal l = dRecip( sqrt( qrel[1] * qrel[1] + qrel[2] * qrel[2] + qrel[3] * qrel[3] ) );
        qrel[1] *= l;
        qrel[2] *= l;
        qrel[3] *= l;

        dQMultiply0( qcross2, qrel, qcross );

        if ( node[1].body )
        {
            dQMultiply1( qq, node[1].body->q, qcross2 );
            dQMultiply2( qrel, qq, qrel2 );
        }
        else
        {
            // pretend joint->node[1].body->q is the identity
            dQMultiply2( qrel, qcross2, qrel2 );
        }

        *angle2 = - getHingeAngleFromRelativeQuat( qrel, axis2 );
    }
    else
    {
        *angle1 = 0;
        *angle2 = 0;
    }
}
示例#4
0
void dJointSetUniversalAxis2Offset( dJointID j, dReal x, dReal y, dReal z,
                                   dReal offset1, dReal offset2 )
{
    dxJointUniversal* joint = ( dxJointUniversal* )j;
    dUASSERT( joint, "bad joint argument" );
    checktype( joint, Universal );

    if ( joint->flags & dJOINT_REVERSE )
    {
        setAxes( joint, x, y, z, joint->axis1, NULL );
        offset1 = -offset2;
        offset2 = -offset1;
    }
    else
        setAxes( joint, x, y, z, NULL, joint->axis2 );


    joint->computeInitialRelativeRotations();

    // It is easier to retreive the 2 axes here since
    // when there is only one body B2 (the axes switch position)
    // Doing this way eliminate the need to write the code differently
    // for both case.
    dVector3 ax1, ax2;
    joint->getAxes(ax1, ax2 );



    dQuaternion qAngle;
    dQFromAxisAndAngle(qAngle, ax1[0], ax1[1], ax1[2], offset1);

    dMatrix3 R;
    dRFrom2Axes( R, ax1[0], ax1[1], ax1[2], ax2[0], ax2[1], ax2[2]);

    dQuaternion qcross;
    dRtoQ( R, qcross );

    dQuaternion qOffset;
    dQMultiply0(qOffset, qAngle, qcross);



    dQMultiply1( joint->qrel1, joint->node[0].body->q, qOffset );


    // Calculating the second offset
    dQFromAxisAndAngle(qAngle, ax2[0], ax2[1], ax2[2], offset2);

    dRFrom2Axes( R, ax2[0], ax2[1], ax2[2], ax1[0], ax1[1], ax1[2]);
    dRtoQ( R, qcross );

    dQMultiply1(qOffset, qAngle, qcross);
    if ( joint->node[1].body )
    {
        dQMultiply1( joint->qrel2, joint->node[1].body->q, qOffset );
    }
    else
    {
        joint->qrel2[0] = qcross[0];
        joint->qrel2[1] = qcross[1];
        joint->qrel2[2] = qcross[2];
        joint->qrel2[3] = qcross[3];
    }
}
示例#5
0
void dJointSetUniversalAxis1Offset( dJointID j, dReal x, dReal y, dReal z,
                                   dReal offset1, dReal offset2 )
{
    dxJointUniversal* joint = ( dxJointUniversal* )j;
    dUASSERT( joint, "bad joint argument" );
    checktype( joint, Universal );
    if ( joint->flags & dJOINT_REVERSE )
    {
        setAxes( joint, x, y, z, NULL, joint->axis2 );
        offset1 = -offset1;
        offset2 = -offset2;
    }
    else
        setAxes( joint, x, y, z, joint->axis1, NULL );

    joint->computeInitialRelativeRotations();


    dVector3 ax2;
    getAxis2( joint, ax2, joint->axis2 );

    {
        dVector3 ax1;
        joint->getAxes(ax1, ax2);
    }



    dQuaternion qAngle;
    dQFromAxisAndAngle(qAngle, x, y, z, offset1);

    dMatrix3 R;
    dRFrom2Axes( R, x, y, z, ax2[0], ax2[1], ax2[2] );

    dQuaternion qcross;
    dRtoQ( R, qcross );

    dQuaternion qOffset;
    dQMultiply0(qOffset, qAngle, qcross);

    dQMultiply1( joint->qrel1, joint->node[0].body->q, qOffset );

    // Calculating the second offset
    dQFromAxisAndAngle(qAngle, ax2[0], ax2[1], ax2[2], offset2);

    dRFrom2Axes( R, ax2[0], ax2[1], ax2[2], x, y, z );
    dRtoQ( R, qcross );

    dQMultiply1(qOffset, qAngle, qcross);
    if ( joint->node[1].body )
    {
        dQMultiply1( joint->qrel2, joint->node[1].body->q, qOffset );
    }
    else
    {
        joint->qrel2[0] = qcross[0];
        joint->qrel2[1] = qcross[1];
        joint->qrel2[2] = qcross[2];
        joint->qrel2[3] = qcross[3];
    }
}
void SimpleTrackedVehicleEnvironment::nearCallbackGrouserTerrain(dGeomID o1, dGeomID o2) {
    dBodyID b1 = dGeomGetBody(o1);
    dBodyID b2 = dGeomGetBody(o2);
    if(b1 && b2 && dAreConnectedExcluding(b1, b2, dJointTypeContact)) return;

    // body of the whole vehicle
    dBodyID vehicleBody = ((SimpleTrackedVehicle*)this->v)->vehicleBody;

    unsigned long geom1Categories = dGeomGetCategoryBits(o1);

    // speeds of the belts
    const dReal leftBeltSpeed = ((SimpleTrackedVehicle*)this->v)->leftTrack->getVelocity();
    const dReal rightBeltSpeed = ((SimpleTrackedVehicle*)this->v)->rightTrack->getVelocity();

    dReal beltSpeed = 0; // speed of the belt which is in collision and examined right now
    if (geom1Categories & Category::LEFT) {
        beltSpeed = leftBeltSpeed;
    } else {
        beltSpeed = rightBeltSpeed;
    }

    // the desired linear and angular speeds (set by desired track velocities)
    const dReal linearSpeed = (leftBeltSpeed + rightBeltSpeed) / 2;
    const dReal angularSpeed = (leftBeltSpeed - rightBeltSpeed) * steeringEfficiency / tracksDistance;

    // radius of the turn the robot is doing
    const dReal desiredRotationRadiusSigned = (fabs(angularSpeed) < 0.1) ?
                                                dInfinity : // is driving straight
                                                ((fabs(linearSpeed) < 0.1) ?
                                                    0 : // is rotating about a single point
                                                    linearSpeed / angularSpeed // general movement
                                                );


    dVector3 yAxisGlobal; // vector pointing from vehicle body center in the direction of +y axis
    dVector3 centerOfRotation; // at infinity if driving straight, so we need to distinguish the case
    { // compute the center of rotation
        dBodyVectorToWorld(vehicleBody, 0, 1, 0, yAxisGlobal);

        dCopyVector3(centerOfRotation, yAxisGlobal);
        // make the unit vector as long as we need (and change orientation if needed; the radius is a signed number)
        dScaleVector3(centerOfRotation, desiredRotationRadiusSigned);

        const dReal *vehicleBodyPos = dBodyGetPosition(vehicleBody);
        dAddVectors3(centerOfRotation, centerOfRotation, vehicleBodyPos);
    }

    int maxContacts = 20;
    dContact contact[maxContacts];
    int numContacts = dCollide(o1, o2, maxContacts, &contact[0].geom, sizeof(dContact));

    for(size_t i = 0; i < numContacts; i++) {
        dVector3 contactInVehiclePos; // position of the contact point relative to vehicle body
        dBodyGetPosRelPoint(vehicleBody, contact[i].geom.pos[0], contact[i].geom.pos[1], contact[i].geom.pos[2], contactInVehiclePos);

        dVector3 beltDirection; // vector tangent to the belt pointing in the belt's movement direction
        dCalcVectorCross3(beltDirection, contact[i].geom.normal, yAxisGlobal);
        if (beltSpeed > 0) {
            dNegateVector3(beltDirection);
        }

        if (desiredRotationRadiusSigned != dInfinity) { // non-straight drive

            dVector3 COR2Contact; // vector pointing from the center of rotation to the contact point
            dSubtractVectors3(COR2Contact, contact[i].geom.pos, centerOfRotation);
            // the friction force should be perpendicular to COR2Contact
            dCalcVectorCross3(contact[i].fdir1, contact[i].geom.normal, COR2Contact);

            const dReal linearSpeedSignum = (fabs(linearSpeed) > 0.1) ? sgn(linearSpeed) : 1;

            // contactInVehiclePos[0] > 0 means the contact is in the front part of the track
            if (sgn(angularSpeed) * sgn(dCalcVectorDot3(yAxisGlobal, contact[i].fdir1)) !=
                    sgn(contactInVehiclePos[0]) * linearSpeedSignum) {
                dNegateVector3(contact[i].fdir1);
            }

        } else { // straight drive

            dCalcVectorCross3(contact[i].fdir1, contact[i].geom.normal, yAxisGlobal);

            if (dCalcVectorDot3(contact[i].fdir1, beltDirection) < 0) {
                dNegateVector3(contact[i].fdir1);
            }

        }

        // use friction direction and motion1 to simulate the track movement
        contact[i].surface.mode = dContactFDir1 | dContactMotion1 | dContactMu2;
        contact[i].surface.mu = 0.5;
        contact[i].surface.mu2 = 10;
        // the dot product <beltDirection,fdir1> is the cosine of the angle they form (because both are unit vectors)
        contact[i].surface.motion1 = -dCalcVectorDot3(beltDirection, contact[i].fdir1) * fabs(beltSpeed) * 0.07;

        // friction force visualization
        dMatrix3 forceRotation;
        dVector3 vec;
        dBodyVectorToWorld(vehicleBody, 1, 0, 0, vec);
        dRFrom2Axes(forceRotation, contact[i].fdir1[0], contact[i].fdir1[1], contact[i].fdir1[2], vec[0], vec[1], vec[2]);
        posr data;
        dCopyVector3(data.pos, contact[i].geom.pos);
        dCopyMatrix4x3(data.R, forceRotation);
        forces.push_back(data);

        dJointID c = dJointCreateContact(this->world, this->contactGroup, &contact[i]);
        dJointAttach(c, b1, b2);
        if(!isValidCollision(o1, o2, contact[i]))
            this->badCollision = true;
        if(config.contact_grouser_terrain.debug)
            this->contacts.push_back(contact[i].geom);
    }
}
示例#7
0
void AvatarGameObj::step_impl() {
  dBodyID body = get_entity().get_id();
  
  const Channel* chn;
  
  chn = &Input::get_axis_ch(ORSave::AxisBoundAction::TranslateX);
  if (chn->is_on()) {
    float v = (chn->get_value())*(MAX_STRAFE/MAX_FPS);
    dBodyAddRelForce(body, -v, 0.0, 0.0);
  }
  
  bool pushing_up = false;
  chn = &Input::get_axis_ch(ORSave::AxisBoundAction::TranslateY);
  if (chn->is_on()) {
    float v = (chn->get_value())*(MAX_STRAFE/MAX_FPS);
    if (Saving::get().config().invertTranslateY()) {
      v = -v;
    }
    dBodyAddRelForce(body, 0.0, -v, 0.0);
    if (v < 0) {
      pushing_up = true;
    }
  }
  
  chn = &Input::get_axis_ch(ORSave::AxisBoundAction::TranslateZ);
  if (chn->is_on()) {
    float v = (chn->get_value())*(MAX_ACCEL/MAX_FPS);
    dBodyAddRelForce(body, 0.0, 0.0, -v);
  }
  
  const dReal* avel = dBodyGetAngularVel(body);
  dVector3 rel_avel;
  dBodyVectorFromWorld(body, avel[0], avel[1], avel[2], rel_avel);
  
  // X-turn and x-counterturn
  chn = &Input::get_axis_ch(ORSave::AxisBoundAction::RotateY);
  if (chn->is_on()) {
    float v = -(chn->get_value())*(MAX_TURN/MAX_FPS);
    dBodyAddRelTorque(body, 0.0, v, 0.0);
  } else {
    float cv = rel_avel[1]*-CTURN_COEF/MAX_FPS;
    dBodyAddRelTorque(body, 0.0, cv, 0.0);
  }
  
  // Y-turn and y-counterturn
  chn = &Input::get_axis_ch(ORSave::AxisBoundAction::RotateX);
  if (chn->is_on()) {
    float v = (chn->get_value())*(MAX_TURN/MAX_FPS);
    if (Saving::get().config().invertRotateY()) {
      v = -v;
    }
    dBodyAddRelTorque(body, v, 0.0, 0.0);
  } else {
    float cv = rel_avel[0]*-CTURN_COEF/MAX_FPS;
    dBodyAddRelTorque(body, cv, 0.0, 0.0);
  }
  
  // Roll and counter-roll
  chn = &Input::get_axis_ch(ORSave::AxisBoundAction::RotateZ);
  if (chn->is_on()) {
    float v = (chn->get_value())*(MAX_ROLL/MAX_FPS);
    dBodyAddRelTorque(body, 0.0, 0.0, v);
  } else {
    float cv = rel_avel[2]*(-CROLL_COEF/MAX_FPS);
    dBodyAddRelTorque(body, 0.0, 0.0, cv);
  }
  
  // Changing stance between superman-style and upright
  if (_attached) {
    _uprightness += UPRIGHTNESS_STEP_DIFF;
  } else {
    _uprightness -= UPRIGHTNESS_STEP_DIFF;
  }
  if (_uprightness > 1.0) { _uprightness = 1.0; } else if (_uprightness < 0.0) { _uprightness = 0.0; }
  
  update_geom_offsets();
  
  _attached = _attached_this_frame;
  
  // If we are attached, work to keep ourselves ideally oriented to the attachment surface
  if (_attached) {
    Vector sn_rel = vector_from_world(_sn);
    Vector lvel = Vector(dBodyGetLinearVel(body));
    Vector lvel_rel = vector_from_world(lvel);
    Vector avel = Vector(dBodyGetAngularVel(body));
    Vector avel_rel = vector_from_world(avel);
    
    // Apply as much of each delta as we can
    
    // X and Z orientation delta
    // TODO Maybe should translate body so that the contact point stays in the same spot through rotation
    float a = limit_abs(_zrot_delta, RUNNING_ADJ_RATE_Z_ROT/MAX_FPS);
    Vector body_x(vector_to_world(Vector(cos(a), sin(a), 0)));
    a = limit_abs(-_xrot_delta, RUNNING_ADJ_RATE_X_ROT/MAX_FPS);
    Vector body_y(vector_to_world(Vector(0, cos(a), sin(a))));
    dMatrix3 matr;
    dRFrom2Axes(matr, body_x.x, body_x.y, body_x.z, body_y.x, body_y.y, body_y.z);
    dBodySetRotation(body, matr);
    
    // Y position delta
    // If the user is pushing up, set the target point high above the ground so we escape sticky attachment
    set_pos(get_pos() + _sn*limit_abs(_ypos_delta + (pushing_up ? RUNNING_MAX_DELTA_Y_POS*2 : 0), RUNNING_ADJ_RATE_Y_POS/MAX_FPS));
    
    // Y linear velocity delta
    lvel_rel.y += limit_abs(_ylvel_delta, RUNNING_ADJ_RATE_Y_LVEL/MAX_FPS);
    lvel = vector_to_world(lvel_rel);
    dBodySetLinearVel(body, lvel.x, lvel.y, lvel.z);
    
    // X and Z angular velocity delta
    avel_rel.x += limit_abs(_xavel_delta, RUNNING_ADJ_RATE_X_AVEL/MAX_FPS);
    avel_rel.z += limit_abs(_zavel_delta, RUNNING_ADJ_RATE_Z_AVEL/MAX_FPS);
    avel = vector_to_world(avel_rel);
    dBodySetAngularVel(body, avel.x, avel.y, avel.z);
  }
  
  if (_attached_this_frame) {
    _attached_this_frame = false;
    dGeomEnable(get_entity().get_geom("sticky_attach"));
  } else {
    dGeomDisable(get_entity().get_geom("sticky_attach"));
  }
}