float AI_Car_Experimental::RayCastDistance( MATHVECTOR <float, 3> direction, float max_length){
	btVector3 pos = car->GetCarDynamics().GetPosition();
	btVector3 dir = car->GetCarDynamics().LocalToWorld(ToBulletVector(direction));
	dir -= pos;
	COLLISION_CONTACT contact;
	car->GetDynamicsWorld()->castRay(
		pos,
		dir,
		max_length,
		&car->GetCarDynamics().getCollisionObject(),
		contact
		);
	float depth = contact.GetDepth();
	float dist = std::min(max_length, depth);
#ifdef VISUALIZE_AI_DEBUG
	MATHVECTOR<float, 3> pos_start(ToMathVector<float>(pos));
	MATHVECTOR<float, 3> pos_end = pos_start + (ToMathVector<float>(dir) * dist);
	AddLinePoint(raycastshape, pos_start);
	AddLinePoint(raycastshape, pos_end);
#endif
	return dist;
}
Esempio n. 2
0
void FollowCamera::update(Real time, const PosInfo& posIn, PosInfo* posOut, COLLISION_WORLD* world, bool bounce)
{
    if (!ca || !posOut)  return;

    ///  input from car posInfoIn
    Vector3 posGoal = posIn.pos;
    Quaternion orientGoal = posIn.rot;
    ///  output saved back to car posInfoOut
    Quaternion camRotFinal;

    const static Quaternion
    qO = Quaternion(Degree(180),Vector3::UNIT_Z) * Quaternion(Degree(-90),Vector3::UNIT_Y),
    qR = Quaternion(Degree(90),Vector3(0,1,0));

    Quaternion  orient = orientGoal * qO;
    Vector3  ofs = orient * ca->mOffset,  goalLook = posGoal + ofs;

    first = iFirst < 2;  ///par few first frames after reset
    if (iFirst < 10)  // after reset
    {
        ++iFirst;
        mDistReduce = 0.f;
        mATilt = 0.f;
    }

    ///  Camera Tilt from terrain/road slope under car
    //-------------------------------------------------------------------------------------------
    const float			//  params  . . .
    Rdist = 1.f,     // dist from car to ray (front or back)
    HupCar = 1.5f,	  // car up dir dist - for pipes - so pos stays inside pipe
    Habove = 1.5f,    // up axis dist, above car - for very high terrain angles
    HMaxDepth = 12.f;  // how far down can the ray goes
    const static Radian r0(0.f),
          angMin = Degree(10.f),   // below this angle, tilt has no effect - terrain bumps
          maxDiff = Degree(1.4f);  // max diff of tilt - no sudden jumps
    const float smoothSpeed = 14.f;  // how fast to apply tilt change

    bool bUseTilt = ca->mType == CAM_ExtAng || ca->mType == CAM_Follow;
    Radian tilt(0.f);
    if (pSet->cam_tilt && bUseTilt)
    {
        //  car pos
        Vector3 carUp = posIn.pos - HupCar * posIn.carY;
        MATHVECTOR<float,3> pos(carUp.x, -carUp.z, carUp.y + Habove);  // to vdr/blt
        const static MATHVECTOR<float,3> dir(0,0,-1);  // cast rays down

        //  car rot, yaw angle
        Quaternion q = posIn.rot * Quaternion(Degree(90),Vector3(0,1,0));
        float angCarY = q.getYaw().valueRadians() + PI_d/2.f;
        float ax = cosf(angCarY)*Rdist, ay = sinf(angCarY)*Rdist;
        //LogO("pos: "+fToStr(pos[0],2,4)+" "+fToStr(pos[1],2,4)+"  a: "+fToStr(angCarY,2,4)+"  dir: "+fToStr(ax,2,4)+" "+fToStr(ay,2,4));

        //  cast 2 rays - 2 times, average 2 angles
        COLLISION_CONTACT ct0,ct1,ct20,ct21;
        MATHVECTOR<float,3> ofs(ax*0.5f,ay*0.5f,0),ofs2(ax,ay,0);
        world->CastRay(pos+ofs, dir, HMaxDepth,chassis, ct0,  0,0, true, true);
        world->CastRay(pos-ofs, dir, HMaxDepth,chassis, ct1,  0,0, true, true);
        world->CastRay(pos+ofs2,dir, HMaxDepth,chassis, ct20, 0,0, true, true);
        world->CastRay(pos-ofs2,dir, HMaxDepth,chassis, ct21, 0,0, true, true);

#ifdef CAM_TILT_DBG
        MATHVECTOR<float,3> v;
        v = pos+ofs;
        posHit[0] = Vector3(v[0],v[2]- ct0.GetDepth(), -v[1]);
        v = pos-ofs;
        posHit[1] = Vector3(v[0],v[2]- ct1.GetDepth(), -v[1]);
        v = pos+ofs2;
        posHit[2] = Vector3(v[0],v[2]- ct20.GetDepth(),-v[1]);
        v = pos-ofs2;
        posHit[3] = Vector3(v[0],v[2]- ct21.GetDepth(),-v[1]);
#endif

        if (ct0.GetColObj() && ct1.GetColObj() && ct20.GetColObj() && ct21.GetColObj() )
            tilt = (GetAngle(Rdist, ct1.GetDepth() - ct0.GetDepth()) +
                    GetAngle(2.f*Rdist, ct21.GetDepth() - ct20.GetDepth())) * 0.5f;
        //else  LogO(String("no hit: ")+(ct0.col?"1":"0")+(ct1.col?" 1":" 0"));

        //if (tilt < angMin && tilt > -angMin)  tilt = 0.f;
        if (tilt < r0 && tilt >-angMin) {
            Radian d = tilt-angMin;
            tilt = std::min(r0, tilt + d*d*5.f);
        }
        if (tilt > r0 && tilt < angMin) {
            Radian d =-angMin-tilt;
            tilt = std::max(r0, tilt - d*d*5.f);
        }

        //LogO("a "+fToStr(angCarY,3,5)+" d  "+fToStr(ct0.GetDepth(),3,5)+" "+fToStr(ct1.GetDepth(),3,5)+"  t "+fToStr(tilt.valueDegrees(),3,5));
    }
    //  smooth tilt angle
    mATilt += std::min(maxDiff, std::max(-maxDiff, tilt - mATilt)) * time * smoothSpeed;


    //-------------------------------------------------------------------------------------------
    if (ca->mType == CAM_Car)	/* 3 Car - car pos & rot full */
    {
        camPosFinal = goalLook;
        camRotFinal = orient;

        posOut->camPos = camPosFinal;  // save result in out posInfo
        posOut->camRot = camRotFinal;
        return;
    }

    if (ca->mType == CAM_Follow)  ofs = ca->mOffset;

    Vector3  pos,goalPos;
    pos     = camPosFinal - ofs;
    goalPos = posGoal;

    Vector3  xyz;
    if (ca->mType != CAM_Arena)
    {
        Real x,y,z,xz;   // pitch & yaw to direction vector
        Real ap = bUseTilt ? (ca->mPitch.valueRadians() + mATilt.valueRadians()) : ca->mPitch.valueRadians(),
             ay = ca->mYaw.valueRadians();
        y = sin(ap), xz = cos(ap);
        x = sin(ay) * xz, z = cos(ay) * xz;
        xyz = Vector3(x,y,z);
        xyz *= ca->mDist;
    }

    bool manualOrient = false;
    switch (ca->mType)
    {
    case CAM_Arena:		/* 2 Arena - free pos & rot */
        goalPos = ca->mOffset - ofs;
        break;

    case CAM_Free:		/* 1 Free - free rot, pos from car */
        goalPos += xyz;
        break;

    case CAM_Follow:	/* 0 Follow - car rotY & pos from behind car, smooth */
    {   Quaternion  orient = orientGoal * qR;
        orient.FromAngleAxis(orient.getYaw(), Vector3::UNIT_Y);
        goalPos += orient * xyz;
    }
    break;

    case CAM_ExtAng:    /* 4 Extended Angle - car in center, angle smooth */
    {   Quaternion  orient = orientGoal * qR;
        Quaternion  ory;
        ory.FromAngleAxis(orient.getYaw(), Vector3::UNIT_Y);

        if (first)  {
            qq = ory;
        }
        else  qq = orient.Slerp(ca->mSpeed * time, qq, ory, true);

        //  smooth dist from vel
#if 0
        {
            if (first)  {
                mPosNodeOld = posGoal;
            }
            Real vel = (posGoal - mPosNodeOld).length() / std::max(0.002f, std::min(0.1f, time));
            mPosNodeOld = posGoal;
            if (first)  mVel = 0.f;
            else
                mVel += (vel - mVel) * time * 8.f;  //par-  vel smooth speed
            if (!first)
                xyz *= 1.f + std::min(100.f, mVel) * 0.01f;  //par-  vel dist factor
        }
#endif

        Quaternion  qy = Quaternion(ca->mYaw,Vector3(0,1,0));
        goalPos += qq * (xyz + ca->mOffset);

        camPosFinal = goalPos;
        camRotFinal = qq * qy * Quaternion(Degree(-ca->mPitch - mATilt), Vector3(1,0,0));
        manualOrient = true;
    }
    break;
    }

    if (!manualOrient)  // if !CAM_ExtAng
    {
        float dtmul = ca->mSpeed == 0 ? 1.0f : ca->mSpeed * time;

        if (ca->mType ==  CAM_Arena)
        {
            Vector3  Pos(0,0,0), goalPos = ca->mOffset;
            Pos = camPosFinal;  //read last state (smooth)
            Pos += (goalPos - Pos) * dtmul;

            mAPitch += (ca->mPitch - mAPitch) * dtmul;
            mAYaw += (ca->mYaw - mAYaw) * dtmul;

            if (first)  {
                Pos = goalPos;
                mAPitch = ca->mPitch;
                mAYaw = ca->mYaw;
            }
            camPosFinal = Pos;
            camRotFinal = Quaternion(Degree(mAYaw),Vector3(0,1,0)) * Quaternion(Degree(mAPitch),Vector3(1,0,0));
            manualOrient = true;
        }
        else
        {
            if (first)  pos = goalPos;
            Vector3  addPos,addLook;
            addPos = (goalPos - pos).normalisedCopy() * (goalPos - pos).length() * dtmul;
            if (addPos.squaredLength() > (goalPos - pos).squaredLength())  addPos = goalPos - pos;
            pos += addPos;
            camPosFinal = pos + ofs;

            goalLook = posGoal + ofs;
            if (first)	{
                mLook = goalLook;
            }

            addLook = (goalLook - mLook) * dtmul;//Rot;
            mLook += addLook;
        }
    }

    //camLookFinal = mLook;
    if (!manualOrient)  // CAM_Free or CAM_Follow
    {
        Vector3 zdir = camPosFinal - mLook;
        zdir.normalise();
        Vector3 xVec = Vector3::UNIT_Y.crossProduct(zdir);
        xVec.normalise();
        Vector3 yVec = zdir.crossProduct(xVec);
        yVec.normalise();
        Quaternion q;
        q.FromAxes(xVec, yVec, zdir);
        camRotFinal = q;
    }

    //  cast ray from car to camera, reduce dist if hit
    //-------------------------------------------------------------------------------------------
    Vector3 pp = camPosFinal;
    if (bounce)
        pp += posIn.camOfs * ca->mOfsMul
              * gPar.camBncScale * pSet->cam_bnc_mul;

    Vector3 p = posGoal;
    p.y += 1.f;  //up
    //Vector3 d = camRotFinal * Vector3::UNIT_Z;  d.normalise();
    Vector3 d = pp - p;
    d.normalise();

    if (!first && ca->mType != CAM_Arena)
    {
        MATHVECTOR<float,3> pos1(p.x,-p.z,p.y), dir(d.x,-d.z,d.y);  //dir = dir.Normalize();
        COLLISION_CONTACT ct;
        float maxLen = (p - pp).length();  //cam near
        world->CastRay(pos1, dir, maxLen,chassis, ct,  0,0, true, true, true/*+*/);
        //dbgLen = -maxLen;

        if (ct.GetColObj())
        {
            float len = ct.GetDepth();  //dbgLen = len;
            len -= 0.2f + ct.GetNormal()[2];  ///par  normal up, flat terrain, move closer
            if (len < maxLen)
            {
                Real dist = maxLen - len;
                if (dist > mDistReduce)
                    mDistReduce = dist;
            }
        }
    }

    //  save result in out posInfo
    posOut->camPos = mDistReduce > 0.0001f ? (pp - d * mDistReduce) : pp;
    posOut->camRot = camRotFinal;

    //  smooth, back to normal dist
    if (mDistReduce > 0.f)
        mDistReduce -= time * 10.f;
}