void Jumper::StandingJump::update(float dt) { updateAnimation( dt ); _clump->getFrame()->getLTM(); if( _actionTime < _blendTime ) return; if( _actionTime > _blendTime + ( FRAMETIME(245) - FRAMETIME(225) ) ) { if( _phActor->isSleeping() ) { Matrix4f sampleLTM = Jumper::getCollisionFF( _clump )->getFrame()->getLTM(); _phActor->setGlobalPose( wrap( sampleLTM ) ); _phActor->wakeUp(); NxVec3 velH = wrap( _clump->getFrame()->getAt() ); velH.normalize(); velH *= 3.0f; NxVec3 velV = wrap( _clump->getFrame()->getUp() ); velV.normalize(); velV *= 1.5f; _phActor->setLinearVelocity( velH + velV ); _jumper->initOverburdenCalculator( velH + velV ); } else { _clump->getFrame()->setMatrix( _matrixConversion->convert( wrap( _phActor->getGlobalPose() ) ) ); } if( _jumper->getSpinalCord()->modifier) _endOfAction = true; } if( _clump->getAnimationController()->isEndOfAnimation( 0 ) ) { _endOfAction = true; } }
NX_INLINE void CollisionResponse(NxExtendedVec3& target_position, const NxExtendedVec3& current_position, const NxVec3& current_dir, const NxVec3& hit_normal, NxF32 bump, NxF32 friction, bool normalize=false) { // Compute reflect direction NxVec3 ReflectDir; ComputeReflexionVector(ReflectDir, current_dir, hit_normal); ReflectDir.normalize(); // Decompose it NxVec3 NormalCompo, TangentCompo; DecomposeVector(NormalCompo, TangentCompo, ReflectDir, hit_normal); // Compute new destination position const Extended Amplitude = target_position.distance(current_position); target_position = current_position; if(bump!=0.0f) { if(normalize) NormalCompo.normalize(); target_position += NormalCompo*float(bump*Amplitude); } if(friction!=0.0) { if(normalize) TangentCompo.normalize(); target_position += TangentCompo*float(friction*Amplitude); } }
void DXApp::Frame() { UINT64 CurrentTime; UINT64 DeltaCount; QueryPerformanceCounter((LARGE_INTEGER*)&CurrentTime); DeltaCount = CurrentTime - OldCount; OldCount = CurrentTime; DeltaTime = (double)DeltaCount/(double)Frequency; { NxVec3 Temp; Cam.location+=Cam.ViewDir*40*fFoward; Temp = Cam.ViewDir; Temp.y = 0; Temp.normalize(); Temp = Temp.cross(NxVec3(0.0f, 1.0f, 0.0f)); Cam.location+=Temp*40*fStrafe;; } if(!bPaused) { DoParticles(); _p_scene->simulate(_time_step); _p_scene->flushStream(); } RenderFrame(); if(!bPaused) _p_scene->fetchResults(NX_RIGID_BODY_FINISHED, true); }
static void MotionCallback(int x, int y) { int dx = gMouseX - x; int dy = gMouseY - y; gDir.normalize(); //カメラの視線ベクトルを正規化 gViewY.cross(gDir, NxVec3(0,1,0)); // if( gMouseButton[0] && gMouseButton[1] ) { //Zoom: Left + Center Buttons Drag gEye -= gDir * 0.5f * dy; } else { if( gMouseButton[0] ) { //Rotate: Left Button Drag NxQuat qx(NxPiF32 * dx * 10/ 180.0f, NxVec3(0,1,0)); qx.rotate(gDir); NxQuat qy(NxPiF32 * dy * 10/ 180.0f, gViewY); qy.rotate(gDir); } else if( gMouseButton[1] ) { //Move: Center Button Drag gEye += 0.1f * (gViewY * dx - NxVec3(0, 1, 0) * dy); } } gMouseX = x; gMouseY = y; glutPostRedisplay(); }
static void KeyboardCallback(unsigned char key, int x, int y) { switch (key) { case 27: exit(0); break; case '1': CreateCube(NxVec3(-40.0f, 60.0f, -18.0f)); break; case '2': CreateCube(NxVec3(0.0f, 60.0f, -18.0f)); break; case '3': CreateCube(NxVec3(40.0f, 60.0f, -18.0f)); break; case '4': CreateCube(NxVec3(-40.0f, 60.0f, 40.0f)); break; case '5': CreateCube(NxVec3(0.0f, 60.0f, 40.0f)); break; case '6': CreateCube(NxVec3(40.0f, 60.0f, 40.0f)); break; case 'p': gPause = !gPause; break; case 101: Eye += Dir * 2.0f; break; case 103: Eye -= Dir * 2.0f; break; case 100: Eye -= N * 2.0f; break; case 102: Eye += N * 2.0f; break; case 'w': { NxVec3 t = Eye; NxVec3 Vel = Dir; Vel.normalize(); Vel*=100.0f; CreateCube(t, &Vel); } break; } }
static void KeyboardCallback(unsigned char key, int x, int y) { static Random random; int sceneIndex = random.rand()&1; switch (key) { case 27: exit(0); break; case ' ': CreateCube(sceneIndex, NxVec3(0.0f, 20.0f, 0.0f), 1+(rand()&3)); break; case 's': CreateStack(sceneIndex, 10); break; case 'b': CreateStack(sceneIndex, 30); break; case 't': CreateTower(sceneIndex, 30); break; case 'x': gShadows = !gShadows; break; case 'p': gPause = !gPause; break; case 101: case '8': Eye += Dir * 2.0f; break; case 103: case '2': Eye -= Dir * 2.0f; break; case 100: case '4': Eye -= N * 2.0f; break; case 102: case '6': Eye += N * 2.0f; break; case 'w': { NxVec3 t = Eye; NxVec3 Vel = Dir; Vel.normalize(); Vel*=200.0f; CreateCube(sceneIndex, t, 8, &Vel); } break; } }
void MotionCallback(int x, int y) { int dx = mx - x; int dy = my - y; if (gMouseSphere) // Move the mouse sphere { NxVec3 pos; ViewUnProject(x,y, gMouseDepth, pos); gMouseSphere->setGlobalPosition(pos); gHitActor->wakeUp(); } else if (gHitCloth) // Attach the cloth vertex { NxVec3 pos; ViewUnProject(x,y, gMouseDepth, pos); gHitCloth->attachVertexToGlobalPosition(gHitClothVertex, pos); } else if (bLeftMouseButtonPressed) // Set camera { gCameraForward.normalize(); gCameraRight.cross(gCameraForward,NxVec3(0,1,0)); NxQuat qx(NxPiF32 * dx * 20 / 180.0f, NxVec3(0,1,0)); qx.rotate(gCameraForward); NxQuat qy(NxPiF32 * dy * 20 / 180.0f, gCameraRight); qy.rotate(gCameraForward); } mx = x; my = y; }
static void computeBasis(const NxVec3& dir, NxVec3& right, NxVec3& up) { // Derive two remaining vectors if(fabsf(dir.y)>0.9999f) right = NxVec3(1.0f, 0.0f, 0.0f); else right = (NxVec3(0.0f, 1.0f, 0.0f) ^ dir); right.normalize(); up = dir ^ right; }
void PhysX::CreateCubeFromEye(float cubeSize) { NxVec3 t = m_Eye; NxVec3 vel = m_Dir; vel.normalize(); vel*=200.0f; CreateCube(t, cubeSize, DENSITY, &vel); }
void CreateCubeFromEye(int size) { NxVec3 t = g_CameraPos; NxVec3 vel = g_CameraForward; vel.normalize(); vel*=200.0f; CreateCube(t, size, &vel); }
void PhysX::CreateSphereFromEye(int radius) { NxVec3 t = m_Eye; NxVec3 vel = m_Dir; vel.normalize(); vel *= 200.0f; CreateSphere(t, radius, DENSITY , &vel); }
void pWheel1::_tick(float dt) { if(!hasGroundContact()) updateContactPosition(); //################################################################ // // Calculate the wheel rotation around the roll axis // updateAngularVelocity(dt*0.001f, false); float motorTorque=0.0; if(getWheelFlag(WF_Accelerated)) { /*if (handBrake && getWheelFlag(NX_WF_AFFECTED_BY_HANDBRAKE)) { // Handbrake, blocking! }*/ if (hasGroundContact()) { // Touching, force applies NxVec3 steeringDirection; getSteeringDirection(steeringDirection); steeringDirection.normalize(); NxReal localTorque = motorTorque; NxReal wheelForce = localTorque / _radius; steeringDirection *= wheelForce; wheelCapsule->getActor().addForceAtPos(steeringDirection, contactInfo->contactPosition); if(contactInfo->otherActor->isDynamic()) contactInfo->otherActor->addForceAtPos(-steeringDirection, contactInfo->contactPosition); } } NxMat34& wheelPose = getWheelCapsule()->getGlobalPose(); NxMat33 rot, axisRot, rollRot; rot.rotY( _angle ); axisRot.rotY(0); rollRot.rotX(_turnAngle); wheelPose.M = rot * wheelPose.M * axisRot * rollRot; float a = _angle; float b = getWheelRollAngle(); setWheelPose(wheelPose); //setWheelOrientation(wheelPose.M); contactInfo->reset(); }
void Jumper::RunningJump::update(float dt) { updateAnimation( dt ); _clump->getFrame()->getLTM(); if( _actionTime < _blendTime ) { Vector3f dir = _clump->getFrame()->getAt(); dir.normalize(); _clump->getFrame()->setPos( _clump->getFrame()->getPos() + dir * dt * _vel ); return; } if( _phActor->isSleeping() ) { // setup physics Matrix4f sampleLTM = Jumper::getCollisionFF( _clump )->getFrame()->getLTM(); _phActor->setGlobalPose( wrap( sampleLTM ) ); _phActor->wakeUp(); NxVec3 velH = wrap( _clump->getFrame()->getAt() ); velH.normalize(); velH *= _vel * 0.01f; NxVec3 velV = wrap( _clump->getFrame()->getUp() ); velV.normalize(); velV *= 1.5f; _phActor->setLinearVelocity( velH + velV + wrap(_clump->getFrame()->getAt() * 600.0f * dt)) ; _jumper->initOverburdenCalculator( velH + velV ); } else { _clump->getFrame()->setMatrix( _matrixConversion->convert( wrap( _phActor->getGlobalPose() ) ) ); } if( _clump->getAnimationController()->isEndOfAnimation( 0 ) ) { _endOfAction = true; } }
void pWheel1::tick(bool handbrake, float motorTorque, float brakeTorque, float dt) { if(getWheelFlag(WF_Accelerated)) { if (handbrake && getWheelFlag(WF_AffectedByHandbrake)) { // Handbrake, blocking! } else if (hasGroundContact()) { // Touching, force applies NxVec3 steeringDirection; getSteeringDirection(steeringDirection); steeringDirection.normalize(); NxReal localTorque = motorTorque; NxReal wheelForce = localTorque / _radius; steeringDirection *= wheelForce; wheelCapsule->getActor().addForceAtPos(steeringDirection, contactInfo->contactPosition); if(contactInfo->otherActor->isDynamic()) contactInfo->otherActor->addForceAtPos(-steeringDirection, contactInfo->contactPosition); } } NxReal OneMinusBreakPedal = 1-brakeTorque; /* if(handBrake && getWheelFlag(WF_AffectedByHandbrake)) { material->setDynamicFrictionV(1); material->setStaticFrictionV(4); material->setDynamicFriction(0.4f); material->setStaticFriction(1.0f); } else { NxReal newv = OneMinusBreakPedal * _frictionToFront + brakeTorque; NxReal newv4= OneMinusBreakPedal * _frictionToFront + brakeTorque*4; material->setDynamicFrictionV(newv); material->setDynamicFriction(_frictionToSide); material->setStaticFrictionV(newv*4); material->setStaticFriction(2); }*/ if(!hasGroundContact()) updateContactPosition(); updateAngularVelocity(dt, handbrake); contactInfo->reset(); }
void MotionCallback(int x, int y) { int dx = mx - x; int dy = my - y; gCameraForward.normalize(); gCameraRight.cross(gCameraForward,NxVec3(0,1,0)); NxQuat qx(NxPiF32 * dx * 20 / 180.0f, NxVec3(0,1,0)); qx.rotate(gCameraForward); NxQuat qy(NxPiF32 * dy * 20 / 180.0f, gCameraRight); qy.rotate(gCameraForward); mx = x; my = y; }
static void MotionCallback(int x, int y) { int dx = mx - x; int dy = my - y; Dir.normalize(); N.cross(Dir,NxVec3(0,1,0)); NxQuat qx(NxPiF32 * dx * 20/ 180.0f, NxVec3(0,1,0)); qx.rotate(Dir); NxQuat qy(NxPiF32 * dy * 20/ 180.0f, N); qy.rotate(Dir); mx = x; my = y; }
void DXApp::HandleMouseMove(bool bMouseDown, int X, int Y) { if(bMouseDown) { NxVec3 Temp; Temp = Cam.location; Temp.y = 0; Temp.normalize(); Temp = Temp.cross(NxVec3(0.0f, 1.0f, 0.0f)); NxQuat(((float)(Y-OldMY))/20.0f, Temp).rotate(Cam.ViewDir); Temp = NxVec3(0.0f, 1.0f, 0.0f); NxQuat(((float)(X-OldMX))/20.0f, Temp).rotate(Cam.ViewDir); } OldMX = X; OldMY = Y; }
void MouseMotion(int x, int y ) { if(g_isButtonDown[0] || g_isButtonDown[2]) { int dx = g_last_x - x; int dy = g_last_y - y; g_CameraForward.normalize(); g_CameraRight.cross(g_CameraForward, NxVec3(0,1,0)); NxQuat qx(NxPiF32 * dx * 20/ 180.0f, NxVec3(0,1,0)); qx.rotate(g_CameraForward); NxQuat qy(NxPiF32 * dy * 20/ 180.0f, g_CameraRight); qy.rotate(g_CameraForward); g_last_x = x; g_last_y = y; } if (g_isButtonDown[1]) { float dt = 0.1f; if ((float) (x-g_last_x)>0) { g_CameraPos -= g_CameraRight*g_Speed*dt; } else if ((float) (x-g_last_x)<0) { g_CameraPos += g_CameraRight*g_Speed*dt; } if ((float) (y-g_last_y)>0) { g_CameraPos +=NxVec3(0.0f,1.0f,0.0f)*g_Speed*dt; } else if ((float) (y-g_last_y)<0) { g_CameraPos -=NxVec3(0.0f,1.0f,0.0f)*g_Speed*dt; } g_last_x = x; g_last_y = y; } glutPostRedisplay(); }
unsigned int Forest::onCollideCanopy(unsigned int id, Matrix4f* matrix, void* data) { Forest* __this = reinterpret_cast<Forest*>( data ); // determine obb of instance NxBox instanceOBB = calculateOBB( __this->_canopyBatch->getBatchScheme()->lodGeometry[0], *matrix, __this->_desc.collScale ); __this->_debugBoxes.push_back( instanceOBB ); // collide obbs if( NxBoxBoxIntersect( instanceOBB, __this->_canopyOBB ) ) { CanopySimulator* canopy = dynamic_cast<CanopySimulator*>( __this->_currentCanopy ); // calculate intersection details float volume; NxVec3 globalIntersectionCenter; calculateIntersectionDetails( instanceOBB, __this->_canopyOBB, volume, globalIntersectionCenter ); assert( volume <= 1.0f ); // add force to canopy NxVec3 linearVelocity = __this->_currentCanopyActor->getLinearVelocity(); float linearVelocityMagnitude = linearVelocity.magnitude(); linearVelocity.normalize(); NxVec3 force = linearVelocity * 0.2f * sqr( linearVelocityMagnitude ) * __this->_currentCanopyInfo->square * -volume; __this->_currentCanopyActor->addForceAtPos( force, globalIntersectionCenter, NX_FORCE ); // damage canopy canopy->rip( __this->_desc.ripFactor * force.magnitude() ); // entangle canopy if( volume > __this->_desc.entangleFactor ) { canopy->entangle( globalIntersectionCenter ); __this->playSqueakSound( wrap( globalIntersectionCenter ) ); } else { __this->playRustleSound( wrap( globalIntersectionCenter ) ); } } return id; }
//----------------------------------------------------------------------------- // ApplyExplosionPart //----------------------------------------------------------------------------- void CPhysicObj::ApplyExplosionPart (int nPartIdx, float fForce, const NxVec3& vPos) { assert( m_bActivated && (nPartIdx < GetNumParts()) ); // Solo podemos aplicar fuerzas a objetos físicos dinámicos if (!IsDynamic()) return; NxActor* pActor = GetActor( nPartIdx ); // Aplicamos una fuerza en cada shape, proporcional a su volumen. // NOTA: Para que fuese mas realista realmente habria que modular la // fuerza en funcion de la superficie de proyeccion de cada shape // hacia el punto de origen de la explosion, para aproximar lo que // seria la superficie de impacto. uint nNumShapes = pActor->getNbShapes(); assert( nNumShapes > 0 ); NxShape* const* pShapes = pActor->getShapes(); for (uint i = 0; i < nNumShapes; i++) { NxShape* pShape = pShapes[i]; // - Calcular BBox de la shape NxBox shapeBox = PhysicUtils::CalcOBBox( *pShape ); // - Calcular punto de impacto de la explosion NxVec3 vImpactPoint = PhysicUtils::CalcExplosionImpact( shapeBox, vPos ); //NxVec3 vImpactPoint = shapeBox.GetCenter(); // - Modular la fuerza de la explosion por el area expuesta de la shape float fVolume = (shapeBox.extents * 2.f).magnitudeSquared(); float fForceMod = fForce * fVolume; // - Modular a su vez en funcion de la distancia al centro de la explosion // usando una funcion exponencial de atenuacion NxVec3 vImpactDir = vImpactPoint - vPos; float fDist = vImpactDir.normalize(); // NOTA: vamos a marcar una zona de radio minimo donde se aplique la fuerza maxima //static float s_fMinDist = 0.1f; //fDist += s_fMinDist; static float s_fAttenuationFactor = 0.05f; fForceMod *= exp( -s_fAttenuationFactor * fDist ); // - Aplicar la fuerza en el punto de impacto pActor->addForceAtPos( vImpactDir * fForceMod, vImpactPoint, NX_IMPULSE ); } }
void DynamicImage::update() { if (!sleep) { NxVec3 towardsVector = tarPos - curPos; switch (mode) { case 0: //Linear if (towardsVector.magnitude() < LINEAR_VELOCITY) { curPos = tarPos; sleep = true; } else { towardsVector.normalize(); curPos = curPos + (towardsVector * LINEAR_VELOCITY); } break; case 1: //Halfling if (towardsVector.magnitude() < THRESHOLD) { curPos = tarPos; sleep = true; } else { curPos = curPos + (towardsVector * 0.033f); } break; } } }
void PxSingleActor::sweepTest( MatrixF *mat ) { NxVec3 nxCurrPos = getPosition(); // If the position is zero, // the parent hasn't been updated yet // and we don't even need to do the sweep test. // This is a fix for a problem that was happening // where on the add of the PxSingleActor, it would // set the position to a very small value because it would be getting a hit // even though the current position was 0. if ( nxCurrPos.isZero() ) return; // Set up the flags and the query structure. NxU32 flags = NX_SF_STATICS | NX_SF_DYNAMICS; NxSweepQueryHit sweepResult; dMemset( &sweepResult, 0, sizeof( sweepResult ) ); NxVec3 nxNewPos = mat->getPosition(); // Get the velocity which will be our sweep direction and distance. NxVec3 nxDir = nxNewPos - nxCurrPos; if ( nxDir.isZero() ) return; // Get the scene and do the sweep. mActor->wakeUp(); mActor->linearSweep( nxDir, flags, NULL, 1, &sweepResult, NULL ); if ( sweepResult.hitShape && sweepResult.t < nxDir.magnitude() ) { nxDir.normalize(); nxDir *= sweepResult.t; nxCurrPos += nxDir; mat->setPosition( Point3F( nxCurrPos.x, nxCurrPos.y, nxCurrPos.z ) ); } }
// ---------------------------------------------------------------------- bool ObjMesh::loadFromObjFile(char *filename) { FILE *f = fopen(filename, "r"); if (!f) return false; clear(); ObjMeshString s, subs[maxVerticesPerFace]; ObjMeshString mtllib, matName; mHasTextureCoords = false; mHasNormals = false; strcpy(mtllib, ""); int materialNr = -1; int i,j; NxVec3 v; ObjMeshTriangle t; TexCoord tc; std::vector<NxVec3> centermVertices; std::vector<TexCoord> centermTexCoords; std::vector<NxVec3> centerNormals; extractPath(filename); while (!feof(f)) { if (fgets(s, OBJ_MESH_STRING_LEN, f) == NULL) break; if (strncmp(s, "mtllib", 6) == 0) { // material library sscanf(&s[7], "%s", mtllib); importMtlFile(mtllib); } else if (strncmp(s, "usemtl", 6) == 0) { // use material sscanf(&s[7], "%s", matName); materialNr = 0; int numMaterials = (int)mMaterials.size(); while (materialNr < numMaterials && strcasecmp(mMaterials[materialNr].name, matName) != 0) materialNr++; if (materialNr >= numMaterials) materialNr = -1; } else if (strncmp(s, "v ", 2) == 0) { // vertex sscanf(s, "v %f %f %f", &v.x, &v.y, &v.z); mVertices.push_back(v); } else if (strncmp(s, "vn ", 3) == 0) { // normal sscanf(s, "vn %f %f %f", &v.x, &v.y, &v.z); mNormals.push_back(v); } else if (strncmp(s, "vt ", 3) == 0) { // texture coords sscanf(s, "vt %f %f", &tc.u, &tc.v); mTexCoords.push_back(tc); } else if (strncmp(s, "f ", 2) == 0) { // face int nr; nr = sscanf(s, "f %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s", subs[0], subs[1], subs[2], subs[3], subs[4], subs[5], subs[6], subs[7], subs[8], subs[9], subs[10], subs[11], subs[12],subs[13], subs[14]); int vertNr[maxVerticesPerFace], texNr[maxVerticesPerFace]; int normalNr[maxVerticesPerFace]; for (i = 0; i < nr; i++) { int refs[3]; parseRef(subs[i], refs); vertNr[i] = refs[0]-1; texNr[i] = refs[1]-1; normalNr[i] = refs[2]-1; } if (nr <= 4) { // simple non-singular triangle or quad if (vertNr[0] != vertNr[1] && vertNr[1] != vertNr[2] && vertNr[2] != vertNr[0]) { t.init(); t.vertexNr[0] = vertNr[0]; t.vertexNr[1] = vertNr[1]; t.vertexNr[2] = vertNr[2]; t.normalNr[0] = normalNr[0]; t.normalNr[1] = normalNr[1]; t.normalNr[2] = normalNr[2]; t.texCoordNr[0] = texNr[0]; t.texCoordNr[1] = texNr[1]; t.texCoordNr[2] = texNr[2]; t.materialNr = materialNr; mTriangles.push_back(t); } if (nr == 4) { // non-singular quad -> generate a second triangle if (vertNr[2] != vertNr[3] && vertNr[3] != vertNr[0] && vertNr[0] != vertNr[2]) { t.init(); t.vertexNr[0] = vertNr[2]; t.vertexNr[1] = vertNr[3]; t.vertexNr[2] = vertNr[0]; t.normalNr[0] = normalNr[2]; t.normalNr[1] = normalNr[3]; t.normalNr[2] = normalNr[0]; t.texCoordNr[0] = texNr[0]; t.texCoordNr[1] = texNr[1]; t.texCoordNr[2] = texNr[2]; t.materialNr = materialNr; mTriangles.push_back(t); } } } else { // polygonal face // compute center properties NxVec3 centerPos(0.0f, 0.0f, 0.0f); TexCoord centerTex; centerTex.zero(); for (i = 0; i < nr; i++) { centerPos += mVertices[vertNr[i]]; if (texNr[i] >= 0) centerTex += mTexCoords[texNr[i]]; } centerPos /= (float)nr; centerTex /= (float)nr; NxVec3 d1 = centerPos - mVertices[vertNr[0]]; NxVec3 d2 = centerPos - mVertices[vertNr[1]]; NxVec3 centerNormal = d1.cross(d2); centerNormal.normalize(); // add center vertex centermVertices.push_back(centerPos); centermTexCoords.push_back(centerTex); centerNormals.push_back(centerNormal); // add surrounding elements for (i = 0; i < nr; i++) { j = i+1; if (j >= nr) j = 0; t.init(); t.vertexNr[0] = mVertices.size() + centermVertices.size()-1; t.vertexNr[1] = vertNr[i]; t.vertexNr[2] = vertNr[j]; t.normalNr[0] = mNormals.size() + centerNormals.size()-1; t.normalNr[1] = normalNr[i]; t.normalNr[2] = normalNr[j]; t.texCoordNr[0] = mTexCoords.size() + centermTexCoords.size()-1; t.texCoordNr[1] = texNr[i]; t.texCoordNr[2] = texNr[j]; t.materialNr = materialNr; mTriangles.push_back(t); } } } } fclose(f); // new center mVertices are inserted here. // If they were inserted when generated, the vertex numbering would be corrupted for (i = 0; i < (int)centermVertices.size(); i++) mVertices.push_back(centermVertices[i]); for (i = 0; i < (int)centerNormals.size(); i++) mNormals.push_back(centerNormals[i]); for (i = 0; i < (int)centermTexCoords.size(); i++) mTexCoords.push_back(centermTexCoords[i]); if (mTexCoords.size() > 0) mHasTextureCoords = true; if (mNormals.size() > 0) mHasNormals = true; else updateNormals(); updateBounds(); return true; }
void CanopySimulator::Rope::initialize(NxActor* actor1, NxVec3 anchor1, NxActor* actor2, NxVec3 anchor2) { _nxActor1 = actor1; assert( _nxActor1 ); _nxActor2 = actor2; assert( _nxActor2 ); _anchor1 = anchor1; _anchor2 = anchor2; // calculate worldspace positions for connections points Matrix4f ltm1 = wrap( _nxActor1->getGlobalPose() ); Matrix4f ltm2 = wrap( _nxActor2->getGlobalPose() ); NxVec3 pos1 = wrap( Gameplay::iEngine->transformCoord( wrap( _anchor1 ), ltm1 ) ); NxVec3 pos2 = wrap( Gameplay::iEngine->transformCoord( wrap( _anchor2 ), ltm2 ) ); NxVec3 dir = pos2 - pos1; // check distance btw connection points (correction just for stability purpose) float idist = dir.magnitude(); dir.normalize(); // create intermediate segment bodies NxVec3 pos = pos1; float step = idist / _numJoints; for( unsigned int i=0; i<_numJoints-1; i++ ) { // segment position pos += dir * step; // create segment body NxBodyDesc nxBodyDesc; nxBodyDesc.mass = _mass / ( _numJoints - 1 ); nxBodyDesc.massSpaceInertia.set( nxBodyDesc.mass, nxBodyDesc.mass, nxBodyDesc.mass ); nxBodyDesc.linearDamping = 2.0f; nxBodyDesc.angularDamping = 0.0f; nxBodyDesc.flags = NX_BF_VISUALIZATION; nxBodyDesc.solverIterationCount = 32; NxActorDesc nxActorDesc; nxActorDesc.body = &nxBodyDesc; nxActorDesc.globalPose.M.id(); nxActorDesc.globalPose.t = pos; _nxSegmentBody[i] = _nxScene->createActor( nxActorDesc ); assert( _nxSegmentBody[i] ); // initialize velocity _nxSegmentBody[i]->addForce( _nxActor1->getLinearVelocity(), NX_VELOCITY_CHANGE ); } // create joints for( i=0; i<_numJoints; i++ ) { // first joint (actor1-segment1) if( i == 0 ) { NxDistanceJointDesc jointDesc; jointDesc.actor[0] = _nxActor1; jointDesc.actor[1] = _nxSegmentBody[0]; jointDesc.maxDistance = _length / _numJoints; jointDesc.minDistance = 0.0f; jointDesc.flags = NX_DJF_MAX_DISTANCE_ENABLED; jointDesc.localAnchor[0] = _anchor1; jointDesc.localAnchor[1].set( 0,0,0 ); jointDesc.jointFlags = NX_JF_VISUALIZATION; _nxSegmentJoint[i] = _nxScene->createJoint( jointDesc ); assert( _nxSegmentJoint[i] ); } // last joint (segmentN-actor2) else if( i == _numJoints-1 ) { NxDistanceJointDesc jointDesc; jointDesc.actor[0] = _nxSegmentBody[_numJoints-2]; jointDesc.actor[1] = _nxActor2; jointDesc.maxDistance = _length / _numJoints; jointDesc.minDistance = 0.0f; jointDesc.flags = NX_DJF_MAX_DISTANCE_ENABLED; jointDesc.localAnchor[0].set( 0,0,0 ); jointDesc.localAnchor[1] = _anchor2; jointDesc.jointFlags = NX_JF_VISUALIZATION; _nxSegmentJoint[i] = _nxScene->createJoint( jointDesc ); assert( _nxSegmentJoint[i] ); } // intermediate joint else { NxDistanceJointDesc jointDesc; jointDesc.actor[0] = _nxSegmentBody[i-1]; jointDesc.actor[1] = _nxSegmentBody[i]; jointDesc.maxDistance = _length / _numJoints; jointDesc.minDistance = 0.0f; jointDesc.flags = NX_DJF_MAX_DISTANCE_ENABLED; jointDesc.localAnchor[0].set( 0,0,0 ); jointDesc.localAnchor[1].set( 0,0,0 ); jointDesc.jointFlags = NX_JF_VISUALIZATION; _nxSegmentJoint[i] = _nxScene->createJoint( jointDesc ); assert( _nxSegmentJoint[i] ); } } }
void Jumper::Flight::updatePhysics(void) { SpinalCord* spinalCord = _jumper->getSpinalCord(); Virtues* virtues = _jumper->getVirtues(); CanopySimulator* canopy = _jumper->getDominantCanopy(); // velocity of base jumper's body NxVec3 velocity = _phActor->getLinearVelocity(); // horizontal velocity (including wind) NxVec3 velocityH = velocity; velocityH += _jumper->getScene()->getWindAtPoint( _phActor->getGlobalPosition() ); velocityH.y = 0; // shock penalty float penalty = _jumper->getVirtues()->getControlPenalty( _jumper->getShock() ); penalty = ( 1 - penalty ); // update canopy controls // modifier to 50% input if (spinalCord->modifier) { float dt = _jumper->getDeltaTime(); if (spinalCord->left > 0.5f && Gameplay::iGameplay->getActionChannel(iaLeft)->getTrigger()) Gameplay::iGameplay->getActionChannel(iaLeft)->downAmplitude(dt, 0.5f); if (spinalCord->right > 0.5f && Gameplay::iGameplay->getActionChannel(iaRight)->getTrigger()) Gameplay::iGameplay->getActionChannel(iaRight)->downAmplitude(dt, 0.5f); if (spinalCord->leftWarp > 0.5f && Gameplay::iGameplay->getActionChannel(iaLeftWarp)->getTrigger()) Gameplay::iGameplay->getActionChannel(iaLeftWarp)->downAmplitude(dt, 0.5f); if (spinalCord->rightWarp > 0.5f && Gameplay::iGameplay->getActionChannel(iaRightWarp)->getTrigger()) Gameplay::iGameplay->getActionChannel(iaRightWarp)->downAmplitude(dt, 0.5f); if (spinalCord->leftRearRiser > 0.5f && Gameplay::iGameplay->getActionChannel(iaLeftRearRiser)->getTrigger()) Gameplay::iGameplay->getActionChannel(iaLeftRearRiser)->downAmplitude(dt, 0.5f); if (spinalCord->rightRearRiser > 0.5f && Gameplay::iGameplay->getActionChannel(iaRightRearRiser)->getTrigger()) Gameplay::iGameplay->getActionChannel(iaRightRearRiser)->downAmplitude(dt, 0.5f); if (spinalCord->leftReserve > 0.5f && Gameplay::iGameplay->getActionChannel(iaReserveLeft)->getTrigger()) Gameplay::iGameplay->getActionChannel(iaReserveLeft)->downAmplitude(dt, 0.5f); if (spinalCord->rightReserve > 0.5f && Gameplay::iGameplay->getActionChannel(iaReserveRight)->getTrigger()) Gameplay::iGameplay->getActionChannel(iaReserveRight)->downAmplitude(dt, 0.5f); if (spinalCord->leftReserveWarp > 0.5f && Gameplay::iGameplay->getActionChannel(iaReserveLeftWarp)->getTrigger()) Gameplay::iGameplay->getActionChannel(iaReserveLeftWarp)->downAmplitude(dt, 0.5f); if (spinalCord->rightReserveWarp > 0.5f && Gameplay::iGameplay->getActionChannel(iaReserveRightWarp)->getTrigger()) Gameplay::iGameplay->getActionChannel(iaReserveRightWarp)->downAmplitude(dt, 0.5f); if (spinalCord->leftReserveRearRiser > 0.5f && Gameplay::iGameplay->getActionChannel(iaReserveLeftRearRiser)->getTrigger()) Gameplay::iGameplay->getActionChannel(iaReserveLeftRearRiser)->downAmplitude(dt, 0.5f); if (spinalCord->rightReserveRearRiser > 0.5f && Gameplay::iGameplay->getActionChannel(iaReserveRightRearRiser)->getTrigger()) Gameplay::iGameplay->getActionChannel(iaReserveRightRearRiser)->downAmplitude(dt, 0.5f); } // set risers canopy->setLeftWarpDeep( spinalCord->leftWarp * penalty ); canopy->setRightWarpDeep( spinalCord->rightWarp * penalty ); canopy->setLeftRearRiser( spinalCord->leftRearRiser * penalty ); canopy->setRightRearRiser( spinalCord->rightRearRiser * penalty ); canopy->setWLOToggles( spinalCord->trigger_wlo ); canopy->setHookKnife( spinalCord->trigger_hook ); // update reserve canopy controls if (_jumper->isPlayer() && _jumper->getCanopyReserveSimulator() && _jumper->getDominantCanopy() != _jumper->getCanopyReserveSimulator() && _jumper->getCanopyReserveSimulator()->isOpened()) { // set toggles CanopySimulator *reserve_canopy = _jumper->getCanopyReserveSimulator(); reserve_canopy->setLeftDeep( spinalCord->leftReserve * penalty ); reserve_canopy->setRightDeep( spinalCord->rightReserve * penalty ); // set risers reserve_canopy->setLeftWarpDeep( spinalCord->leftReserveWarp * penalty ); reserve_canopy->setRightWarpDeep( spinalCord->rightReserveWarp * penalty ); reserve_canopy->setLeftRearRiser( spinalCord->leftReserveRearRiser * penalty ); reserve_canopy->setRightRearRiser( spinalCord->rightReserveRearRiser * penalty ); reserve_canopy->setWLOToggles( spinalCord->trigger_wlo ); reserve_canopy->setHookKnife( spinalCord->trigger_hook ); } // determine animation sequence to be played _targetSequence = &passiveFlightSequence; // get total left and right input float totalInputLeft = 0.0f; float totalInputRight = 0.0f; float toggleLeft = spinalCord->left; float toggleRight = spinalCord->right; if (canopy->getLeftForcedDeep() != -1.0f) toggleLeft = 0.0f; if (canopy->getRightForcedDeep() != -1.0f) toggleRight = 0.0f; // hard toggle input if unstowing if (canopy->getLeftStowed() && spinalCord->trigger_left) { toggleLeft = 0.75f; } if (canopy->getRightStowed() && spinalCord->trigger_right) { toggleRight = 0.75f; } // set toggles canopy->setLeftDeep( spinalCord->left * penalty ); canopy->setRightDeep( spinalCord->right * penalty ); if (toggleLeft > spinalCord->leftRearRiser && toggleLeft > spinalCord->leftWarp) { totalInputLeft = toggleLeft; } else if (spinalCord->leftRearRiser > toggleLeft && spinalCord->leftRearRiser > spinalCord->leftWarp) { totalInputLeft = spinalCord->leftRearRiser; } else { totalInputLeft = spinalCord->leftWarp; } if (toggleRight > spinalCord->rightRearRiser && toggleRight > spinalCord->rightWarp) { totalInputRight = toggleRight; } else if (spinalCord->rightRearRiser > toggleRight && spinalCord->rightRearRiser > spinalCord->rightWarp) { totalInputRight = spinalCord->rightRearRiser; } else { totalInputRight = spinalCord->rightWarp; } if( totalInputLeft != 0 && totalInputRight == 0 ) { if (canopy->getLeftStowed() && spinalCord->trigger_left) { _targetSequence = &unstowLeftSequence; } else if (spinalCord->modifier) { _targetSequence = &steerLeftSequenceHalf; } else { _targetSequence = &steerLeftSequence; } } if( totalInputRight != 0 && totalInputLeft == 0 ) { if (canopy->getRightStowed() && spinalCord->trigger_right) { _targetSequence = &unstowRightSequence; } else if (spinalCord->modifier) { _targetSequence = &steerRightSequenceHalf; } else { _targetSequence = &steerRightSequence; } } if( totalInputLeft != 0 && totalInputRight != 0 ) { if (canopy->getLeftStowed() || canopy->getRightStowed()) { _targetSequence = &groupingUnstowSequence; } else if (spinalCord->modifier) { _targetSequence = &groupingSequenceHalf; } else { _targetSequence = &groupingSequence; } } // unstow toggles if (spinalCord->left > 0.1f) { canopy->setLeftStowed(false); } if (spinalCord->right > 0.1f) { canopy->setRightStowed(false); } // local coordinate system of base jumper NxMat34 pose = _phActor->getGlobalPose(); NxVec3 x = pose.M.getColumn(0); NxVec3 y = pose.M.getColumn(1); NxVec3 z = pose.M.getColumn(2); // altitude [m] //NxVec3 pos = _phActor->getGlobalPosition(); //const float altitude = pos.y; //const float arch_pose_area = 1.9f; //// air density: converted to linear from barometric equation [0:10] km altitude //// http://www.denysschen.com/catalogue/density.aspx //const float AirDensityOld = altitude <= 10000.0f ? (1.196f - 0.0000826f * altitude) : (0.27f); //// add drag force //float Cd = 0.4f; // altitude suit = 0.4f //const float mTracking = database::Suit::getRecord( _jumper->getVirtues()->equipment.suit.id )->mTracking; //Cd *= mTracking; //// Drag force vector //NxVec3 VecFd = -_phActor->getLinearVelocity(); //VecFd.normalize(); //float Fd = 0.5f * AirDensityOld * velocity.magnitudeSquared() * Cd * arch_pose_area * getCore()->getRandToolkit()->getUniform(0.94f, 1.06f); //_phActor->addForceAtLocalPos(Fd*VecFd, NxVec3(0, -3.0f, 0)); // air resistance coefficient const float ARmult = 2.5f; float AR = ARmult * virtues->getTrackingAirResistance(); if( database::Suit::getRecord( virtues->equipment.suit.id )->wingsuit ) { AR = ARmult * virtues->getFrogAirResistance(); } // terminal velocity const float Vt = sqrt( 9.8f * _phActor->getMass() / AR ); const float It = velocity.magnitude() / Vt; NxVec3 dir = velocity * -1; dir.normalize(); // air resistance force const NxVec3 Far = dir * getAirResistancePower( velocity.magnitude() / Vt ) * _phActor->getMass() * 9.8f; // finalize motion equation _phActor->addForce( Far ); }
void NxVehicle::updateVehicle(NxReal lastTimeStepSize) { //printf("updating %x\n", this); NxReal distanceSteeringAxisCarTurnAxis = _steeringSteerPoint.x - _steeringTurnPoint.x; NX_ASSERT(_steeringSteerPoint.z == _steeringTurnPoint.z); NxReal distance2 = 0; if (NxMath::abs(_steeringWheelState) > 0.01f) distance2 = distanceSteeringAxisCarTurnAxis / NxMath::tan(_steeringWheelState * _steeringMaxAngleRad); //printf("d1 = %2.3f, d2 = %2.3f, a1 = %2.3f, a2 = %2.3f\n", // distanceSteeringAxisCarTurnAxis, distance2, // _steeringWheelState, _steeringWheelState * _steeringMaxAngleRad); _lastTrailTime += lastTimeStepSize; if(_lastTrailTime > TRAIL_FREQUENCY) { _lastTrailTime = 0.0f; } NxU32 nbTouching = 0; NxU32 nbNotTouching = 0; NxU32 nbHandBrake = 0; for(NxU32 i = 0; i < _wheels.size(); i++) { NxWheel* wheel = _wheels[i]; if (_lastTrailTime == 0.0f) { if(_wheels[i]->hasGroundContact()) { if (++_nextTrailSlot >= NUM_TRAIL_POINTS) _nextTrailSlot = 0; _trailBuffer[_nextTrailSlot] = _bodyActor->getGlobalPose() * _wheels[i]->getGroundContactPos(); } } if(wheel->getWheelFlag(NX_WF_STEERABLE_INPUT)) { if(distance2 != 0) { NxReal xPos = wheel->getWheelPos().x; NxReal zPos = wheel->getWheelPos().z; NxReal dz = -zPos + distance2; NxReal dx = xPos - _steeringTurnPoint.x; wheel->setAngle(NxMath::atan(dx/dz)); } else { wheel->setAngle(0.f); } //printf("%2.3f\n", wheel->getAngle()); } else if(wheel->getWheelFlag(NX_WF_STEERABLE_AUTO)) { NxVec3 localVelocity = _bodyActor->getLocalPointVelocity(wheel->getWheelPos()); NxQuat local2Global = _bodyActor->getGlobalOrientationQuat(); local2Global.inverseRotate(localVelocity); // printf("%2.3f %2.3f %2.3f\n", wheel->getWheelPos().x,wheel->getWheelPos().y,wheel->getWheelPos().z); localVelocity.y = 0; if(localVelocity.magnitudeSquared() < 0.01f) { wheel->setAngle(0.0f); } else { localVelocity.normalize(); // printf("localVelocity: %2.3f %2.3f\n", localVelocity.x, localVelocity.z); if(localVelocity.x < 0) localVelocity = -localVelocity; NxReal angle = NxMath::clamp((NxReal)atan(localVelocity.z / localVelocity.x), 0.3f, -0.3f); wheel->setAngle(angle); } } // now the acceleration part if(!wheel->getWheelFlag(NX_WF_ACCELERATED)) continue; if(_handBrake && wheel->getWheelFlag(NX_WF_AFFECTED_BY_HANDBRAKE)) { nbHandBrake++; } else { if (!wheel->hasGroundContact()) { nbNotTouching++; } else { nbTouching++; } } } NxReal motorTorque = 0.0f; if(nbTouching && NxMath::abs(_accelerationPedal) > 0.01f) { NxReal axisTorque = _computeAxisTorque(); NxReal wheelTorque = axisTorque / (NxReal)(_wheels.size() - nbHandBrake); NxReal wheelTorqueNotTouching = nbNotTouching>0?wheelTorque*(NxMath::pow(0.5f, (NxReal)nbNotTouching)):0; NxReal wheelTorqueTouching = wheelTorque - wheelTorqueNotTouching; motorTorque = wheelTorqueTouching / (NxReal)nbTouching; } else { _updateRpms(); } //printf("wt: %f %f\n", motorTorque, _brakePedal); for(NxU32 i = 0; i < _wheels.size(); i++) { NxWheel* wheel = _wheels[i]; wheel->tick(_handBrake, motorTorque, _brakePedal, lastTimeStepSize); } //printf("---\n"); }
void Jumper::AirplaneJump::update(float dt) { updateAnimation( dt ); bool useWingsuit = database::Suit::getRecord( _jumper->getVirtues()->equipment.suit.id )->wingsuit; float phaseTime = useWingsuit ? trackInvSpeed * ( FRAMETIME(2113) - FRAMETIME(2104) ) : trackInvSpeed * ( FRAMETIME(1673) - FRAMETIME(1669) ); if( _actionTime > _blendTime + phaseTime ) { if( _phActor->isSleeping() ) { // place jumper to airplane exit Matrix4f clumpLTM = _clump->getFrame()->getLTM(); Vector3f clumpScale = calcScale( clumpLTM ); Matrix4f exitLTM = _jumper->getAirplaneExit()->getLTM(); orthoNormalize( exitLTM ); exitLTM[0][0] *= clumpScale[0], exitLTM[0][1] *= clumpScale[0], exitLTM[0][2] *= clumpScale[0]; exitLTM[1][0] *= clumpScale[1], exitLTM[1][1] *= clumpScale[1], exitLTM[1][2] *= clumpScale[1]; exitLTM[2][0] *= clumpScale[2], exitLTM[2][1] *= clumpScale[2], exitLTM[2][2] *= clumpScale[2]; _clump->getFrame()->setMatrix( exitLTM ); _clump->getFrame()->getLTM(); Matrix4f sampleLTM = Jumper::getCollisionFF( _clump )->getFrame()->getLTM(); _phActor->setGlobalPose( wrap( sampleLTM ) ); _phActor->wakeUp(); NxVec3 velH = wrap( _clump->getFrame()->getAt() ); velH.normalize(); velH *= 3.0f; NxVec3 velV = wrap( _clump->getFrame()->getUp() ); velV.normalize(); velV *= 0.25f; NxVec3 velA = wrap( _jumper->getAirplane()->getVel() ); _phActor->setLinearVelocity( velH + velV + velA ); _jumper->initOverburdenCalculator( velH + velV + velA ); // modified exits (only fixed wing, not heli) bool helicopter = strcmp(_jumper->getAirplane()->getDesc()->templateClump->getName(), "Helicopter01") == 0; if (!helicopter) { if (_jumper->getSpinalCord()->left) { _phActor->addLocalTorque(NxVec3(0,5700.0f,0)); //_phActor->setAngularDamping(2.0f); } else if (_jumper->getSpinalCord()->right) { _phActor->addLocalTorque(NxVec3(0,-5700.0f,0)); //_phActor->setAngularDamping(2.0f); } if (_jumper->getSpinalCord()->up) { // headdown exit _phActor->addLocalTorque(NxVec3(5700.0f,0,0)); } else if (_jumper->getSpinalCord()->down) { // sitfly exit _phActor->addLocalTorque(NxVec3(-8700.0f,0,0)); _phActor->addLocalForce(NxVec3(0,0,10000.0f)); } _phActor->setAngularDamping(2.0f); } } else { if (_jumper->getSpinalCord()->left) { _phActor->addLocalTorque(NxVec3(0,2000.0f*dt,0)); } else if (_jumper->getSpinalCord()->right) { _phActor->addLocalTorque(NxVec3(0,-2000.0f*dt,0)); } _clump->getFrame()->setMatrix( _matrixConversion->convert( wrap( _phActor->getGlobalPose() ) ) ); } } else { // place jumper to airplane exit Matrix4f clumpLTM = _clump->getFrame()->getLTM(); Vector3f clumpScale = calcScale( clumpLTM ); Matrix4f exitLTM = _jumper->getAirplaneExit()->getLTM(); Vector3f pos = _jumper->getAirplaneExit()->getPos(); getCore()->logMessage("exit pos: %2.2f %2.2f %2.2f", pos[0], pos[1], pos[2]); orthoNormalize( exitLTM ); exitLTM[0][0] *= clumpScale[0], exitLTM[0][1] *= clumpScale[0], exitLTM[0][2] *= clumpScale[0]; exitLTM[1][0] *= clumpScale[1], exitLTM[1][1] *= clumpScale[1], exitLTM[1][2] *= clumpScale[1]; exitLTM[2][0] *= clumpScale[2], exitLTM[2][1] *= clumpScale[2], exitLTM[2][2] *= clumpScale[2]; _clump->getFrame()->setMatrix( exitLTM ); } if( _clump->getAnimationController()->isEndOfAnimation( 0 )) // || (_jumper->getSpinalCord()->modifier && _jumper->isPlayer() && _actionTime > _blendTime + phaseTime )) { _endOfAction = true; } }
Jumper::CanopyOpening::CanopyOpening(Jumper* jumper, NxActor* phFreeFall, NxActor* phFlight, MatrixConversion* mcFlight, PilotchuteSimulator* pc, CanopySimulator* c, NxVec3 fla, NxVec3 fra, NxVec3 rla, NxVec3 rra) : JumperAction( jumper ) { // set action properties _actionTime = 0.0f; _blendTime = 0.2f; _endOfAction = false; _phActor = phFlight; _matrixConversion = mcFlight; _pilotchute = pc; _canopy = c; _frontLeftAnchor = fla; _frontRightAnchor = fra; _rearLeftAnchor = rla; _rearRightAnchor = rra; _initialLD = phFlight->getLinearDamping(); // activate jumper body simulator Matrix4f sampleLTM = Jumper::getCollisionFC( _clump )->getFrame()->getLTM(); phFlight->setGlobalPose( wrap( sampleLTM ) ); phFlight->wakeUp(); phFlight->setLinearVelocity( phFreeFall->getLinearVelocity() ); phFlight->setAngularVelocity( phFreeFall->getAngularVelocity() ); // connect & open canopy _canopy->connect( _phActor, _frontLeftAnchor, _frontRightAnchor, _rearLeftAnchor, _rearRightAnchor, Jumper::getFrontLeftRiser( _clump ), Jumper::getFrontRightRiser( _clump ), Jumper::getRearLeftRiser( _clump ), Jumper::getRearRightRiser( _clump ) ); // age if (_jumper->getCanopyReserveSimulator() && _jumper->getCanopyReserveSimulator() == _canopy) { ++jumper->getVirtues()->equipment.reserve.age; } else { ++jumper->getVirtues()->equipment.canopy.age; } // retrieve pilotchute velocity float pcVel = pc->getPhActor()->getLinearVelocity().magnitude(); float anglVel = phFreeFall->getAngularVelocity().magnitude(); // retrieve pilotchute reference velocity database::Canopy* canopyInfo = _canopy->getGearRecord(); database::Pilotchute* pcInfo; if (_jumper->getCanopyReserveSimulator() == _canopy) { pcInfo = canopyInfo->pilots; } else { assert( canopyInfo->numPilots > _jumper->getVirtues()->equipment.pilotchute ); pcInfo = canopyInfo->pilots + _jumper->getVirtues()->equipment.pilotchute; } // probability of lineover float lineoverProb = _jumper->getVirtues()->getLineoverProbability( pcVel / pcInfo->Vrec ); // no slider has not smaller probability if (_jumper->getVirtues()->equipment.sliderOption != soRemoved) { lineoverProb *= 0.3f; } // reserves have 70% less lineover probability if (_jumper->getCanopyReserveSimulator() == _canopy) { lineoverProb *= 0.3f; } bool leftLineover = ( getCore()->getRandToolkit()->getUniform( 0, 1 ) < lineoverProb ); bool rightLineover = !leftLineover && ( getCore()->getRandToolkit()->getUniform( 0, 1 ) < lineoverProb ); float leftLOW = leftLineover ? getCore()->getRandToolkit()->getUniform( 0.5, 1.0f ) : 0; float rightLOW = rightLineover ? getCore()->getRandToolkit()->getUniform( 0.5, 1.0f ) : 0; // probability of linetwists // add probability if spinning //if( _jumper->isPlayer() ) getCore()->logMessage( "angular velocity component on deployment: %2.10f", anglVel * 0.13f ); float linetwistsProb = _jumper->getVirtues()->getLinetwistsProbability( pcVel ) + anglVel * 0.13f; float linetwistsDice = getCore()->getRandToolkit()->getUniform( 0.0f, 1.0f ); // probability of linetwists because of incorrect body position NxVec3 motionDir = _jumper->getFreefallActor()->getLinearVelocity(); motionDir.normalize(); NxVec3 canopyDown = _jumper->getFreefallActor()->getGlobalPose().M.getColumn(2); canopyDown.normalize(); float relativity = 1.0f + fabs(canopyDown.dot( motionDir )); linetwistsProb *= relativity; // reserves have 50% less linetwist probability if (_jumper->getCanopyReserveSimulator() == _canopy) { linetwistsProb *= 0.5f; } // base canopies gave 40% less linetwist probability else if (!canopyInfo->skydiving) { linetwistsProb *= 0.4f; } bool linetwists = ( linetwistsDice <= linetwistsProb ); //if( _jumper->isPlayer() ) { //getCore()->logMessage( "linetwists prob: %3.5f", linetwistsProb ); //getCore()->logMessage( "linetwists dice: %3.5f", linetwistsDice ); //} else { //getCore()->logMessage( "linetwists prob BOT: %3.5f", linetwistsProb ); //getCore()->logMessage( "linetwists dice BOT: %3.5f", linetwistsDice ); //} // generate linetwists (positive is righttwist, negative is lefttwist) // the smaller the canopy, the heavier the linetwist float sq = canopyInfo->square * 2.0f; // 300 canopy: 120; 840 // 200 canopy: 320; 1040 // 100 canopy: 520; 1240 float linetwistsAngle = getCore()->getRandToolkit()->getUniform( 720 - sq, 1540 - sq ); if (linetwistsAngle > 1080.0f) { linetwistsAngle = 1440.0f; } else if (linetwistsAngle < 320.0f) { linetwistsAngle = 180.0f; } float sign = getCore()->getRandToolkit()->getUniform( -1, 1 ); sign = sign < 0.0f ? -1.0f : ( sign > 0.0f ? 1.0f : 0.0f ); linetwistsAngle *= sign; if( !linetwists ) linetwistsAngle = 0.0f; // test, force linetwist //if (!_jumper->isPlayer() && _jumper->getCanopyReserveSimulator() != _canopy) { // linetwists = true; // linetwistsAngle = 1440.0f; //} // offheading : canopy turns by specified angle float minTurn = 30.0f; // rigging skill = 0.0 float maxTurn = 10.0f; // rigging skill = 1.0 float rigging = _jumper->getVirtues()->getRiggingSkill(); assert( rigging >= 0 && rigging <= 1 ); float turn = minTurn * ( 1 - rigging ) + maxTurn * rigging; float angle = getCore()->getRandToolkit()->getUniform( -turn, turn ); //if( _jumper->isPlayer() ) getCore()->logMessage( "additional turn (offheading): %2.1f", angle ); //if( !_jumper->isPlayer() ) angle = 0; Vector3f sampleX( sampleLTM[0][0], sampleLTM[0][1], sampleLTM[0][2] ); Vector3f sampleY( sampleLTM[1][0], sampleLTM[1][1], sampleLTM[1][2] ); Vector3f sampleZ( sampleLTM[2][0], sampleLTM[2][1], sampleLTM[2][2] ); Vector3f sampleP( sampleLTM[3][0], sampleLTM[3][1], sampleLTM[3][2] ); // orient canopy towards jumper velocity sampleZ = wrap( phFlight->getLinearVelocity() ); sampleZ *= -1; sampleZ.normalize(); sampleY = _jumper->getClump()->getFrame()->getAt() * -1; sampleX.cross( sampleY, sampleZ ); sampleX.normalize(); sampleY.cross( sampleZ, sampleX ); sampleY.normalize(); sampleLTM.set( sampleX[0], sampleX[1], sampleX[2], 0.0f, sampleY[0], sampleY[1], sampleY[2], 0.0f, sampleZ[0], sampleZ[1], sampleZ[2], 0.0f, 0.0f, 0.0f, 0.0f, 1.0f ); // turn canopy by random angle sampleLTM = Gameplay::iEngine->rotateMatrix( sampleLTM, sampleZ, angle ); // move clump behind jumper sampleP -= sampleZ * 80.0f; sampleLTM[3][0] = sampleP[0]; sampleLTM[3][1] = sampleP[1]; sampleLTM[3][2] = sampleP[2]; _canopy->open( wrap( sampleLTM ), _phActor->getLinearVelocity(), leftLOW, rightLOW, linetwistsAngle ); // reconnect pilotchute to canopy _canopy->getClump()->getFrame()->getLTM(); _pilotchute->connect( _canopy->getNxActor(), CanopySimulator::getPilotCordJoint( _canopy->getClump() ), _canopy->getPilotAnchor() ); //_pilotchute->setFreebag(_canopy == _jumper->getCanopyReserveSimulator()); set in jumper constructor and jumper::fireReserveCanopy() // put to sleep freefall simulator phFreeFall->putToSleep(); phFreeFall->raiseActorFlag( NX_AF_DISABLE_COLLISION ); // show risers Jumper::getRisers( _clump )->setFlags( engine::afRender ); // animation controller engine::IAnimationController* animCtrl = _clump->getAnimationController(); // capture blend source animCtrl->captureBlendSrc(); // reset animation mixer for( unsigned int i=0; i<engine::maxAnimationTracks; i++ ) { if( animCtrl->getTrackAnimation( i ) ) animCtrl->setTrackActivity( i, false ); } // setup animation animCtrl->setTrackAnimation( 0, &openingSequence ); animCtrl->setTrackActivity( 0, true ); animCtrl->setTrackSpeed( 0, 0.75f ); animCtrl->setTrackWeight( 0, 1.0f ); animCtrl->resetTrackTime( 0 ); animCtrl->advance( 0.0f ); // capture blend destination animCtrl->captureBlendDst(); animCtrl->blend( 0.0f ); }
// This is the generic sweep test for all swept volumes, but not character-controller specific bool SweepTest::DoSweepTest(void* user_data, void* user_data2, NxU32 nb_boxes, const NxExtendedBounds3* boxes, const void** box_user_data, NxU32 nb_capsules, const NxExtendedCapsule* capsules, const void** capsule_user_data, SweptVolume& swept_volume, const NxVec3& direction, NxU32 max_iter, NxU32* nb_collisions, NxU32 group_flags, float min_dist, const NxGroupsMask* groupsMask, bool down_pass) { // Early exit when motion is zero. Since the motion is decomposed into several vectors // and this function is called for each of them, it actually happens quite often. if(direction.isZero()) return false; bool HasMoved = false; mValidTri = false; NxExtendedVec3 CurrentPosition = swept_volume.mCenter; NxExtendedVec3 TargetPosition = swept_volume.mCenter; TargetPosition += direction; NxU32 NbCollisions = 0; while(max_iter--) { gNbIters++; // Compute current direction NxVec3 CurrentDirection = TargetPosition - CurrentPosition; // Make sure the new TBV is still valid { // Compute temporal bounding box. We could use a capsule or an OBB instead: // - the volume would be smaller // - but the query would be slower // Overall it's unclear whether it's worth it or not. // TODO: optimize this part ? NxExtendedBounds3 TemporalBox; swept_volume.ComputeTemporalBox(*this, TemporalBox, CurrentPosition, CurrentDirection); // Gather touched geoms UpdateTouchedGeoms(user_data, swept_volume, nb_boxes, boxes, box_user_data, nb_capsules, capsules, capsule_user_data, group_flags, TemporalBox, groupsMask); } const float Length = CurrentDirection.magnitude(); if(Length<min_dist) break; CurrentDirection /= Length; // From Quake2: "if velocity is against the original velocity, stop dead to avoid tiny occilations in sloping corners" if((CurrentDirection|direction) <= 0.0f) break; // From this point, we're going to update the position at least once HasMoved = true; // Find closest collision SweptContact C; C.mDistance = Length + mSkinWidth; if(!CollideGeoms(this, swept_volume, mGeomStream, CurrentPosition, CurrentDirection, C)) { // no collision found => move to desired position CurrentPosition = TargetPosition; break; } ASSERT(C.mGeom); // If we reach this point, we must have touched a geom if(C.mGeom->mType==TOUCHED_USER_BOX || C.mGeom->mType==TOUCHED_USER_CAPSULE) { // We touched a user object, typically another CCT if(mValidateCallback) UserHitCallback(user_data2, C, CurrentDirection, Length); // Trying to solve the following problem: // - by default, the CCT "friction" is infinite, i.e. a CCT will not slide on a slope (this is by design) // - this produces bad results when a capsule CCT stands on top of another capsule CCT, without sliding. Visually it looks // like the character is standing on the other character's head, it looks bad. So, here, we would like to let the CCT // slide away, i.e. we don't want friction. // So here we simply increase the number of iterations (== let the CCT slide) when the first down collision is with another CCT. if(down_pass && !NbCollisions) max_iter += 9; } else { // We touched a normal object #ifdef USE_CONTACT_NORMAL_FOR_SLOPE_TEST mValidTri = true; mCN = C.mWorldNormal; #else if(C.mIndex!=INVALID_ID) { mValidTri = true; mTouched = mWorldTriangles[C.mIndex]; } #endif { if(mValidateCallback) ShapeHitCallback(user_data2, C, CurrentDirection, Length); } } NbCollisions++; mContactPointHeight = (float)C.mWorldPos[mUpDirection]; // UBI const float DynSkin = mSkinWidth; if(C.mDistance>DynSkin/*+0.01f*/) CurrentPosition += CurrentDirection*(C.mDistance-DynSkin); NxVec3 WorldNormal = C.mWorldNormal; if(mWalkExperiment) { // Make sure the auto-step doesn't bypass this ! WorldNormal[mUpDirection]=0.0f; WorldNormal.normalize(); } const float Bump = 0.0f; // ### doesn't work when !=0 because of Quake2 hack! const float Friction = 1.0f; CollisionResponse(TargetPosition, CurrentPosition, CurrentDirection, WorldNormal, Bump, Friction, mNormalizeResponse); } if(nb_collisions) *nb_collisions = NbCollisions; // Final box position that should be reflected in the graphics engine swept_volume.mCenter = CurrentPosition; // If we didn't move, don't update the box position at all (keeping possible lazy-evaluated structures valid) return HasMoved; }
void Airplane::onUpdatePhysics() { if (_phActor != NULL) { if (_phActor->isSleeping()) { _phActor->wakeUp(); return; } /// PHYSICS // altitude [m] NxVec3 pos = _phActor->getGlobalPosition(); NxVec3 velocity = _phActor->getLinearVelocity(); float altitude = pos.y; // speed (m/s) squared const float Vsq = velocity.magnitudeSquared(); // air density: converted to linear from barometric equation [0:10] km altitude // http://www.denysschen.com/catalogue/density.aspx const float AirDensityOld = altitude <= 10000.0f ? (1.196f - 0.0000826f * altitude) : (0.27f); // AOA NxMat34 globalPose = _phActor->getGlobalPose(); NxVec3 x = globalPose.M.getColumn(0); NxVec3 y = globalPose.M.getColumn(1); NxVec3 z = globalPose.M.getColumn(2); NxVec3 velocityN = velocity; velocityN.normalize(); const float AOA = -::calcAngle( z, velocityN, x ); // ADD DRAG const float Cd = 0.027f; const float Fd = 0.5f * AirDensityOld * Vsq * Cd * 10.0f; // crosssectional objects const unsigned int xsections_c = 1; NxVec3 xsections[xsections_c]; // fuselage //_phActor->addLocalForce(wrap(_propellerFrame->getAt()) * 100.0f); // synchronize physics & render //_clump->getFrame()->setPos(wrap(_phActor->getGlobalPosition())); //_clump->getFrame()->setMatrix(wrap(_phActor->getGlobalPose())); } if( !_roughMode ) { float dt = ::simulationStepTime; _clump->getAnimationController()->advance( dt * _desc.animationSpeed ); _clump->getFrame()->getLTM(); // landing mode if( _landingMode && _clump->getFrame()->getPos()[1] > _desc.lastAltitude ) { _clump->getFrame()->translate( Vector3f( 0.0f, -_desc.loweringSpeed * dt, 0.0f ) ); } // calculate velocity Vector3f currPoint = _propellerFrame->getPos(); _velocity = ( currPoint - _prevPoint ) / ( dt ); _prevPoint = currPoint; } // fly by waypoints if( _desc.waypoints.size() && _waypointId < _desc.waypoints.size() - 1 ) { // current waypoints AirplaneDesc::WayPoint waypoint1 = _desc.waypoints[_waypointId]; AirplaneDesc::WayPoint waypoint2 = _desc.waypoints[_waypointId+1]; // trajectory vector Vector3f trajectory = waypoint2.pos - waypoint1.pos; // current velocity float vel = waypoint1.vel * ( 1 - _waypointFactor ) + waypoint2.vel * _waypointFactor; // motion distance float distance = vel * ::simulationStepTime; // determine factor distance float fDistance = distance / trajectory.length(); // move in factor space _waypointFactor += fDistance; // out of current waypoints? if( _waypointFactor > 1 ) { // determine rest of distance fDistance = _waypointFactor - 1; distance = fDistance * trajectory.length(); _waypointFactor = 0; _waypointId++; if( _waypointId < _desc.waypoints.size() - 1 ) { // new waypoints waypoint1 = _desc.waypoints[_waypointId]; waypoint2 = _desc.waypoints[_waypointId+1]; // new trajectory vector trajectory = waypoint2.pos - waypoint1.pos; // new factor distance fDistance = distance / trajectory.length(); // move in factor space _waypointFactor += fDistance; } else { _waypointFactor = 0; } } } }