///note that carposition must be in patch space ///returns distance from left side of the track float GetHorizontalDistanceAlongPatch(const BEZIER & patch, MATHVECTOR <float, 3> carposition) { MATHVECTOR <float, 3> leftside = (patch.GetPoint(0,0) + patch.GetPoint(3,0))*0.5; MATHVECTOR <float, 3> rightside = (patch.GetPoint(0,3) + patch.GetPoint(3,3))*0.5; MATHVECTOR <float, 3> patchwidthvector = rightside - leftside; return patchwidthvector.Normalize().dot(carposition-leftside); }
// 3D effects //-------------------------------------------------------------------------------------------------------------------- void SOUND::Compute3DEffects(std::list <SOUNDSOURCE *> & sources, const MATHVECTOR <float, 3> & listener_pos, const QUATERNION <float> & listener_rot) const { for (std::list <SOUNDSOURCE *>::iterator i = sources.begin(); i != sources.end(); ++i) { if ((*i)->Get3DEffects()) { MATHVECTOR <float, 3> relvec = (*i)->GetPosition() - listener_pos; float len = relvec.Magnitude(); if (len < 0.1) { relvec[2] = 0.1; len = relvec.Magnitude(); } listener_rot.RotateVector(relvec); // attenuation //float cgain = 0.25 / log(100.0) * (log(1000.0) - 1.6 * log(len)); float cgain = log(1000.0 / pow((double)len, 1.3)) / log(100.0); cgain = std::min(1.f, std::max(0.f, cgain)); // pan float xcoord = -relvec.Normalize()[0]; float pgain1 = std::max(0.f, -xcoord); float pgain2 = std::max(0.f, xcoord); (*i)->SetComputationResults(cgain*(*i)->GetGain()*(1.f-pgain1), cgain*(*i)->GetGain()*(1.f-pgain2)); } else { (*i)->SetComputationResults((*i)->GetGain(), (*i)->GetGain()); } } }
void CAMERA_MOUNT::Update(const MATHVECTOR <float, 3> & newpos, const QUATERNION <float> & newdir, float dt) { rotation = newdir * offsetrot; MATHVECTOR <float, 3> pos = offset; newdir.RotateVector(pos); pos = pos + newpos; MATHVECTOR <float, 3> vel = pos - position; effect = (vel.Magnitude() - 0.02) / 0.04; if (effect < 0) effect = 0; else if (effect > 1) effect = 1; float bumpdiff = randgen.Get(); float power = pow(bumpdiff, 32); if (power < 0) power = 0; else if (power > 0.2) power = 0.2; float veleffect = std::min(pow(vel.Magnitude() * ( 2.0 - stiffness), 3.0), 1.0); float bumpimpulse = power * 130.0 * veleffect; float k = 800.0 + stiffness * 800.0 * 4.0; float c = 2.0 * std::sqrt(k * mass) * 0.35; MATHVECTOR <float, 3> bumpforce = direction::Up * bumpimpulse; MATHVECTOR <float, 3> springforce = -displacement * k; MATHVECTOR <float, 3> damperforce = -velocity * c; velocity = velocity + (springforce + damperforce + bumpforce) * dt; displacement = displacement + velocity * dt; UpdatePosition(pos); }
void CARDYNAMICS::ApplyForce(const MATHVECTOR<Dbl,3> & force, const MATHVECTOR<Dbl,3> & offset) { body.ApplyForce(force, offset); MATHVECTOR<Dbl,3> fo = offset * force.Magnitude(); cam_body.ApplyForce((force * gPar.camBncFo + fo * gPar.camBncFof) * fBncMass); //chassis->applyForce(ToBulletVector(force), ToBulletVector(offset)); }
//simple hinge (arc) suspension displacement MATHVECTOR<Dbl,3> CARDYNAMICS::GetLocalWheelPosition(WHEEL_POSITION wp, Dbl displacement_percent) const { //const const MATHVECTOR<Dbl,3> & wheelext = wheel[wp].GetExtendedPosition(); const MATHVECTOR<Dbl,3> & hinge = suspension[wp].GetHinge(); MATHVECTOR<Dbl,3> relwheelext = wheelext - hinge; MATHVECTOR<Dbl,3> up(0,0,1); MATHVECTOR<Dbl,3> rotaxis = up.cross ( relwheelext.Normalize() ); Dbl hingeradius = relwheelext.Magnitude(); Dbl travel = suspension[wp].GetTravel(); //const Dbl displacement = displacement_percent * travel; Dbl displacementradians = displacement / hingeradius; QUATERNION<Dbl> hingerotate; hingerotate.Rotate ( -displacementradians, rotaxis[0], rotaxis[1], rotaxis[2] ); MATHVECTOR<Dbl,3> localwheelpos = relwheelext; hingerotate.RotateVector ( localwheelpos ); return localwheelpos + hinge; }
///trim the patch's width in-place void TrimPatch(BEZIER & patch, float trimleft_front, float trimright_front, float trimleft_back, float trimright_back) { MATHVECTOR <float, 3> frontvector = (patch.GetPoint(0,3) - patch.GetPoint(0,0)); MATHVECTOR <float, 3> backvector = (patch.GetPoint(3,3) - patch.GetPoint(3,0)); float frontwidth = frontvector.Magnitude(); float backwidth = backvector.Magnitude(); if (trimleft_front + trimright_front > frontwidth) { float scale = frontwidth/(trimleft_front + trimright_front); trimleft_front *= scale; trimright_front *= scale; } if (trimleft_back + trimright_back > backwidth) { float scale = backwidth/(trimleft_back + trimright_back); trimleft_back *= scale; trimright_back *= scale; } MATHVECTOR <float, 3> newfl = patch.GetPoint(0,0); MATHVECTOR <float, 3> newfr = patch.GetPoint(0,3); MATHVECTOR <float, 3> newbl = patch.GetPoint(3,0); MATHVECTOR <float, 3> newbr = patch.GetPoint(3,3); if (frontvector.Magnitude() > 0.001) { MATHVECTOR <float, 3> trimdirection_front = frontvector.Normalize(); newfl = patch.GetPoint(0,0) + trimdirection_front*trimleft_front; newfr = patch.GetPoint(0,3) - trimdirection_front*trimright_front; } if (backvector.Magnitude() > 0.001) { MATHVECTOR <float, 3> trimdirection_back = backvector.Normalize(); newbl = patch.GetPoint(3,0) + trimdirection_back*trimleft_back; newbr = patch.GetPoint(3,3) - trimdirection_back*trimright_back; } patch.SetFromCorners(newfl, newfr, newbl, newbr); }
///fix invalid normals (my own fault, i suspect. the DOF converter i wrote may have flipped Y & Z normals) static bool NeedsNormalSwap(JOEObject & Object) { bool need_normal_flip = false; for (int f = 0; f < Object.info.num_frames; f++) { int normal_flip_count = 0; for (int i = 0; i < Object.info.num_faces; i++) { MATHVECTOR <float,3> tri[3]; MATHVECTOR <float,3> norms[3]; for (unsigned int v = 0; v < 3; v++) { assert(Object.frames[f].faces[i].vertexIndex[v] < Object.frames[f].num_verts); assert(Object.frames[f].faces[i].normalIndex[v] < Object.frames[f].num_normals); tri[v].Set(Object.frames[f].verts[Object.frames[f].faces[i].vertexIndex[v]].vertex); norms[v].Set(Object.frames[f].normals[Object.frames[f].faces[i].normalIndex[v]].vertex); } MATHVECTOR <float,3> norm; for (unsigned int v = 0; v < 3; v++) norm = norm + norms[v]; MATHVECTOR <float,3> tnorm = (tri[2] - tri[0]).cross(tri[1] - tri[0]); if (tnorm.Magnitude() > 0.0001 && norm.Magnitude() > 0.0001) { norm = norm.Normalize(); tnorm = tnorm.Normalize(); if (norm.dot(tnorm) < 0.5 && norm.dot(tnorm) > -0.5) { normal_flip_count++; //std::cout << norm.dot(tnorm) << std::endl; //std::cout << norm << " -- " << tnorm << std::endl; } } } if (normal_flip_count > Object.info.num_faces/4) need_normal_flip = true; } return need_normal_flip; }
void AI::analyzeOthers(AI_Car *c, float dt, const std::list <CAR> & othercars) { //const float speed = std::max(1.0f,c->car->GetVelocity().Magnitude()); const float half_carlength = 1.25; //in meters //std::cout << speed << ": " << authority << std::endl; //const MATHVECTOR <float, 3> steer_right_axis = direction::Right; const MATHVECTOR <float, 3> throttle_axis = direction::Forward; #ifdef VISUALIZE_AI_DEBUG //c->avoidancedraw->ClearLine(); #endif for (std::list <CAR>::const_iterator i = othercars.begin(); i != othercars.end(); ++i) { if (&(*i) != c->car) { struct AI_Car::OTHERCARINFO & info = c->othercars[&(*i)]; //find direction of othercar in our frame MATHVECTOR <float, 3> relative_position = i->GetCenterOfMassPosition() - c->car->GetCenterOfMassPosition(); (-c->car->GetOrientation()).RotateVector(relative_position); //std::cout << relative_position.dot(throttle_axis) << ", " << relative_position.dot(steer_right_axis) << std::endl; //only make a move if the other car is within our distance limit float fore_position = relative_position.dot(throttle_axis); //float speed_diff = i->GetVelocity().dot(throttle_axis) - c->car->GetVelocity().dot(throttle_axis); //positive if other car is faster MATHVECTOR <float, 3> myvel = c->car->GetVelocity(); MATHVECTOR <float, 3> othervel = i->GetVelocity(); (-c->car->GetOrientation()).RotateVector(myvel); (-i->GetOrientation()).RotateVector(othervel); float speed_diff = othervel.dot(throttle_axis) - myvel.dot(throttle_axis); //positive if other car is faster //std::cout << speed_diff << std::endl; //float distancelimit = clamp(distancelimitcoeff*-speed_diff, distancelimitmin, distancelimitmax); const float fore_position_offset = -half_carlength; if (fore_position > fore_position_offset)// && fore_position < distancelimit) //only pay attention to cars roughly in front of us { //float horizontal_distance = relative_position.dot(steer_right_axis); //fallback method if not on a patch //float orig_horiz = horizontal_distance; const BEZIER * othercarpatch = GetCurrentPatch(&(*i)); const BEZIER * mycarpatch = GetCurrentPatch(c->car); if (othercarpatch && mycarpatch) { float my_track_placement = GetHorizontalDistanceAlongPatch(*mycarpatch, TransformToPatchspace(c->car->GetCenterOfMassPosition())); float their_track_placement = GetHorizontalDistanceAlongPatch(*othercarpatch, TransformToPatchspace(i->GetCenterOfMassPosition())); float speed_diff_denom = clamp(speed_diff, -100, -0.01); float eta = (fore_position-fore_position_offset)/-speed_diff_denom; info.fore_distance = fore_position; if (!info.active) info.eta = eta; else info.eta = RateLimit(info.eta, eta, 10.f*dt, 10000.f*dt); float horizontal_distance = their_track_placement - my_track_placement; //if (!info.active) info.horizontal_distance = horizontal_distance; /*else info.horizontal_distance = RateLimit(info.horizontal_distance, horizontal_distance, spacingdistance*dt, spacingdistance*dt);*/ //std::cout << info.horizontal_distance << ", " << info.eta << std::endl; info.active = true; } else info.active = false; //std::cout << orig_horiz << ", " << horizontal_distance << ", " << fore_position << ", " << speed_diff << std::endl; /*if (!min_horizontal_distance) min_horizontal_distance = optional <float> (horizontal_distance); else if (std::abs(min_horizontal_distance.get()) > std::abs(horizontal_distance)) min_horizontal_distance = optional <float> (horizontal_distance);*/ } else info.active = false; /*#ifdef VISUALIZE_AI_DEBUG if (info.active) { c->avoidancedraw->AddLinePoint(c->car->GetCenterOfMassPosition()); MATHVECTOR <float, 3> feeler1(speed*info.eta,0,0); c->car->GetOrientation().RotateVector(feeler1); MATHVECTOR <float, 3> feeler2(0,-info.horizontal_distance,0); c->car->GetOrientation().RotateVector(feeler2); c->avoidancedraw->AddLinePoint(c->car->GetCenterOfMassPosition()+feeler1+feeler2); c->avoidancedraw->AddLinePoint(c->car->GetCenterOfMassPosition()); } #endif*/ } } }
void MODEL_JOE03::ReadData ( FILE * m_FilePointer, const JOEPACK * pack, JOEObject & Object ) { int num_frames = Object.info.num_frames; int num_faces = Object.info.num_faces; Object.frames.resize(num_frames); for ( int i = 0; i < num_frames; i++ ) { Object.frames[i].faces.resize(num_faces); BinaryRead ( &Object.frames[i].faces[0], sizeof ( JOEFace ), num_faces, m_FilePointer, pack ); CorrectEndian ( Object.frames[i].faces ); BinaryRead ( &Object.frames[i].num_verts, sizeof ( int ), 1, m_FilePointer, pack ); Object.frames[i].num_verts = ENDIAN_SWAP_32 ( Object.frames[i].num_verts ); BinaryRead ( &Object.frames[i].num_texcoords, sizeof ( int ), 1, m_FilePointer, pack ); Object.frames[i].num_texcoords = ENDIAN_SWAP_32 ( Object.frames[i].num_texcoords ); BinaryRead ( &Object.frames[i].num_normals, sizeof ( int ), 1, m_FilePointer, pack ); Object.frames[i].num_normals = ENDIAN_SWAP_32 ( Object.frames[i].num_normals ); Object.frames[i].verts.resize(Object.frames[i].num_verts); Object.frames[i].normals.resize(Object.frames[i].num_normals); Object.frames[i].texcoords.resize(Object.frames[i].num_texcoords); BinaryRead ( &Object.frames[i].verts[0], sizeof ( JOEVertex ), Object.frames[i].num_verts, m_FilePointer, pack ); CorrectEndian ( Object.frames[i].verts ); BinaryRead ( &Object.frames[i].normals[0], sizeof ( JOEVertex ), Object.frames[i].num_normals, m_FilePointer, pack ); CorrectEndian ( Object.frames[i].normals ); BinaryRead ( &Object.frames[i].texcoords[0], sizeof ( JOETexCoord ), Object.frames[i].num_texcoords, m_FilePointer, pack ); CorrectEndian ( Object.frames[i].texcoords ); } //cout << "!!! loading " << modelpath << endl; //go do scaling for (int i = 0; i < num_frames; i++) { for ( int v = 0; v < Object.frames[i].num_verts; v++ ) { MATHVECTOR <float, 3> temp; temp.Set ( Object.frames[i].verts[v].vertex ); temp = temp * MODEL_SCALE; for (int n = 0; n < 3; n++) Object.frames[i].verts[v].vertex[n] = temp[n]; } } if (NeedsNormalSwap(Object)) { for (int i = 0; i < num_frames; i++) { for ( int v = 0; v < Object.frames[i].num_normals; v++ ) { std::swap(Object.frames[i].normals[v].vertex[1], Object.frames[i].normals[v].vertex[2]); Object.frames[i].normals[v].vertex[1] = -Object.frames[i].normals[v].vertex[1]; } } //std::cout << "!!! swapped normals !!!" << std::endl; } //assert(!NeedsNormalFlip(pObject)); /*//make sure vertex ordering is consistent with normals for (i = 0; i < Object.info.num_faces; i++) { short vi[3]; VERTEX tri[3]; VERTEX norms[3]; for (unsigned int v = 0; v < 3; v++) { vi[v] = GetFace(i)[v]; tri[v].Set(GetVert(vi[v])); norms[v].Set(GetNorm(GetNormIdx(i)[v])); } VERTEX norm; for (unsigned int v = 0; v < 3; v++) norm = norm + norms[v]; norm = norm.normalize(); VERTEX tnorm = (tri[2] - tri[0]).cross(tri[1] - tri[0]); if (norm.dot(tnorm) > 0) { short tvi = Object.frames[0].faces[i].vertexIndex[1]; Object.frames[0].faces[i].vertexIndex[1] = Object.frames[0].faces[i].vertexIndex[2]; Object.frames[0].faces[i].vertexIndex[2] = tvi; tvi = Object.frames[0].faces[i].normalIndex[1]; Object.frames[0].faces[i].normalIndex[1] = Object.frames[0].faces[i].normalIndex[2]; Object.frames[0].faces[i].normalIndex[2] = tvi; tvi = Object.frames[0].faces[i].textureIndex[1]; Object.frames[0].faces[i].textureIndex[1] = Object.frames[0].faces[i].textureIndex[2]; Object.frames[0].faces[i].textureIndex[2] = tvi; } }*/ //build unique vertices //cout << "building unique vertices...." << endl; int frame(0); typedef size_t size_type; vector <VERT_ENTRY> vert_master ((size_type)(Object.frames[frame].num_verts)); vert_master.reserve(Object.frames[frame].num_verts*2); vector <int> v_faces((size_type)(Object.info.num_faces*3)); for (int i = 0; i < Object.info.num_faces; i++) { for (int v = 0; v < 3; v++) { VERT_ENTRY & ve = vert_master[Object.frames[frame].faces[i].vertexIndex[v]]; if (ve.original_index == -1) //first entry { ve.original_index = Object.frames[frame].faces[i].vertexIndex[v]; ve.norm_index = Object.frames[frame].faces[i].normalIndex[v]; ve.tex_index = Object.frames[frame].faces[i].textureIndex[v]; //if (ve.tex_index < 0) assert(ve.tex_index >= 0); v_faces[i*3+v] = Object.frames[frame].faces[i].vertexIndex[v]; //cout << "(first) face " << i << " vert " << v << " index: " << v_faces[i*3+v] << endl; //cout << "first entry: " << ve.original_index << "," << ve.norm_index << "," << ve.tex_index << endl; } else { //see if we match the pre-existing entry if (ve.norm_index == Object.frames[frame].faces[i].normalIndex[v] && ve.tex_index == Object.frames[frame].faces[i].textureIndex[v]) { v_faces[i*3+v] = Object.frames[frame].faces[i].vertexIndex[v]; assert(ve.tex_index >= 0); //cout << "(matched) face " << i << " vert " << v << " index: " << v_faces[i*3+v] << endl; //cout << "matched entry: " << ve.original_index << "," << ve.norm_index << "," << ve.tex_index << endl; } else { //create a new entry vert_master.push_back(VERT_ENTRY()); vert_master.back().original_index = Object.frames[frame].faces[i].vertexIndex[v]; vert_master.back().norm_index = Object.frames[frame].faces[i].normalIndex[v]; vert_master.back().tex_index = Object.frames[frame].faces[i].textureIndex[v]; assert(vert_master.back().tex_index >= 0); v_faces[i*3+v] = vert_master.size()-1; //cout << "(new) face " << i << " vert " << v << " index: " << v_faces[i*3+v] << endl; //cout << "new entry: " << vert_master.back().original_index << "," << vert_master.back().norm_index << "," << vert_master.back().tex_index << " (" << ve.original_index << "," << ve.norm_index << "," << ve.tex_index << ")" << endl; } } } } /*for (int i = 0; i < vert_master.size(); i++) { if (vert_master[i].original_index < 0) std::cout << i << ", " << Object.frames[frame].num_verts << ", " << vert_master.size() << std::endl; assert(vert_master[i].original_index >= 0); }*/ float newvertnum = vert_master.size(); /*std::cout << modelpath << " (" << Object.info.num_faces << ") used to have " << Object.frames[frame].num_verts << " vertices, " << Object.frames[frame].num_normals << " normals, " << Object.frames[frame].num_texcoords << " tex coords, now it has " << newvertnum << " combo verts (combo indices)" << std::endl;*/ //now, fill up the vertices, normals, and texcoords vector <float> v_vertices((size_type)(newvertnum*3)); vector <float> v_texcoords((size_type)(newvertnum*2)); vector <float> v_normals((size_type)(newvertnum*3)); for (int i = 0; i < newvertnum; ++i) { if (vert_master[i].original_index >= 0) { for (int d = 0; d < 3; d++) v_vertices[i*3+d] = Object.frames[frame].verts[vert_master[i].original_index].vertex[d]; for (int d = 0; d < 3; d++) v_normals[i*3+d] = Object.frames[frame].normals[vert_master[i].norm_index].vertex[d]; //std::cout << i << ", " << vert_master[i].tex_index << ", " << vert_master.size() << ", " << Object.frames[frame].num_texcoords << std::endl; //assert(vert_master[i].tex_index >= 0); //assert(vert_master[i].tex_index < Object.frames[frame].num_texcoords); if (vert_master[i].tex_index < Object.frames[frame].num_texcoords) { v_texcoords[i*2+0] = Object.frames[frame].texcoords[vert_master[i].tex_index].u; v_texcoords[i*2+1] = Object.frames[frame].texcoords[vert_master[i].tex_index].v; } else { v_texcoords[i*2+0] = 0; v_texcoords[i*2+1] = 0; } } } /*for (int i = 0; i < newvertnum; i++) cout << v_vertices[i*3] << "," << v_vertices[i*3+1] << "," << v_vertices[i*3+2] << endl;*/ //assign to our mesh m_mesh.SetFaces(&v_faces[0], v_faces.size()); m_mesh.SetVertices(&v_vertices[0], v_vertices.size()); m_mesh.SetNormals(&v_normals[0], v_normals.size()); m_mesh.SetTexCoordSets(1); m_mesh.SetTexCoords(0, &v_texcoords[0], v_texcoords.size()); }
bool BEZIER::IntersectQuadrilateralF(const MATHVECTOR<float,3> & orig, const MATHVECTOR<float,3> & dir, const MATHVECTOR<float,3> & v_00, const MATHVECTOR<float,3> & v_10, const MATHVECTOR<float,3> & v_11, const MATHVECTOR<float,3> & v_01, float &t, float &u, float &v) const { const float EPSILON = 0.000001; // Reject rays that are parallel to Q, and rays that intersect the plane // of Q either on the left of the line V00V01 or below the line V00V10. MATHVECTOR<float,3> E_01 = v_10 - v_00; MATHVECTOR<float,3> E_03 = v_01 - v_00; MATHVECTOR<float,3> P = dir.cross(E_03); float det = E_01.dot(P); if (std::abs(det) < EPSILON) return false; MATHVECTOR<float,3> T = orig - v_00; float alpha = T.dot(P) / det; if (alpha < 0.0) return false; MATHVECTOR<float,3> Q = T.cross(E_01); float beta = dir.dot(Q) / det; if (beta < 0.0) return false; if (alpha + beta > 1.0) { // Reject rays that that intersect the plane of Q either on // the right of the line V11V10 or above the line V11V00. MATHVECTOR<float,3> E_23 = v_01 - v_11; MATHVECTOR<float,3> E_21 = v_10 - v_11; MATHVECTOR<float,3> P_prime = dir.cross(E_21); float det_prime = E_23.dot(P_prime); if (std::abs(det_prime) < EPSILON) return false; MATHVECTOR<float,3> T_prime = orig - v_11; float alpha_prime = T_prime.dot(P_prime) / det_prime; if (alpha_prime < 0.0) return false; MATHVECTOR<float,3> Q_prime = T_prime.cross(E_23); float beta_prime = dir.dot(Q_prime) / det_prime; if (beta_prime < 0.0) return false; } // Compute the ray parameter of the intersection point, and // reject the ray if it does not hit Q. t = E_03.dot(Q) / det; if (t < 0.0) return false; // Compute the barycentric coordinates of the fourth vertex. // These do not depend on the ray, and can be precomputed // and stored with the quadrilateral. float alpha_11, beta_11; MATHVECTOR<float,3> E_02 = v_11 - v_00; MATHVECTOR<float,3> n = E_01.cross(E_03); if ((std::abs(n[0]) >= std::abs(n[1])) && (std::abs(n[0]) >= std::abs(n[2]))) { alpha_11 = ((E_02[1] * E_03[2]) - (E_02[2] * E_03[1])) / n[0]; beta_11 = ((E_01[1] * E_02[2]) - (E_01[2] * E_02[1])) / n[0]; } else if ((std::abs(n[1]) >= std::abs(n[0])) && (std::abs(n[1]) >= std::abs(n[2]))) { alpha_11 = ((E_02[2] * E_03[0]) - (E_02[0] * E_03[2])) / n[1]; beta_11 = ((E_01[2] * E_02[0]) - (E_01[0] * E_02[2])) / n[1]; } else { alpha_11 = ((E_02[0] * E_03[1]) - (E_02[1] * E_03[0])) / n[2]; beta_11 = ((E_01[0] * E_02[1]) - (E_01[1] * E_02[0])) / n[2]; } // Compute the bilinear coordinates of the intersection point. if (std::abs(alpha_11 - (1.0)) < EPSILON) { // Q is a trapezium. u = alpha; if (std::abs(beta_11 - (1.0)) < EPSILON) v = beta; // Q is a parallelogram. else v = beta / ((u * (beta_11 - (1.0))) + (1.0)); // Q is a trapezium. } else if (std::abs(beta_11 - (1.0)) < EPSILON) { // Q is a trapezium. v = beta; if ( ((v * (alpha_11 - (1.0))) + (1.0)) == 0 ) { return false; } u = alpha / ((v * (alpha_11 - (1.0))) + (1.0)); } else { float A = (1.0) - beta_11; float B = (alpha * (beta_11 - (1.0))) - (beta * (alpha_11 - (1.0))) - (1.0); float C = alpha; float D = (B * B) - ((4.0) * A * C); if (D < 0) return false; float Q = (-0.5) * (B + ((B < (0.0) ? (-1.0) : (1.0)) * std::sqrt(D))); u = Q / A; if ((u < (0.0)) || (u > (1.0))) u = C / Q; v = beta / ((u * (beta_11 - (1.0))) + (1.0)); } return true; }
//----------------------------------------------------------------------------------- void CAR::GraphsNewVals(double dt) // CAR { size_t gsi = pApp->graphs.size(); bool tireEdit = false; // RANGE gui sld .. //const Dbl fMAX = 9000.0, max_y = 80.0, max_x = 1.0; //const Dbl fMAX = 7000.0, max_y = 180.0, max_x = 12.0, pow_x = 1.0; //const Dbl fMAX = 7000.0, max_y = 5080.0, max_x = 502.0, pow_x = 5.5; Dbl fMAX = pSet->te_yf, max_y = pSet->te_xfy, max_x = pSet->te_xfx, pow_x = pSet->te_xf_pow; if (pApp->scn->sc->asphalt) max_y *= 0.5; switch (pApp->pSet->graphs_type) { case Gh_BulletHit: /// bullet hit force,normvel, sndnum,scrap,screech if (gsi >= 6) { const CARDYNAMICS& cd = dynamics; pApp->graphs[0]->AddVal(std::min(1.f, cd.fHitForce * 2.f)); pApp->graphs[1]->AddVal(std::min(1.f, cd.fHitForce2)); pApp->graphs[2]->AddVal(std::min(1.f, cd.fHitForce3)); pApp->graphs[3]->AddVal(std::min(1.f, cd.fCarScrap)); pApp->graphs[4]->AddVal(std::min(1.f, cd.fCarScreech)); pApp->graphs[5]->AddVal(cd.fHitDmgA); } break; case Gh_CarAccelG: /// car accel x,y,z if (gsi >= 3) { MATHVECTOR<Dbl,3> v = dynamics.body.GetForce(); (-dynamics.Orientation()).RotateVector(v); float m = dynamics.body.GetMass(); //LogO("mass: "+fToStr(m,1,5)+" x: "+fToStr(v[0]/m,2,4)+" y: "+fToStr(v[1]/m,2,4)+" z: "+fToStr(v[2]/m,2,4)); for (int i=0; i < 3; ++i) pApp->graphs[i]->AddVal( std::max(0.f, std::min(1.f, float( v[i]/m *0.63f /9.81f/3.f + (i==2 ? 0.f : 0.5f) ) ))); } break; case Gh_CamBounce: /// cam bounce x,y,z if (gsi >= 3) { const MATHVECTOR<Dbl,3> v = dynamics.cam_body.GetPosition(); for (int i=0; i < 3; ++i) pApp->graphs[i]->AddVal( std::max(0.f, std::min(1.f, (float)v[i] * 3.f + 0.5f))); } break; case Gh_TireSlips: /// tire slide,slip if (gsi >= 8) for (int i=0; i < 4; ++i) { pApp->graphs[i]->AddVal(negPow(dynamics.wheel[i].slips.slideratio, 0.2) * 0.12f +0.5f); //pApp->graphs[i]->AddVal(dynamics.wheel[i].slips.slide * 0.1f +0.5f); pApp->graphs[i+4]->AddVal(dynamics.wheel[i].slips.slipratio * 0.1f +0.5f); } break; case Gh_Suspension: /// suspension if (gsi >= 8) for (int i=0; i < 4; ++i) { const CARSUSPENSION& susp = dynamics.GetSuspension((WHEEL_POSITION)i); pApp->graphs[i+4]->AddVal( dynamics.hover ? susp.GetVelocity() * 0.2f +0.5f : negPow(susp.GetVelocity(), 0.5) * 0.2f +0.5f); pApp->graphs[i]->AddVal(susp.GetDisplacementPercent()); } break; case Gh_TorqueCurve: /// torque curves, gears //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . { static int ii = 0; ++ii; // skip upd cntr if (ii >= 1/*! 10*/ && gsi >= 6*2) { ii = 0; const CARDYNAMICS& d = dynamics; const Dbl fin = d.diff_center.GetFinalDrive(); const Dbl r = 1.0 / (2 * PI_d * d.wheel[0].GetRadius()); String s0=" ratio\n", s1="rpmLow\n", s2="velMax\n"; // text legend for (int i=0; i < 6; ++i) { int g = i+1; bool bValid = i < d.transmission.GetForwardGears(); bool bCur = (g == GetGear()) && d.clutch.IsLocked(); const Dbl gr = bValid ? d.transmission.GetGearRatio(g) : 0.01, grfin = gr * fin; Dbl engRpm = d.engine.GetRPM(); Dbl downRpm = i>0 ? d.DownshiftRPM(g) : d.engine.GetStartRPM(); Dbl rmax = d.engine.GetRpmMax(), rmin = d.engine.GetStartRPM(), rng = rmax-rmin; Dbl rpmOld = 0; // graph ------ for (int x = 0; x < 512; ++x) { // 100 kmh = 28 car.m/s = 15 wh.rps = 102 eng.rps = 6100 eng.rpm // / 3.6 /1.95 (2*PI*r) *6.87 ratio = (3.9 * 1.76) 3rd gear Dbl xx = x/511.0; // 0..1 Dbl vel = xx * 250.0 / 3.6; // 250 kmh max, in m/s Dbl whrps = vel * r; // wheel revs per sec Dbl rpm = whrps * grfin * 60.0; // engine rpm Dbl tq = gr * d.engine.GetTorqueCurve(1.0, rpm); if (rpm > rmax) tq = 0.0; if (rpm < rmin) tq = 0.0; // lines down || Dbl v = tq / 2400.0; // 2400 max if (bCur && engRpm > rpmOld && engRpm <= rpm) // cur rpm mark ^ v = 1.0; pApp->graphs[i]->AddVal(v); // torque if (i>0) { v = rpm < downRpm //downRpm > rpmOld && downRpm <= rpm ? 0.0 : std::max(0.0, std::min(1.0, (rpm-rmin)/rng )); // rpm range pApp->graphs[i+6]->AddVal(v); } rpmOld = rpm; } pApp->graphs[i]->SetUpdate(); if (i>0) pApp->graphs[i+6]->SetUpdate(); // text ------ if (bValid) { Dbl velMax = 3.6 * d.engine.GetRpmMax() / (grfin * 60.0) / r; if (!bValid) velMax = 0; s0 += toStr(g)+": "+fToStr(gr,3,5)+"\n"; s1 += fToStr(downRpm,0,4)+"\n"; s2 += fToStr(velMax,0,3)+"\n"; } } s0 += " final\n "+fToStr(fin,3,5); pApp->graphs[0]->UpdTitle(s0); pApp->graphs[1]->UpdTitle(s1); pApp->graphs[2]->UpdTitle(s2); } } break; case Gh_Engine: /// engine torque, power { static int ii = 0; ++ii; // skip upd cntr if (ii >= 10 && gsi >= 2) { ii = 0; const CARENGINE& eng = dynamics.engine; float maxTrq = 0.f, maxPwr = 0.f; int rpmMaxTq = 0, rpmMaxPwr = 0; float rmin = eng.GetStartRPM(), rmax = eng.GetRpmMax(), rng = rmax - rmin; for (int x = 0; x < 512; ++x) { float r = x/512.f * rng + rmin; float tq = eng.GetTorqueCurve(1.0, r); float pwr = tq * 2.0 * PI_d * r / 60.0 * 0.001 * 1.341; //kW // 1kW = 1.341 bhp if (tq > maxTrq) { maxTrq = tq; rpmMaxTq = r; } if (pwr > maxPwr) { maxPwr = pwr; rpmMaxPwr = r; } pApp->graphs[0]->AddVal( tq / 600.0 ); pApp->graphs[1]->AddVal( pwr / 600.0 ); } pApp->graphs[0]->SetUpdate(); pApp->graphs[1]->SetUpdate(); //pApp->graphs[0]->UpdTitle(ss); } } break; case Gh_Clutch: /// clutch,rpm,gears if (gsi >= 4) { const CARENGINE& eng = dynamics.engine; const CARCLUTCH& clu = dynamics.clutch; pApp->graphs[0]->AddVal(eng.GetRPM() / 7500.0); #if 0 MATHVECTOR<Dbl,3> vel = dynamics.GetVelocity(), vx(1,0,0); dynamics.Orientation().RotateVector(vx); Dbl d = vel.dot(vx), velCar = vel.Magnitude() * (d >= 0.0 ? 1 : -1), velWh = dynamics.GetSpeedMPS(); //pApp->graphs[1]->AddVal(velCar * 0.02f)); //pApp->graphs[2]->AddVal(velWh * 0.02f); if (velWh < 1.1f && velWh > -1.1f) d = 1.f; else d = fabs(velCar >= velWh ? velCar/velWh : velWh/velCar); pApp->graphs[2]->AddVal(/*std::min(1.f, std::max(1.f,*/ d * 0.5f); #else pApp->graphs[1]->AddVal(clu.GetClutch() * 0.3f + 0.15f); pApp->graphs[2]->AddVal(clu.IsLocked() ? 0.15f : 0.f); #endif pApp->graphs[3]->AddVal(GetGear() / 6.f); } break; case Gh_Diffs: /// differentials if (gsi >= 6) for (int i=0; i < 3*2; ++i) { CARDIFFERENTIAL* diff; switch (i%3) { case 0: diff = &dynamics.diff_front; break; case 1: diff = &dynamics.diff_rear; break; case 2: diff = &dynamics.diff_center; break; } Dbl d; if (i/3==0) { d = diff->GetSide1Speed() - diff->GetSide2Speed(); d = negPow(d, 0.4)*0.07 + 0.5; } // blue else { d = diff->GetSide1Torque() - diff->GetSide2Torque(); d = d*0.0004 + 0.5; } // orange pApp->graphs[i]->AddVal(d); } break; case Gh_TireEdit: /// tire pacejka //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . { static int ii = 0; ++ii; // skip upd cntr const int im = pApp->iUpdTireGr > 0 ? 2 : 8; // faster when editing val if (ii >= im && gsi >= TireNG*2) { ii = 0; pApp->iUpdTireGr = 0; const CARTIRE* tire = dynamics.GetTire(FRONT_LEFT); Dbl* ft = new Dbl[TireLenG]; Dbl fmin, fmax, frng, maxF; const bool common = 1; // common range for all const bool cust = 1; /// Fy lateral -- for (int i=0; i < TireNG; ++i) { bool comi = common || i == 0; if (comi) { fmin = FLT_MAX; fmax = FLT_MIN; frng = 0.0; } for (int x=0; x < TireLenG; ++x) { Dbl x0 = Dbl(x) / TireLenG; //Dbl yy = max_y * 2.0 * (x-LEN*0.5) / LEN; Dbl yy = max_y * pow(x0, pow_x); Dbl n = (TireNG-1-i+1) * 0.65; Dbl fy = !pApp->iTireLoad ? tire->Pacejka_Fy(yy, n, 0, 1.0, maxF) // normF : tire->Pacejka_Fy(yy, 3, n-2, 1.0, maxF); // camber ft[x] = fy; if (comi) // get min, max { if (fy < fmin) fmin = fy; if (fy > fmax) fmax = fy; } } if (comi) // get range frng = 1.0 / (fmax - fmin); if (cust) { fmax = fMAX; fmin = 0.0; frng = 1.0 / (fmax - fmin); } for (int x = 0; x < TireLenG; ++x) pApp->graphs[i]->AddVal( (ft[x] - fmin) * frng ); pApp->graphs[i]->SetUpdate(); if (i==0) pApp->graphs[i]->UpdTitle("Fy Lateral--\n" "max y "+fToStr((float)fmax,0,1)+" x "+fToStr(max_y,0,1)+"\n"); } /// Fx long | for (int i=0; i < TireNG; ++i) { bool comi = common || i == 0; if (comi) { fmin = FLT_MAX; fmax = FLT_MIN; frng = 0.0; } for (int x=0; x < TireLenG; ++x) { Dbl x0 = Dbl(x) / TireLenG; Dbl xx = max_x * pow(x0, pow_x); Dbl n = (TireNG-1-i+1) * 0.65; Dbl fx = pApp->iEdTire != 2 ? tire->Pacejka_Fx(xx, n, 1.0, maxF) // normF : (!pApp->iTireLoad ? tire->Pacejka_Mz(xx, 0, n, 0.0, 1.0, maxF) // align- norm : tire->Pacejka_Mz(0, xx, n, 0.0, 1.0, maxF)); // align- camber ft[x] = fx; if (comi) // get min, max { if (fx < fmin) fmin = fx; if (fx > fmax) fmax = fx; } } if (comi) // get range frng = 1.0 / (fmax - fmin); if (cust) { fmax = fMAX; fmin = 0.0; frng = 1.0 / (fmax - fmin); } for (int x = 0; x < TireLenG; ++x) pApp->graphs[i+TireNG]->AddVal( (ft[x] - fmin) * frng ); pApp->graphs[i+TireNG]->SetUpdate(); if (i==0) pApp->graphs[i+TireNG]->UpdTitle("Fx Longit |\n" "max y "+fToStr((float)fmax,0,1)+" x "+fToStr(max_x,0,1)+"\n"); } delete[]ft; } } tireEdit = true; break; case Gh_Tires4Edit: /// all tires pacejka vis, edit //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . { static int ii = 0; ++ii; // skip upd cntr const int im = 1; //pApp->iUpdTireGr > 0 ? 2 : 8; // faster when editing val if (ii >= im && gsi >= TireNG*2) { ii = 0; pApp->iUpdTireGr = 0; Dbl* ft = new Dbl[TireLenG]; Dbl fmin, fmax, frng, maxF; const bool common = 1; // common range for all const bool cust = 1; /// Fy lateral -- ........ for (int i=0; i < TireNG; ++i) { WHEEL_POSITION wp = (WHEEL_POSITION)i; const CARTIRE* tire = dynamics.GetTire(wp); const CARWHEEL& wh = dynamics.GetWheel(wp); const CARWHEEL::SlideSlip& t = wh.slips; bool comi = common || i == 0; if (comi) { fmin = FLT_MAX; fmax = FLT_MIN; frng = 0.0; } Dbl yyo=0; for (int x=0; x < TireLenG; ++x) { Dbl x0 = Dbl(x) / TireLenG; Dbl yy = max_y * pow(x0, pow_x); Dbl fy = fabs(t.fy_ar * tire->Pacejka_Fy(yy, t.Fz, t.gamma, t.frict, maxF)); if (t.fy_rar > yyo && t.fy_rar <= yy) fy = 0.0; // cur mark | yyo = yy; ft[x] = fy; if (comi) // get min, max { if (fy < fmin) fmin = fy; if (fy > fmax) fmax = fy; } } if (comi) // get range frng = 1.0 / (fmax - fmin); if (cust) { fmax = fMAX; fmin = 0.0; frng = 1.0 / (fmax - fmin); } for (int x = 0; x < TireLenG; ++x) pApp->graphs[i]->AddVal( (ft[x] - fmin) * frng ); pApp->graphs[i]->SetUpdate(); if (i==0) pApp->graphs[i]->UpdTitle("Fy Lateral -- " /*"max y "+fToStr((float)fmax,0,1)+" x "+fToStr(max_y,0,1)+"\n"/**/); } /// Fx long | ........ for (int i=0; i < TireNG; ++i) { WHEEL_POSITION wp = (WHEEL_POSITION)i; const CARTIRE* tire = dynamics.GetTire(wp); const CARWHEEL& wh = dynamics.GetWheel(wp); const CARWHEEL::SlideSlip& t = wh.slips; bool comi = common || i == 0; if (comi) { fmin = FLT_MAX; fmax = FLT_MIN; frng = 0.0; } Dbl xxo=0; for (int x=0; x < TireLenG; ++x) { Dbl x0 = Dbl(x) / TireLenG; Dbl xx = max_x * pow(x0, pow_x); Dbl fx = fabs(t.fx_sr * tire->Pacejka_Fx(xx, t.Fz, t.frict, maxF)); if (t.fx_rsr > xxo && t.fx_rsr <= xx) fx = 0.0; // cur mark | xxo = xx; ft[x] = fx; if (comi) // get min, max { if (fx < fmin) fmin = fx; if (fx > fmax) fmax = fx; } } if (comi) // get range frng = 1.0 / (fmax - fmin); if (cust) { fmax = fMAX; fmin = 0.0; frng = 1.0 / (fmax - fmin); } for (int x = 0; x < TireLenG; ++x) pApp->graphs[i+TireNG]->AddVal( (ft[x] - fmin) * frng ); pApp->graphs[i+TireNG]->SetUpdate(); if (i==0) pApp->graphs[i+TireNG]->UpdTitle("Fx Longit | " /*"max y "+fToStr((float)fmax,0,1)+" x "+fToStr(max_x,0,1)+"\n"/**/); } delete[]ft; } } tireEdit = true; break; } if (tireEdit) { const CGui* g = pApp->gui; const CARTIRE* tire = dynamics.GetTire(FRONT_LEFT); String ss,sd; if (pApp->iEdTire == 0) { ss += "#A0F0FF--Lateral--\n"; sd += g->sCommon; for (int i=0; i < tire->lateral.size(); ++i) { float f = tire->lateral[i]; char p = f > 100 ? 0 : (f > 10 ? 1 : (f > 1 ? 2 : 3)); bool cur = (i == pApp->iCurLat); ss += cur ? "#A0EEFF" : "#E0FFFF"; ss += g->csLateral[i][0] +" "+ fToStr(f, p,5); ss += cur ? " <\n" : "\n"; sd += g->csLateral[i][1] +"\n"; } ss += "\n#C0F0F0alpha hat\n"; int z = (int)tire->alpha_hat.size()-1; ss += " "+fToStr( tire->alpha_hat[0], 3,5) + "\n"; ss += " "+fToStr( tire->alpha_hat[z/2], 3,5) + "\n"; ss += " "+fToStr( tire->alpha_hat[z], 3,5) + "\n"; } else if (pApp->iEdTire == 1) { ss += "#FFFF70| Longit |\n"; sd += g->sCommon; for (int i=0; i < tire->longitudinal.size(); ++i) { float f = tire->longitudinal[i]; char p = f > 100 ? 0 : (f > 10 ? 1 : (f > 1 ? 2 : 3)); bool cur = (i == pApp->iCurLong); ss += cur ? "#FFE090" : "#FFFFD0"; ss += g->csLongit[i][0] +" "+ fToStr(f, p,5); ss += cur ? " <\n" : "\n"; sd += g->csLongit[i][1] +"\n"; } ss += "\n#F0F0C0sigma hat\n"; int z = (int)tire->sigma_hat.size()-1; ss += " "+fToStr( tire->sigma_hat[0], 3,5) + "\n"; ss += " "+fToStr( tire->sigma_hat[z/2], 3,5) + "\n"; ss += " "+fToStr( tire->sigma_hat[z], 3,5) + "\n"; } pApp->graphs[gsi-2]->UpdTitle(ss); pApp->graphs[gsi-1]->UpdTitle(sd); } }
void CarModel::LoadConfig(const std::string & pathCar) { Defaults(); /// load ----- CONFIGFILE cf; if (!cf.Load(pathCar)) { LogO("!! CarModel: Can't load .car "+pathCar); return; } //- custom interior model offset cf.GetParam("model_ofs.interior-x", interiorOffset[0]); cf.GetParam("model_ofs.interior-y", interiorOffset[1]); cf.GetParam("model_ofs.interior-z", interiorOffset[2]); cf.GetParam("model_ofs.rot_fix", bRotFix); //~ boost offset cf.GetParam("model_ofs.boost-x", boostOffset[0]); cf.GetParam("model_ofs.boost-y", boostOffset[1]); cf.GetParam("model_ofs.boost-z", boostOffset[2]); cf.GetParam("model_ofs.boost-size-z", boostSizeZ); cf.GetParam("model_ofs.boost-name", sBoostParName); // thruster spaceship hover cf.GetParam("model_ofs.thrust-x", thrusterOfs[0]); cf.GetParam("model_ofs.thrust-y", thrusterOfs[1]); cf.GetParam("model_ofs.thrust-z", thrusterOfs[2]); cf.GetParam("model_ofs.thrust-size-z", thrusterSizeZ); cf.GetParam("model_ofs.thrust-name", sThrusterPar); //~ brake flares float pos[3]; bool ok=true; int i=0; while (ok) { ok = cf.GetParam("flares.brake-pos"+toStr(i), pos); ++i; if (ok) brakePos.push_back(bRotFix ? Vector3(-pos[0],pos[2],pos[1]) : Vector3(-pos[1],-pos[2],pos[0])); } cf.GetParam("flares.brake-color", pos); brakeClr = ColourValue(pos[0],pos[1],pos[2]); cf.GetParam("flares.brake-size", brakeSize); //- custom exhaust pos for boost particles if (cf.GetParam("model_ofs.exhaust-x", exhaustPos[0])) { manualExhaustPos = true; cf.GetParam("model_ofs.exhaust-y", exhaustPos[1]); cf.GetParam("model_ofs.exhaust-z", exhaustPos[2]); }else manualExhaustPos = false; if (!cf.GetParam("model_ofs.exhaust-mirror-second", has2exhausts)) has2exhausts = false; //- load cameras pos cf.GetParam("driver.view-position", pos, pGame->error_output); driver_view[0]=pos[1]; driver_view[1]=-pos[0]; driver_view[2]=pos[2]; cf.GetParam("driver.hood-position", pos, pGame->error_output); hood_view[0]=pos[1]; hood_view[1]=-pos[0]; hood_view[2]=pos[2]; // tire params WHEEL_POSITION leftside = FRONT_LEFT, rightside = FRONT_RIGHT; float value; bool both = cf.GetParam("tire-both.radius", value); std::string posstr = both ? "both" : "front"; for (int p = 0; p < 2; ++p) { if (p == 1) { leftside = REAR_LEFT; rightside = REAR_RIGHT; if (!both) posstr = "rear"; } float radius; cf.GetParam("tire-"+posstr+".radius", radius, pGame->error_output); whRadius[leftside] = radius; whRadius[rightside] = radius; float width = 0.2f; cf.GetParam("tire-"+posstr+".width-trail", width); whWidth[leftside] = width; whWidth[rightside] = width; } // wheel pos // for track's ghost or garage view int version(1); cf.GetParam("version", version); for (int i = 0; i < 4; ++i) { std::string sPos; if (i == 0) sPos = "FL"; else if (i == 1) sPos = "FR"; else if (i == 2) sPos = "RL"; else sPos = "RR"; float pos[3]; MATHVECTOR<float,3> vec; cf.GetParam("wheel-"+sPos+".position", pos, pGame->error_output); if (version == 2) ConvertV2to1(pos[0],pos[1],pos[2]); vec.Set(pos[0],pos[1], pos[2]); whPos[i] = vec; } // steer angle maxangle = 26.f; cf.GetParam("steering.max-angle", maxangle, pGame->error_output); maxangle *= pGame->GetSteerRange(); }
void MODEL::GenerateMeshMetrics() { float maxv[3] = {0, 0, 0}; float minv[3] = {0, 0, 0}; bool havevals[6]; for ( int n = 0; n < 6; n++ ) havevals[n] = false; const float * verts; int vnum; mesh.GetVertices(verts, vnum); vnum = vnum / 3; for ( int v = 0; v < vnum; v++ ) { MATHVECTOR <float, 3> temp; temp.Set ( verts + v*3 ); //cout << verts[v*3] << "," << verts[v*3+1] << "," << verts[v*3+2] << endl; //cache for bbox stuff for ( int n = 0; n < 3; n++ ) { if (!havevals[n]) { maxv[n] = temp[n]; havevals[n] = true; } else if (temp[n] > maxv[n]) maxv[n] = temp[n]; if (!havevals[n+3]) { minv[n] = temp[n]; havevals[n+3] = true; } else if (temp[n] < minv[n]) minv[n] = temp[n]; } float r = temp.Magnitude(); MATHVECTOR <float, 2> tempxz; tempxz.Set(temp[0], temp[2]); float rxz = tempxz.Magnitude(); if ( r > radius ) radius = r; if ( rxz > radiusxz ) radiusxz = rxz; } bboxmin.Set(minv[0], minv[1], minv[2]); bboxmax.Set(maxv[0], maxv[1], maxv[2]); MATHVECTOR <float, 3> center; center = (bboxmin + bboxmax)*0.5; radius = (bboxmin - center).Magnitude(); MATHVECTOR <float, 3> minv_noy = bboxmin; minv_noy[1] = 0; center[1] = 0; radiusxz = (minv_noy - center).Magnitude(); generatedmetrics = true; }
//----------------------------------------------------------------------------------- void CAR::GraphsNewVals(double dt) // CAR { size_t gsi = pApp->graphs.size(); if (pApp->pSet->graphs_type != Gh_TireEdit) switch (pApp->pSet->graphs_type) { case Gh_BulletHit: /// bullet hit force,normvel, sndnum,scrap,screech if (gsi >= 6) { const CARDYNAMICS& cd = dynamics; pApp->graphs[0]->AddVal(std::min(1.f, cd.fHitForce * 2.f)); pApp->graphs[1]->AddVal(std::min(1.f, cd.fHitForce2)); pApp->graphs[2]->AddVal(std::min(1.f, cd.fHitForce3)); pApp->graphs[3]->AddVal(std::min(1.f, cd.fCarScrap)); pApp->graphs[4]->AddVal(std::min(1.f, cd.fCarScreech)); pApp->graphs[5]->AddVal(cd.fHitDmgA); } break; case Gh_CarAccelG: /// car accel x,y,z if (gsi >= 3) { MATHVECTOR<Dbl,3> v = dynamics.body.GetForce(); (-dynamics.Orientation()).RotateVector(v); float m = dynamics.body.GetMass(); //LogO("mass: "+fToStr(m,1,5)+" x: "+fToStr(v[0]/m,2,4)+" y: "+fToStr(v[1]/m,2,4)+" z: "+fToStr(v[2]/m,2,4)); for (int i=0; i < 3; ++i) pApp->graphs[i]->AddVal( std::max(0.f, std::min(1.f, float( v[i]/m *0.63f /9.81f/3.f + (i==2 ? 0.f : 0.5f) ) ))); } break; case Gh_TireSlips: /// tire slide,slip if (gsi >= 8) for (int i=0; i < 4; ++i) { pApp->graphs[i]->AddVal(negPow(dynamics.wheel[i].slips.slideratio, 0.2) * 0.12f +0.5f); //pApp->graphs[i]->AddVal(dynamics.wheel[i].slips.slide * 0.1f +0.5f); pApp->graphs[i+4]->AddVal(dynamics.wheel[i].slips.slipratio * 0.1f +0.5f); } break; case Gh_Suspension: /// suspension if (gsi >= 8) for (int i=0; i < 4; ++i) { const CARSUSPENSION& susp = dynamics.GetSuspension((WHEEL_POSITION)i); pApp->graphs[i+4]->AddVal(negPow(susp.GetVelocity(), 0.5) * 0.2f +0.5f); pApp->graphs[i]->AddVal(susp.GetDisplacementPercent()); } break; case Gh_TorqueCurve: /// torque curves, gears //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . { static int ii = 0; ++ii; // skip upd cntr if (ii >= 1/*! 10*/ && gsi >= 6*2) { ii = 0; const CARDYNAMICS& d = dynamics; const Dbl fin = d.diff_center.GetFinalDrive(); const Dbl r = 1.0 / (2 * PI_d * d.wheel[0].GetRadius()); String s0=" ratio\n", s1="rpmLow\n", s2="velMax\n"; // text legend for (int i=0; i < 6; ++i) { int g = i+1; bool bValid = i < d.transmission.GetForwardGears(); bool bCur = (g == GetGear()) && d.clutch.IsLocked(); const Dbl gr = bValid ? d.transmission.GetGearRatio(g) : 0.01, grfin = gr * fin; Dbl engRpm = d.engine.GetRPM(); Dbl downRpm = i>0 ? d.DownshiftRPM(g) : d.engine.GetStartRPM(); Dbl rmax = d.engine.GetRpmMax(), rmin = d.engine.GetStartRPM(), rng = rmax-rmin; Dbl rpmOld = 0; // graph ------ for (int x = 0; x < 512; ++x) { // 100 kmh = 28 car.m/s = 15 wh.rps = 102 eng.rps = 6100 eng.rpm // / 3.6 /1.95 (2*PI*r) *6.87 ratio = (3.9 * 1.76) 3rd gear Dbl xx = x/511.0; // 0..1 Dbl vel = xx * 250.0 / 3.6; // 250 kmh max, in m/s Dbl whrps = vel * r; // wheel revs per sec Dbl rpm = whrps * grfin * 60.0; // engine rpm Dbl tq = gr * d.engine.GetTorqueCurve(1.0, rpm); if (rpm > rmax) tq = 0.0; if (rpm < rmin) tq = 0.0; // lines down || Dbl v = tq / 2400.0; // 2400 max if (bCur && engRpm > rpmOld && engRpm <= rpm) // cur rpm mark ^ v = 1.0; pApp->graphs[i]->AddVal(v); // torque if (i>0) { v = rpm < downRpm //downRpm > rpmOld && downRpm <= rpm ? 0.0 : std::max(0.0, std::min(1.0, (rpm-rmin)/rng )); // rpm range pApp->graphs[i+6]->AddVal(v); } rpmOld = rpm; } pApp->graphs[i]->SetUpdate(); if (i>0) pApp->graphs[i+6]->SetUpdate(); // text ------ if (bValid) { Dbl velMax = 3.6 * d.engine.GetRpmMax() / (grfin * 60.0) / r; if (!bValid) velMax = 0; s0 += toStr(g)+": "+fToStr(gr,3,5)+"\n"; s1 += fToStr(downRpm,0,4)+"\n"; s2 += fToStr(velMax,0,3)+"\n"; } } s0 += " final\n "+fToStr(fin,3,5); pApp->graphs[0]->UpdTitle(s0); pApp->graphs[1]->UpdTitle(s1); pApp->graphs[2]->UpdTitle(s2); } } break; case Gh_Engine: /// engine torque, power { static int ii = 0; ++ii; // skip upd cntr if (ii >= 10 && gsi >= 2) { ii = 0; const CARENGINE& eng = dynamics.engine; float maxTrq = 0.f, maxPwr = 0.f; int rpmMaxTq = 0, rpmMaxPwr = 0; float rmin = eng.GetStartRPM(), rmax = eng.GetRpmMax(), rng = rmax - rmin; for (int x = 0; x < 512; ++x) { float r = x/512.f * rng + rmin; float tq = eng.GetTorqueCurve(1.0, r); float pwr = tq * 2.0 * PI_d * r / 60.0 * 0.001 * 1.341; //kW // 1kW = 1.341 bhp if (tq > maxTrq) { maxTrq = tq; rpmMaxTq = r; } if (pwr > maxPwr) { maxPwr = pwr; rpmMaxPwr = r; } pApp->graphs[0]->AddVal( tq / 600.0 ); pApp->graphs[1]->AddVal( pwr / 600.0 ); } pApp->graphs[0]->SetUpdate(); pApp->graphs[1]->SetUpdate(); //pApp->graphs[0]->UpdTitle(ss); } } break; case Gh_Clutch: /// clutch,rpm,gears if (gsi >= 4) { const CARENGINE& eng = dynamics.engine; const CARCLUTCH& clu = dynamics.clutch; pApp->graphs[0]->AddVal(eng.GetRPM() / 7500.0); #if 0 MATHVECTOR<Dbl,3> vel = dynamics.GetVelocity(), vx(1,0,0); dynamics.Orientation().RotateVector(vx); Dbl d = vel.dot(vx), velCar = vel.Magnitude() * (d >= 0.0 ? 1 : -1), velWh = dynamics.GetSpeedMPS(); //pApp->graphs[1]->AddVal(velCar * 0.02f)); //pApp->graphs[2]->AddVal(velWh * 0.02f); if (velWh < 1.1f && velWh > -1.1f) d = 1.f; else d = fabs(velCar >= velWh ? velCar/velWh : velWh/velCar); pApp->graphs[2]->AddVal(/*std::min(1.f, std::max(1.f,*/ d * 0.5f); #else pApp->graphs[1]->AddVal(clu.GetClutch() * 0.3f + 0.15f); pApp->graphs[2]->AddVal(clu.IsLocked() ? 0.15f : 0.f); #endif pApp->graphs[3]->AddVal(GetGear() / 6.f); } break; case Gh_Diffs: /// differentials if (gsi >= 6) for (int i=0; i < 3*2; ++i) { CARDIFFERENTIAL* diff; switch (i%3) { case 0: diff = &dynamics.diff_front; break; case 1: diff = &dynamics.diff_rear; break; case 2: diff = &dynamics.diff_center; break; } Dbl d; if (i/3==0) { d = diff->GetSide1Speed() - diff->GetSide2Speed(); d = negPow(d, 0.4)*0.07 + 0.5; } // blue else { d = diff->GetSide1Torque() - diff->GetSide2Torque(); d = d*0.0004 + 0.5; } // orange pApp->graphs[i]->AddVal(d); } break; } else ///Gh_TireEdit: /// tire pacejka //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . { static int ii = 0; ++ii; // skip upd cntr const int im = pApp->iUpdTireGr > 0 ? 2 : 8; // faster when editing val if (ii >= im && gsi >= TireNG*2) { ii = 0; pApp->iUpdTireGr = 0; const CARTIRE* tire = dynamics.GetTire(FRONT_LEFT); Dbl* ft = new Dbl[TireLenG]; Dbl fmin, fmax, frng, maxF; const bool common = 1; // common range for all const bool cust = 1; // RANGE gui sld .. const Dbl fMAX = 9000.0, max_y = pApp->sc->asphalt ? 40.0 : 80.0, max_x = 1.0; /// Fy lateral -- for (int i=0; i < TireNG; ++i) { bool comi = common || i == 0; if (comi) { fmin = FLT_MAX; fmax = FLT_MIN; frng = 0.0; } for (int x=0; x < TireLenG; ++x) { //Dbl yy = max_y * 2.0 * (x-LEN*0.5) / LEN; Dbl yy = max_y * x / TireLenG; Dbl n = (TireNG-1-i+1) * 0.65; Dbl fy = !pApp->iTireLoad ? tire->Pacejka_Fy(yy, n, 0, 1.0, maxF) // normF : tire->Pacejka_Fy(yy, 3, n-2, 1.0, maxF); // camber ft[x] = fy; if (comi) // get min, max { if (fy < fmin) fmin = fy; if (fy > fmax) fmax = fy; } } if (comi) // get range frng = 1.0 / (fmax - fmin); if (cust) { fmax = fMAX; fmin = 0.0; frng = 1.0 / (fmax - fmin); } for (int x = 0; x < TireLenG; ++x) pApp->graphs[i]->AddVal( (ft[x] - fmin) * frng ); pApp->graphs[i]->SetUpdate(); if (i==0) pApp->graphs[i]->UpdTitle("Fy Lateral--\n" //#33FF77 //"min: "+fToStr((float)fmin,2,4)+"\n"+ "max y "+fToStr((float)fmax,0,1)+ " x "+fToStr(max_y,0,1)+"\n"); } /// Fx long | for (int i=0; i < TireNG; ++i) { bool comi = common || i == 0; if (comi) { fmin = FLT_MAX; fmax = FLT_MIN; frng = 0.0; } for (int x=0; x < TireLenG; ++x) { //Dbl xx = max_x * 2.0 * (x-LEN*0.5) / LEN; Dbl xx = max_x * x / TireLenG; Dbl n = (TireNG-1-i+1) * 0.65; Dbl fx = pApp->iEdTire != 2 ? tire->Pacejka_Fx(xx, n, 1.0, maxF) // normF : (!pApp->iTireLoad ? tire->Pacejka_Mz(xx, 0, n, 0.0, 1.0, maxF) // align- norm : tire->Pacejka_Mz(0, xx, n, 0.0, 1.0, maxF)); // align- camber ft[x] = fx; if (comi) // get min, max { if (fx < fmin) fmin = fx; if (fx > fmax) fmax = fx; } } if (comi) // get range frng = 1.0 / (fmax - fmin); if (cust) { fmax = fMAX; fmin = 0.0; frng = 1.0 / (fmax - fmin); } for (int x = 0; x < TireLenG; ++x) pApp->graphs[i+TireNG]->AddVal( (ft[x] - fmin) * frng ); pApp->graphs[i+TireNG]->SetUpdate(); if (i==0) pApp->graphs[i+TireNG]->UpdTitle("Fx Longit |\n" //"min: "+fToStr((float)fmin,2,4)+"\n"+ "max y "+fToStr((float)fmax,0,1)+ " x "+fToStr(max_x,0,1)+"\n"); } delete[]ft; // update edit values text and descr ///---------------------------------------------------- const static String sLateral[15][2] = { " a0","#F0FFFFShape factor", " a1","#C0E0FFLoad infl. on friction coeff", " a2","#F0FFFFLateral friction coeff at load = 0", " a3","#F0FFFFMaximum stiffness", " a4","#F0FFFFLoad at maximum stiffness", " a5","#C0E0FF-Camber infl. on stiffness", " a6","Curvature change with load", " a7","Curvature at load = 0", " a8","#A0C0D0 -Horiz. shift because of camber", " a9"," Load infl. on horizontal shift", " a10"," Horizontal shift at load = 0", "a111"," -Camber infl. on vertical shift", "a112"," -Camber infl. on vertical shift", " a12"," Load infl. on vertical shift", " a13"," Vertical shift at load = 0" }; const static String sLongit[13][2] = { " b0","#FFFFF0Shape factor", " b1","#F0F0A0Load infl. on long. friction coeff", " b2","#FFFFF0Longit. friction coeff at load = 0", " b3","#F0F0A0Curvature factor of stiffness", " b4","#F0F0A0Change of stiffness with load at load = 0", " b5","#E0C080Change of progressivity/load", //of stiffness " b6","Curvature change with load^2", " b7","Curvature change with load", " b8","Curvature at load = 0", " b9","#D0D0A0 Load infl. on horizontal shift", " b10"," Horizontal shift at load = 0", " b11"," Load infl. on vertical shift", " b12"," Vertical shift at load = 0" }; const static String sAlign[18][2] = { " c0","#E0FFE0Shape factor", " c1","Load infl. of peak value", " c2","Load infl. of peak value", " c3","Curvature factor of stiffness", " c4","Change of stiffness with load at load = 0", " c5","Change of progressivity/load", " c6","-Camber infl. on stiffness", " c7","Curvature change with load", " c8","Curvature change with load", " c9","Curvature at load = 0", "c10","-Camber infl. of stiffness", "c11"," -Camber infl. on horizontal shift", "c12"," Load infl. on horizontal shift", "c13"," Horizontal shift at load = 0", "c14"," -Camber infl. on vertical shift", "c15"," -Camber infl. on vertical shift", "c16"," Load infl. on vertical shift", "c17"," Vertical shift at load = 0" }; const static String sCommon = "#C8C8F0Pacejka's Magic Formula coeffs\n"; String ss,sd; if (pApp->iEdTire == 0) { ss += "#A0F0FF--Lateral--\n"; sd += sCommon; for (int i=0; i < tire->lateral.size(); ++i) { //ss += (i == pApp->iCurLat) ? "." : " "; float f = tire->lateral[i]; char p = f > 100 ? 0 : (f > 10 ? 1 : (f > 1 ? 2 : 3)); bool cur = (i == pApp->iCurLat); ss += cur ? "#A0EEFF" : "#E0FFFF"; ss += sLateral[i][0] +" "+ fToStr(f, p,5); ss += cur ? " <\n" : "\n"; sd += sLateral[i][1] +"\n"; } ss += "\n#C0F0F0alpha hat\n"; //for (int a=0; a < tire->alpha_hat.size(); ++a) // ss += " "+fToStr( tire->alpha_hat[a], 3,5) + "\n"; int z = (int)tire->alpha_hat.size()-1; ss += " "+fToStr( tire->alpha_hat[0], 3,5) + "\n"; ss += " "+fToStr( tire->alpha_hat[z/2], 3,5) + "\n"; ss += " "+fToStr( tire->alpha_hat[z], 3,5) + "\n"; } else if (pApp->iEdTire == 1) { ss += "#FFFF70| Longit |\n"; sd += sCommon; for (int i=0; i < tire->longitudinal.size(); ++i) { //ss += (i == pApp->iCurLong) ? "." : " "; float f = tire->longitudinal[i]; char p = f > 100 ? 0 : (f > 10 ? 1 : (f > 1 ? 2 : 3)); bool cur = (i == pApp->iCurLong); ss += cur ? "#FFE090" : "#FFFFD0"; ss += sLongit[i][0] +" "+ fToStr(f, p,5); ss += cur ? " <\n" : "\n"; sd += sLongit[i][1] +"\n"; } ss += "\n#F0F0C0sigma hat\n"; //for (int a=0; a < tire->sigma_hat.size(); ++a) // ss += " "+fToStr( tire->sigma_hat[a], 3,5) + "\n"; int z = (int)tire->sigma_hat.size()-1; ss += " "+fToStr( tire->sigma_hat[0], 3,5) + "\n"; ss += " "+fToStr( tire->sigma_hat[z/2], 3,5) + "\n"; ss += " "+fToStr( tire->sigma_hat[z], 3,5) + "\n"; } else //if (pApp->iEdTire == 2) { ss += "#D0FFD0o Align o\n"; sd += sCommon; for (int i=0; i < tire->aligning.size(); ++i) { float f = tire->aligning[i]; char p = f > 100 ? 0 : (f > 10 ? 1 : (f > 1 ? 2 : 3)); bool cur = (i == pApp->iCurAlign); ss += cur ? "#80FF80" : "#E0FFE0"; ss += sAlign[i][0] +" "+ fToStr(f, p,5); ss += cur ? " <\n" : "\n"; sd += sAlign[i][1] +"\n"; } } pApp->graphs[gsi-2]->UpdTitle(ss); pApp->graphs[gsi-1]->UpdTitle(sd); pApp->graphs[2]->UpdTitle(TireVar[pApp->iTireLoad]); //- } } }
void BEZIER::SetFromCorners(const MATHVECTOR<float,3> & fl, const MATHVECTOR<float,3> & fr, const MATHVECTOR<float,3> & bl, const MATHVECTOR<float,3> & br) { MATHVECTOR<float,3> temp; center = fl + fr + bl + br; center = center*0.25; radius = 0; if ((fl - center).Magnitude() > radius) radius = (fl - center).Magnitude(); if ((fr - center).Magnitude() > radius) radius = (fr - center).Magnitude(); if ((bl - center).Magnitude() > radius) radius = (bl - center).Magnitude(); if ((br - center).Magnitude() > radius) radius = (br - center).Magnitude(); //assign corners points[0][0] = fl; points[0][3] = fr; points[3][3] = br; points[3][0] = bl; //calculate intermediate front and back points temp = fr - fl; if (temp.Magnitude() < 0.0001) { points[0][1] = fl; points[0][2] = fl; } else { points[0][1] = fl + temp.Normalize()*(temp.Magnitude()/3.0); points[0][2] = fl + temp.Normalize()*(2.0*temp.Magnitude()/3.0); } temp = br - bl; if (temp.Magnitude() < 0.0001) { points[3][1] = bl; points[3][2] = bl; } else { points[3][1] = bl + temp.Normalize()*(temp.Magnitude()/3.0); points[3][2] = bl + temp.Normalize()*(2.0*temp.Magnitude()/3.0); } //calculate intermediate left and right points int i; for (i = 0; i < 4; i++) { temp = points[3][i] - points[0][i]; if (temp.Magnitude() > 0.0001) { points[1][i] = points[0][i] + temp.Normalize()*(temp.Magnitude()/3.0); points[2][i] = points[0][i] + temp.Normalize()*(2.0*temp.Magnitude()/3.0); } else { points[1][i] = points[0][i]; points[2][i] = points[0][i]; } } //CheckForProblems(); }
//---------------------------------------------------------------------------------------------------------------------------------- /// Load (.car file) //---------------------------------------------------------------------------------------------------------------------------------- bool CARDYNAMICS::Load(GAME* pGame, CONFIGFILE & c, ostream & error_output) { QTimer ti; ti.update(); /// time //bTerrain = false; string drive = "RWD"; int version(1); c.GetParam("version", version); if (version > 2) { error_output << "Unsupported car version: " << version << endl; return false; } float temp_vec3[3]; //load the engine { float mass, rpm_limit, inertia, friction, start_rpm, stall_rpm, fuel_consumption; MATHVECTOR<double,3> position; if (!c.GetParam("engine.rpm-limit", rpm_limit, error_output)) return false; engine.SetRpmMax(rpm_limit); if (!c.GetParam("engine.inertia", inertia, error_output)) return false; engine.SetInertia(inertia); if (!c.GetParam("engine.friction", friction, error_output)) return false; engine.SetFrictionB(friction); if (!c.GetParam("engine.start-rpm", start_rpm, error_output)) return false; engine.SetStartRPM(start_rpm); if (!c.GetParam("engine.stall-rpm", stall_rpm, error_output)) return false; engine.SetStallRPM(stall_rpm); if (!c.GetParam("engine.fuel-consumption", fuel_consumption, error_output)) return false; engine.SetFuelConsumption(fuel_consumption); if (!c.GetParam("engine.mass", mass, error_output)) return false; if (!c.GetParam("engine.position", temp_vec3, error_output)) return false; if (version == 2) ConvertV2to1(temp_vec3[0],temp_vec3[1],temp_vec3[2]); position.Set(temp_vec3[0],temp_vec3[1],temp_vec3[2]); engine.SetMass(mass); engine.SetPosition(position); AddMassParticle(mass, position); float mul = 1.f, max_torque = 0; c.GetParam("engine.torque-val-mul", mul); float torque_point[3]; string torque_str("engine.torque-curve-00"); vector <pair <double, double> > torques; int curve_num = 0; while (c.GetParam(torque_str, torque_point)) { max_torque = max(max_torque, torque_point[1] * mul); torques.push_back(pair <float, float> (torque_point[0], torque_point[1] * mul)); curve_num++; stringstream str; str << "engine.torque-curve-"; str.width(2); str.fill('0'); str << curve_num; torque_str = str.str(); } if (torques.size() <= 1) { error_output << "You must define at least 2 torque curve points." << endl; return false; } engine.SetTorqueCurve(rpm_limit, torques); //load the clutch { float mul; //max_torque = sliding * radius * area * max_pressure; //if (!c.GetParam("clutch.max-torque", max_torque, error_output)) return false; if (!c.GetParam("clutch.max-torque-mul", mul, error_output)) return false; clutch.SetMaxTorque(max_torque * mul); } // factor for stats - mul = 1.f; if (c.GetParam("engine.real-pow-tq-mul", mul)) engine.real_pow_tq_mul = mul; mul = 1.f; if (c.GetParam("engine.sound-vol-mul", mul)) engine_vol_mul = mul; } //load the transmission { float time = 0; float ratio; int gears; c.GetParam("transmission.shift-delay", time); shift_time = time; if (!c.GetParam("transmission.gear-ratio-r", ratio, error_output)) return false; transmission.SetGearRatio(-1, ratio); if (!c.GetParam("transmission.gears", gears, error_output)) return false; for (int i = 0; i < gears; i++) { stringstream s; s << "transmission.gear-ratio-" << i+1; if (!c.GetParam(s.str(), ratio, error_output)) return false; transmission.SetGearRatio(i+1, ratio); } } //load the differential(s) string drivetype; if (!c.GetParam("drive", drivetype, error_output)) return false; SetDrive(drivetype); float final_drive, a, a_tq(0), a_tq_dec(0); /// new 3 sets if (drivetype == "AWD" && c.GetParam("diff-center.final-drive", a)) { c.GetParam("diff-rear.anti-slip", a, error_output); c.GetParam("diff-rear.torque", a_tq); c.GetParam("diff-rear.torque-dec", a_tq_dec); diff_rear.SetFinalDrive(1.0); diff_rear.SetAntiSlip(a, a_tq, a_tq_dec); c.GetParam("diff-front.anti-slip", a, error_output); c.GetParam("diff-front.torque", a_tq); c.GetParam("diff-front.torque-dec", a_tq_dec); diff_front.SetFinalDrive(1.0); diff_front.SetAntiSlip(a, a_tq, a_tq_dec); c.GetParam("diff-center.final-drive", final_drive, error_output); c.GetParam("diff-center.anti-slip", a, error_output); c.GetParam("diff-center.torque", a_tq); c.GetParam("diff-center.torque-dec", a_tq_dec); diff_center.SetFinalDrive(final_drive); diff_center.SetAntiSlip(a, a_tq, a_tq_dec); } else // old 1 for all { if (!c.GetParam("differential.final-drive", final_drive, error_output)) return false; if (!c.GetParam("differential.anti-slip", a, error_output)) return false; c.GetParam("differential.torque", a_tq); c.GetParam("differential.torque-dec", a_tq_dec); if (drivetype == "RWD") { diff_rear.SetFinalDrive(final_drive); diff_rear.SetAntiSlip(a, a_tq, a_tq_dec); } else if (drivetype == "FWD") { diff_front.SetFinalDrive(final_drive); diff_front.SetAntiSlip(a, a_tq, a_tq_dec); } else if (drivetype == "AWD") { diff_rear.SetFinalDrive(1.0); diff_rear.SetAntiSlip(a, a_tq, a_tq_dec); diff_front.SetFinalDrive(1.0); diff_front.SetAntiSlip(a, a_tq, a_tq_dec); diff_center.SetFinalDrive(final_drive); diff_center.SetAntiSlip(a, a_tq, a_tq_dec); }else { error_output << "Unknown drive type: " << drive << endl; return false; } } //load the brake { for (int i = 0; i < 2; i++) { string pos = "front"; WHEEL_POSITION left = FRONT_LEFT; WHEEL_POSITION right = FRONT_RIGHT; if (i == 1) { left = REAR_LEFT; right = REAR_RIGHT; pos = "rear"; } float friction, max_pressure, area, bias, radius, handbrake(0); if (!c.GetParam("brakes-"+pos+".friction", friction, error_output)) return false; brake[left].SetFriction(friction); brake[right].SetFriction(friction); if (!c.GetParam("brakes-"+pos+".area", area, error_output)) return false; brake[left].SetArea(area); brake[right].SetArea(area); if (!c.GetParam("brakes-"+pos+".radius", radius, error_output)) return false; brake[left].SetRadius(radius); brake[right].SetRadius(radius); c.GetParam("brakes-"+pos+".handbrake", handbrake); brake[left].SetHandbrake(handbrake); brake[right].SetHandbrake(handbrake); if (!c.GetParam("brakes-"+pos+".bias", bias, error_output)) return false; brake[left].SetBias(bias); brake[right].SetBias(bias); if (!c.GetParam("brakes-"+pos+".max-pressure", max_pressure, error_output)) return false; brake[left].SetMaxPressure(max_pressure*bias); brake[right].SetMaxPressure(max_pressure*bias); } } //load the fuel tank { float pos[3]; MATHVECTOR<double,3> position; float capacity, volume, fuel_density; if (!c.GetParam("fuel-tank.capacity", capacity, error_output)) return false; fuel_tank.SetCapacity(capacity); if (!c.GetParam("fuel-tank.volume", volume, error_output)) return false; fuel_tank.SetVolume(volume); if (!c.GetParam("fuel-tank.fuel-density", fuel_density, error_output)) return false; fuel_tank.SetDensity(fuel_density); if (!c.GetParam("fuel-tank.position", pos, error_output)) return false; if (version == 2) ConvertV2to1(pos[0],pos[1],pos[2]); position.Set(pos[0],pos[1],pos[2]); fuel_tank.SetPosition(position); //AddMassParticle(fuel_density*volume, position); } //load the suspension { for (int i = 0; i < 2; i++) { string posstr = "front"; string posshortstr = "F"; WHEEL_POSITION posl = FRONT_LEFT; WHEEL_POSITION posr = FRONT_RIGHT; if (i == 1) { posstr = "rear"; posshortstr = "R"; posl = REAR_LEFT; posr = REAR_RIGHT; } float spring_constant, bounce, rebound, travel, camber, caster, toe, anti_roll;//, maxcompvel; float hinge[3]; MATHVECTOR<double,3> tempvec; if (!c.GetParam("suspension-"+posstr+".spring-constant", spring_constant, error_output)) return false; suspension[posl].SetSpringConstant(spring_constant); suspension[posr].SetSpringConstant(spring_constant); if (!c.GetParam("suspension-"+posstr+".bounce", bounce, error_output)) return false; suspension[posl].SetBounce(bounce); suspension[posr].SetBounce(bounce); if (!c.GetParam("suspension-"+posstr+".rebound", rebound, error_output)) return false; suspension[posl].SetRebound(rebound); suspension[posr].SetRebound(rebound); string file; if (c.GetParam("suspension-"+posstr+".factors-file", file)) { int id = pGame->suspS_map[file]-1; if (id == -1) { id = 0; error_output << "Can't find suspension spring factors file: " << file << endl; } suspension[posl].SetSpringFactorPoints(pGame->suspS[id]); suspension[posr].SetSpringFactorPoints(pGame->suspS[id]); id = pGame->suspD_map[file]-1; if (id == -1) { id = 0; error_output << "Can't find suspension damper factors file: " << file << endl; } suspension[posl].SetDamperFactorPoints(pGame->suspD[id]); suspension[posr].SetDamperFactorPoints(pGame->suspD[id]); }else { // factor points vector <pair <double, double> > damper, spring; c.GetPoints("suspension-"+posstr, "damper-factor", damper); suspension[posl].SetDamperFactorPoints(damper); suspension[posr].SetDamperFactorPoints(damper); c.GetPoints("suspension-"+posstr, "spring-factor", spring); suspension[posl].SetSpringFactorPoints(spring); suspension[posr].SetSpringFactorPoints(spring); } if (!c.GetParam("suspension-"+posstr+".travel", travel, error_output)) return false; suspension[posl].SetTravel(travel); suspension[posr].SetTravel(travel); if (!c.GetParam("suspension-"+posstr+".camber", camber, error_output)) return false; suspension[posl].SetCamber(camber); suspension[posr].SetCamber(camber); if (!c.GetParam("suspension-"+posstr+".caster", caster, error_output)) return false; suspension[posl].SetCaster(caster); suspension[posr].SetCaster(caster); if (!c.GetParam("suspension-"+posstr+".toe", toe, error_output)) return false; suspension[posl].SetToe(toe); suspension[posr].SetToe(toe); if (!c.GetParam("suspension-"+posstr+".anti-roll", anti_roll, error_output)) return false; suspension[posl].SetAntiRollK(anti_roll); suspension[posr].SetAntiRollK(anti_roll); if (!c.GetParam("suspension-"+posshortstr+"L.hinge", hinge, error_output)) return false; //cap hinge to reasonable values for (int i = 0; i < 3; i++) { if (hinge[i] < -100) hinge[i] = -100; if (hinge[i] > 100) hinge[i] = 100; } if (version == 2) ConvertV2to1(hinge[0],hinge[1],hinge[2]); tempvec.Set(hinge[0],hinge[1], hinge[2]); suspension[posl].SetHinge(tempvec); if (!c.GetParam("suspension-"+posshortstr+"R.hinge", hinge, error_output)) return false; for (int i = 0; i < 3; i++) { if (hinge[i] < -100) hinge[i] = -100; if (hinge[i] > 100) hinge[i] = 100; } if (version == 2) ConvertV2to1(hinge[0],hinge[1],hinge[2]); tempvec.Set(hinge[0],hinge[1], hinge[2]); suspension[posr].SetHinge(tempvec); } } //load the wheels { for (int i = 0; i < 4; i++) { string sPos; WHEEL_POSITION wp; if (i == 0) { sPos = "FL"; wp = FRONT_LEFT; } else if (i == 1){ sPos = "FR"; wp = FRONT_RIGHT; } else if (i == 2){ sPos = "RL"; wp = REAR_LEFT; } else { sPos = "RR"; wp = REAR_RIGHT; } float roll_h, mass; float pos[3]; MATHVECTOR<double,3> vec; if (!c.GetParam("wheel-"+sPos+".mass", mass, error_output)) return false; wheel[wp].SetMass(mass); if (!c.GetParam("wheel-"+sPos+".roll-height", roll_h, error_output)) return false; wheel[wp].SetRollHeight(roll_h); if (!c.GetParam("wheel-"+sPos+".position", pos, error_output)) return false; if (version == 2) ConvertV2to1(pos[0],pos[1],pos[2]); vec.Set(pos[0],pos[1], pos[2]); wheel[wp].SetExtendedPosition(vec); AddMassParticle(mass, vec); } //load the rotational inertia parameter from the tire section float front_inertia; float rear_inertia; if (c.GetParam("tire-both.rotational-inertia", front_inertia, error_output)) rear_inertia = front_inertia; else { if (!c.GetParam("tire-front.rotational-inertia", front_inertia, error_output)) return false; if (!c.GetParam("tire-rear.rotational-inertia", rear_inertia, error_output)) return false; } wheel[FRONT_LEFT].SetInertia(front_inertia); wheel[FRONT_RIGHT].SetInertia(front_inertia); wheel[REAR_LEFT].SetInertia(rear_inertia); wheel[REAR_RIGHT].SetInertia(rear_inertia); } //load the tire parameters { WHEEL_POSITION leftside = FRONT_LEFT; WHEEL_POSITION rightside = FRONT_RIGHT; float value; bool both = c.GetParam("tire-both.radius", value); string posstr = both ? "both" : "front"; for (int p = 0; p < 2; ++p) { if (p == 1) { leftside = REAR_LEFT; rightside = REAR_RIGHT; if (!both) posstr = "rear"; } float rolling_resistance[3]; if (!c.GetParam("tire-"+posstr+".rolling-resistance", rolling_resistance, error_output)) return false; wheel[leftside].SetRollingResistance(rolling_resistance[0], rolling_resistance[1]); wheel[rightside].SetRollingResistance(rolling_resistance[0], rolling_resistance[1]); float radius; if (!c.GetParam("tire-"+posstr+".radius", radius, error_output)) return false; wheel[leftside].SetRadius(radius); wheel[rightside].SetRadius(radius); } } //load the mass-only particles { MATHVECTOR<double,3> position; float pos[3], mass; if (c.GetParam("contact-points.mass", mass)) { int paramnum(0); string paramname("contact-points.position-00"); stringstream output_supression; while (c.GetParam(paramname, pos)) { if (version == 2) ConvertV2to1(pos[0],pos[1],pos[2]); position.Set(pos[0],pos[1],pos[2]); AddMassParticle(mass, position); paramnum++; stringstream str; str << "contact-points.position-"; str.width(2); str.fill('0'); str << paramnum; paramname = str.str(); } } string paramname = "particle-00"; int paramnum = 0; while (c.GetParam(paramname+".mass", mass)) { if (!c.GetParam(paramname+".position", pos, error_output)) return false; if (version == 2) ConvertV2to1(pos[0],pos[1],pos[2]); position.Set(pos[0],pos[1],pos[2]); AddMassParticle(mass, position); paramnum++; stringstream str; str << "particle-"; str.width(2); str.fill('0'); str << paramnum; paramname = str.str(); } } //load the max steering angle { float maxangle = 26.f; if (!c.GetParam("steering.max-angle", maxangle, error_output)) return false; SetMaxSteeringAngle( maxangle ); float a = 1.f; c.GetParam("steering.flip-pow-mul", a); flip_mul = a; } ///car angular damping -new { float a = 0.4f; c.GetParam("steering.angular-damping", a, error_output); SetAngDamp(a); a=0.f; c.GetParam("rot_drag.roll", a); rot_coef[0] = a; a=0.f; c.GetParam("rot_drag.pitch", a); rot_coef[1] = a; a=0.f; c.GetParam("rot_drag.yaw", a); rot_coef[2] = a; a=0.f; c.GetParam("rot_drag.yaw2", a); rot_coef[3] = a; } //load the driver { float mass; float pos[3]; MATHVECTOR<double,3> position; if (!c.GetParam("driver.mass", mass, error_output)) return false; if (!c.GetParam("driver.position", pos, error_output)) return false; if (version == 2) ConvertV2to1(pos[0],pos[1],pos[2]); position.Set(pos[0], pos[1], pos[2]); AddMassParticle(mass, position); } //load the aerodynamics { float drag_area, drag_c, lift_area, lift_c, lift_eff; float pos[3]; MATHVECTOR<double,3> position; if (!c.GetParam("drag.frontal-area", drag_area, error_output)) return false; if (!c.GetParam("drag.drag-coefficient", drag_c, error_output)) return false; if (!c.GetParam("drag.position", pos, error_output)) return false; if (version == 2) ConvertV2to1(pos[0],pos[1],pos[2]); position.Set(pos[0], pos[1], pos[2]); AddAerodynamicDevice(position, drag_area, drag_c, 0,0,0); for (int i = 0; i < 2; i++) { string wingpos = "front"; if (i == 1) wingpos = "rear"; if (!c.GetParam("wing-"+wingpos+".frontal-area", drag_area, error_output)) return false; if (!c.GetParam("wing-"+wingpos+".drag-coefficient", drag_c, error_output)) return false; if (!c.GetParam("wing-"+wingpos+".surface-area", lift_area, error_output)) return false; if (!c.GetParam("wing-"+wingpos+".lift-coefficient", lift_c, error_output)) return false; if (!c.GetParam("wing-"+wingpos+".efficiency", lift_eff, error_output)) return false; if (!c.GetParam("wing-"+wingpos+".position", pos, error_output)) return false; if (version == 2) ConvertV2to1(pos[0],pos[1],pos[2]); position.Set(pos[0], pos[1], pos[2]); AddAerodynamicDevice(position, drag_area, drag_c, lift_area, lift_c, lift_eff); } } UpdateMass(); ti.update(); /// time float dt = ti.dt * 1000.f; LogO(Ogre::String(":::: Time car dynamics load: ") + fToStr(dt,0,3) + " ms"); return true; }
void FollowCamera::update( Real time ) { if (!mGoalNode || !ca || !mCamera) return; Vector3 posGoal = mGoalNode ? mGoalNode->getPosition() : Vector3::UNIT_Y; Quaternion orientGoal = mGoalNode ? mGoalNode->getOrientation() : Quaternion::IDENTITY; 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; if (ca->mType == CAM_Car) /* 3 Car - car pos & rot full */ { mCamera->setPosition( goalLook ); mCamera->setOrientation( orient ); updInfo(time); return; } if (ca->mType == CAM_Follow) ofs = ca->mOffset; Vector3 pos,goalPos; pos = mCamera->getPosition() - ofs; goalPos = posGoal; Vector3 xyz; if (ca->mType != CAM_Arena) { Real x,y,z,xz; // pitch & yaw to direction vector Real ap = 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; first = false; } 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.001f, 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 } Quaternion qy = Quaternion(ca->mYaw,Vector3(0,1,0)); goalPos += qq * (xyz + ca->mOffset); mCamera->setPosition( goalPos ); mCamera->setOrientation( qq * qy * Quaternion(Degree(-ca->mPitch),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 = mCamera->getPosition(); Pos += (goalPos - Pos) * dtmul; static Radian pitch(0), yaw(0); pitch += (ca->mPitch - pitch) * dtmul; yaw += (ca->mYaw - yaw) * dtmul; if (first) { Pos = goalPos; pitch = ca->mPitch; yaw = ca->mYaw; first = false; } mCamera->setPosition( Pos ); mCamera->setOrientation(Quaternion::IDENTITY); mCamera->pitch(pitch); mCamera->yaw(yaw); 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; mCamera->setPosition( pos + ofs ); if (mGoalNode) goalLook = posGoal + ofs; if (first) { mLook = goalLook; first = false; } addLook = (goalLook - mLook) * dtmul;//Rot; mLook += addLook; } } /// cast ray from car to camera, to prevent objects blocking the camera's sight #ifdef CAM_BLT // update sphere pos btVector3 carPos = BtOgre::Convert::toBullet(posGoal); state->setWorldTransform( btTransform(btQuaternion(0,0,0,1), carPos )); // calculate origin & direction of the ray, convert to vdrift coordinates MATHVECTOR<float,3> origin; origin.Set( carPos.x(), carPos.y(), carPos.z() ); MATHVECTOR<float,3> direction; btVector3 dir = BtOgre::Convert::toBullet(mCamera->getPosition()-posGoal); direction.Set(dir.x(), dir.y(), dir.z()); Real distance = (mCamera->getPosition()-posGoal ).length(); int pOnRoad; // shoot our ray COLLISION_CONTACT contact; mWorld->CastRay( origin, direction, distance, body, contact, &pOnRoad ); if (contact.col != NULL) { LogO("Collision occured"); // collision occured - update cam pos mCamera->setPosition( BtOgre::Convert::toOgre( btVector3(contact.GetPosition()[0], contact.GetPosition()[1], contact.GetPosition()[2]) ) ); } #endif moveAboveTerrain(); if (!manualOrient) mCamera->lookAt( mLook ); updInfo(time); }