void DrawForce(NxActor* actor, NxVec3& forceVec, const NxVec3& color) { // Draw only if the force is large enough NxReal force = forceVec.magnitude(); if (force < 0.1) return; forceVec = 3*forceVec/force; NxVec3 pos = actor->getCMassGlobalPosition(); DrawArrow(pos, pos + forceVec, color); }
// ---------------------------------------------------------------------- void ObjMesh::updateNormals() { mNormals.resize(mVertices.size()); int i; for (i = 0; i < (int)mNormals.size(); i++) mNormals[i].zero(); NxVec3 n; for (i = 0; i < (int)mTriangles.size(); i++) { ObjMeshTriangle &mt = mTriangles[i]; mt.normalNr[0] = mt.vertexNr[0]; mt.normalNr[1] = mt.vertexNr[1]; mt.normalNr[2] = mt.vertexNr[2]; n.cross(mVertices[mt.vertexNr[1]] - mVertices[mt.vertexNr[0]], mVertices[mt.vertexNr[2]] - mVertices[mt.vertexNr[0]]); mNormals[mt.normalNr[0]] += n; mNormals[mt.normalNr[1]] += n; mNormals[mt.normalNr[2]] += n; } for (i = 0; i < (int)mNormals.size(); i++) mNormals[i].normalize(); }
void SetupGLMatrix(const NxVec3& pos, const NxMat33& orient) { float glmat[16]; //4x4 column major matrix for OpenGL. orient.getColumnMajorStride4(&(glmat[0])); pos.get(&(glmat[12])); //clear the elements we don't need: glmat[3] = glmat[7] = glmat[11] = 0.0f; glmat[15] = 1.0f; glMultMatrixf(&(glmat[0])); }
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 Jumper::CanopyOpening::updatePhysics(void) { // velocity of base jumper's body NxVec3 velocity = _phActor->getLinearVelocity(); // 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); // air resistance force float AR = _jumper->getVirtues()->getTrackingAirResistance(); // terminal velocity float Vt = sqrt( 9.8f * _phActor->getMass() / AR ); float It = velocity.magnitude() / Vt; // air resistance force NxVec3 Far = NxVec3(0,1,0) * getAirResistancePower( velocity.magnitude() / Vt ) * _phActor->getMass() * 9.8f; // finalize motion equation _phActor->addForce( Far ); // linear damping is function of jumper velocity // this is prevents calculation errors due to high speed rates float minVel = 50.0f; float minDamping = _initialLD; float maxVel = 70.0f; float maxDamping = 2.5f; float factor = ( velocity.magnitude() - minVel ) / ( maxVel - minVel ); factor = factor < 0 ? 0 : ( factor > 1 ? 1 : factor ); float damping = minDamping * ( factor - 1 ) + maxDamping * ( factor ); _phActor->setLinearDamping( damping ); // shallow brake setting _canopy->setLeftDeep( 0.0f ); _canopy->setRightDeep( 0.0f ); }
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 PxSingleActor::applyCorrection( const MatrixF& mat, const NxVec3& linVel, const NxVec3& angVel ) { // Sometimes the actor hasn't been // created yet during the call from unpackUpdate. if ( !mActor || !mWorld ) return; mWorld->releaseWriteLock(); NxVec3 newPos = mat.getPosition(); NxVec3 currPos = getPosition(); NxVec3 offset = newPos - currPos; // If the difference isn't large enough, // just set the new transform, no correction. if ( offset.magnitude() > 0.3f ) { // If we're going to set the linear or angular velocity, // we do it before we add a corrective force, since it would be overwritten otherwise. NxVec3 currLinVel, currAngVel; currLinVel = mActor->getLinearVelocity(); currAngVel = mActor->getAngularVelocity(); // Scale the corrective force by half, // otherwise it will over correct and oscillate. NxVec3 massCent = mActor->getCMassGlobalPosition(); mActor->addForceAtPos( offset, massCent, NX_VELOCITY_CHANGE ); // If the linear velocity is divergent enough, change to server linear velocity. if ( (linVel - currLinVel).magnitude() > 0.3f ) mActor->setLinearVelocity( linVel ); // Same for angular. if ( (angVel - currAngVel).magnitude() > 0.3f ) mActor->setAngularVelocity( angVel ); } Parent::setTransform( mat ); }
// ray-sphere intersection test from Graphics Gems p.388 // **NOTE** There is a bug in this Graphics Gem. If the origin // of the ray is *inside* the sphere being tested, it reports the // wrong intersection location. This code has a fix for the bug. bool SBM_rayIntersectsSphere(const float *point,const float *direction,const float *_center,float radius,float &t) { bool ret = false; NxVec3 rayOrigin(point); NxVec3 dir(direction); NxVec3 center(_center); // notation: // point E = rayOrigin // point O = sphere center NxVec3 EO = center - rayOrigin; NxVec3 V = dir; float dist2 = EO.x*EO.x + EO.y*EO.y + EO.z * EO.z; float r2 = radius*radius; // Bug Fix For Gem, if origin is *inside* the sphere, invert the // direction vector so that we get a valid intersection location. if ( dist2 < r2 ) V*=-1; float v = EO.dot(V); float disc = r2 - (EO.magnitudeSquared() - v*v); if (disc > 0.0f) { t = sqrtf(disc); ret = true; } return ret; }
void DrawForceAtShape(NxActor* actor, NxShape* shape, NxVec3& forceVec, const NxVec3& color) { // Draw only if the force is large enough NxReal force = forceVec.magnitude(); if (force < 0.1f) return; forceVec = 3*forceVec/force; NxVec3 pos; if (bShapeSelectMode && bForceMode) pos = shape->getGlobalPosition(); else pos = actor->getCMassGlobalPosition(); DrawArrow(pos, pos + forceVec, color); }
void CreateExperiment() { switch (gExperimentType) { case LANDER: { gScene->releaseActor(*groundPlane); groundPlane=NULL; // will be recreated with the container cell CreateExperimentMaterials(); CreateContainerCell(gCellSize); gPhysicsSDK->setParameter(NX_VISUALIZE_ACTOR_AXES,0); gPhysicsSDK->setParameter(NX_VISUALIZE_COLLISION_FNORMALS,0); gPhysicsSDK->setParameter(NX_VISUALIZE_COLLISION_SHAPES,1); gPhysicsSDK->setParameter(NX_VISUALIZE_WORLD_AXES,0); //gLander=CreateLander(NxVec3(0.0f,0.0f,0.0f)); gLander=CreateLander(NxVec3(0.0f,gCellSize/2.0f,0.0f)); IdentifyGravitators(); if (gLander) { ReOrientActor(gLander); SpinActor(gLander,gLandingRoughness*sqrt(gCellSize*gDefaultGravity.magnitude()/(gLander->getMassSpaceInertiaTensor().magnitude()))); LaunchActor(gLander,gLandingRoughness*sqrt(gCellSize*gDefaultGravity.magnitude())); gSelectedActor=gLander; gPhysicsSDK->setParameter(NX_VISUALIZE_ACTOR_AXES,gLanderSize.magnitude()); isRunning=true; } else { printf("Error: Unable to create lander\a\n"); isRunning=false; } break; } case LAY_SUBSTRATE: { gScene->releaseActor(*groundPlane); groundPlane=NULL; // will be recreated with the container cell CreateExperimentMaterials(); CreateContainerCell(gCellSize); gPhysicsSDK->setParameter(NX_VISUALIZE_ACTOR_AXES,0); gPhysicsSDK->setParameter(NX_VISUALIZE_COLLISION_FNORMALS,0); gPhysicsSDK->setParameter(NX_VISUALIZE_COLLISION_SHAPES,1); gPhysicsSDK->setParameter(NX_VISUALIZE_WORLD_AXES,0); //ThrowStone(); isRunning=true; break; } default: {printf("Error: unimplemented experiment type\a\n"); isRunning=false; break;} } }
// ----------------------------------------------------------------------------------- bool ObjMesh::rayTriangleIntersection(const NxVec3 &orig, const NxVec3 &dir, const ObjMeshTriangle &triangle, NxReal &t, NxReal &u, NxReal &v) const { const NxVec3 &a = mVertices[triangle.vertexNr[0]]; const NxVec3 &b = mVertices[triangle.vertexNr[0]]; const NxVec3 &c = mVertices[triangle.vertexNr[0]]; NxVec3 edge1, edge2, tvec, pvec, qvec; NxReal det,inv_det; edge1 = b - a; edge2 = c - a; pvec.cross(dir, edge2); /* if determinant is near zero, ray lies in plane of triangle */ det = edge1.dot(pvec); if (det == 0.0f) return false; inv_det = 1.0f / det; /* calculate distance from vert0 to ray origin */ tvec = orig - a; /* calculate U parameter and test bounds */ u = tvec.dot(pvec) * inv_det; if (u < 0.0f || u > 1.0f) return false; /* prepare to test V parameter */ qvec.cross(tvec, edge1); /* calculate V parameter and test bounds */ v = dir.dot(qvec) * inv_det; if (v < 0.0f || u + v > 1.0f) return false; /* calculate t, ray intersects triangle */ t = edge2.dot(qvec) * inv_det; return true; }
void ViewUnProject(int xi, int yi, float depth, NxVec3 &v) { //We cannot do picking easily on the xbox/PS3 anyway #if defined(_XBOX)||defined(__CELLOS_LV2__) v=NxVec3(0,0,0); #else GLint viewPort[4]; GLdouble modelMatrix[16]; GLdouble projMatrix[16]; glGetIntegerv(GL_VIEWPORT, viewPort); glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix); glGetDoublev(GL_PROJECTION_MATRIX, projMatrix); yi = viewPort[3] - yi - 1; GLdouble wx, wy, wz; gluUnProject((GLdouble) xi, (GLdouble) yi, (GLdouble) depth, modelMatrix, projMatrix, viewPort, &wx, &wy, &wz); v.set((NxReal)wx, (NxReal)wy, (NxReal)wz); #endif }
void WindPointer::onEvent(Actor* initiator, unsigned int eventId, void* eventData) { if( eventId == EVENT_CAMERA_IS_ACTUAL ) { // current wind NxVec3 wind = _scene->getWindAtPoint( NxVec3( 0,0,0 ) ); // make signature worldspace position Matrix4f cameraPose = _scene->getCamera()->getPose(); Vector3f cameraPos( cameraPose[3][0], cameraPose[3][1], cameraPose[3][2] ); Vector3f pos( wind.x, wind.y, wind.z ); pos.normalize(); pos *= 10000.0f; pos += cameraPos; // update signature window Vector3f screenPos = Gameplay::iEngine->getDefaultCamera()->projectPosition( pos ); if( screenPos[2] > 1 ) { _signature->getPanel()->setVisible( false ); return; } else { _signature->getPanel()->setVisible( true ); gui::Rect oldRect = _signature->getPanel()->getRect(); gui::Rect newRect( int( screenPos[0] ), int( screenPos[1] ), int( screenPos[0] ) + oldRect.getWidth(), int( screenPos[1] ) + oldRect.getHeight() ); _signature->getPanel()->setRect( newRect ); _windSpeed->getStaticText()->setText( wstrformat( Gameplay::iLanguage->getUnicodeString(295), wind.magnitude() ).c_str() ); } } }
void GetPos(NxVec3 &maxPos, NxVec3 &minPos, NxCloth *cloth) { NxVec3 vetex[2000]; ofstream outFile("vetex"); NxReal maxX = -999.0f, minX = 999.0f; NxReal maxY = -999.0f, minY = 999.0f; NxReal maxZ = -999.0f, minZ = 999.0f; memset(vetex, 0, 2000 * sizeof(NxVec3)); cloth->getPositions(vetex); for (int i = 0; i < 2000; i++) { if (vetex[i].x == 0 && vetex[i].y == 0 || vetex[i].z == 0) { //printf("i = %d\n", i); break; } else { if (vetex[i].x > maxX) maxX = vetex[i].x; if (vetex[i].y > maxY) maxY = vetex[i].y; if (vetex[i].z > maxZ) maxZ = vetex[i].z; if (vetex[i].x < minX) minX = vetex[i].x; if (vetex[i].y < minY) minY = vetex[i].y; if (vetex[i].z < minZ) minZ = vetex[i].z; //printf("vetex %f %f %f\n", vetex[i].x, vetex[i].y, vetex[i].z); //outFile << vetex[i].x << "\t" << vetex[i].y << "\t" << vetex[i].z << endl; } } minPos.setx(minX); minPos.sety(minY); minPos.setz(minZ); maxPos.setx(maxX); maxPos.sety(maxY); maxPos.setz(maxZ); outFile << maxX << endl; outFile.close(); }
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 ) ); } }
NxFluid* CreateFluid(const NxVec3& pos, NxU32 sideNum, NxReal distance, NxScene* scene) { float rad = sideNum*distance*0.5; for (unsigned i=0; i<sideNum; i++) for (unsigned j=0; j<sideNum; j++) for (unsigned k=0; k<sideNum; k++) { NxVec3 p = NxVec3(i*distance,j*distance,k*distance); if (p.distance(NxVec3(rad,rad,rad)) < rad) { p += pos; if(gParticleBufferNum< MAX_PARTICLES) gParticleBuffer[gParticleBufferNum++] = p; } } NxParticleData particles; //particles.maxParticles = gParticleBufferCap; particles.numParticlesPtr = &gParticleBufferNum; particles.bufferPos = &gParticleBuffer[0].x; particles.bufferPosByteStride = sizeof(NxVec3); //Create a fluid descriptor NxFluidDesc fluidDesc; fluidDesc.maxParticles = MAX_PARTICLES; fluidDesc.flags |= NX_FF_COLLISION_TWOWAY; fluidDesc.simulationMethod = NX_F_SPH; fluidDesc.restParticlesPerMeter = 5.0f; fluidDesc.motionLimitMultiplier = 10.0f; fluidDesc.restDensity = 1000.0f; fluidDesc.kernelRadiusMultiplier = 1.6f; fluidDesc.stiffness = 10.0f; fluidDesc.viscosity = 50.0f; fluidDesc.damping = 0.5f; fluidDesc.packetSizeMultiplier = 16; fluidDesc.name = "fluid"; fluidDesc.kernelRadiusMultiplier = KERNEL_RADIUS_MULTIPLIER; fluidDesc.restParticlesPerMeter = REST_PARTICLES_PER_METER; fluidDesc.motionLimitMultiplier = MOTION_LIMIT_MULTIPLIER; fluidDesc.packetSizeMultiplier = PACKET_SIZE_MULTIPLIER; fluidDesc.stiffness = 40; // 50 fluidDesc.viscosity = 22; fluidDesc.restDensity = 1000; fluidDesc.damping = 0; // There are some API changes since 280 version, Fluid collision coefficients have been renamed, // E.g. NxFluidDesc::dynamicCollisionAdhesion is named NxFluidDesc::dynamicFrictionForDynamicShapes. #if NX_SDK_VERSION_NUMBER < 280 fluidDesc.staticCollisionRestitution = 0.162f; fluidDesc.staticCollisionAdhesion = 0.146f; fluidDesc.dynamicCollisionRestitution = 0.5f; fluidDesc.dynamicCollisionAdhesion = 0.5f; #else fluidDesc.restitutionForStaticShapes = 0.162f; fluidDesc.dynamicFrictionForStaticShapes = 0.146f; fluidDesc.restitutionForDynamicShapes = 0.5f; fluidDesc.dynamicFrictionForDynamicShapes = 0.5f; #endif fluidDesc.simulationMethod = NX_F_SPH; //NX_F_NO_PARTICLE_INTERACTION; fluidDesc.initialParticleData = particles; fluidDesc.particlesWriteData = particles; if(!bHardwareFluid) fluidDesc.flags &= ~NX_FF_HARDWARE; fluid = gScene->createFluid(fluidDesc); if(!fluid) { fluidDesc.flags &= ~NX_FF_HARDWARE; bHardwareFluid = false; fluid = gScene->createFluid(fluidDesc); } assert(fluid != NULL); return fluid; }
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 Cloth::generateRegularMeshDesc(NxClothMeshDesc &desc, NxReal w, NxReal h, NxReal d, bool texCoords) { int numX = (int)(w / d) + 1; int numY = (int)(h / d) + 1; desc.numVertices = (numX+1) * (numY+1); desc.numTriangles = numX*numY*2; desc.pointStrideBytes = sizeof(NxVec3); desc.triangleStrideBytes = 3*sizeof(NxU32); desc.vertexMassStrideBytes = sizeof(NxReal); desc.vertexFlagStrideBytes = sizeof(NxU32); desc.points = (NxVec3*)malloc(sizeof(NxVec3)*desc.numVertices); desc.triangles = (NxU32*)malloc(sizeof(NxU32)*desc.numTriangles*3); desc.vertexMasses = 0; desc.vertexFlags = 0; desc.flags = 0; mMaxVertices = TEAR_MEMORY_FACTOR * desc.numVertices; mMaxIndices = 3 * desc.numTriangles; _geo_cloth = new osg::Geode; int i,j; // create particles - POINTS { osg::Geometry* pointsGeom = new osg::Geometry(); osg::Vec3Array* vertices = new osg::Vec3Array; NxVec3 *p = (NxVec3*)desc.points; for (i = 0; i <= numY; i++) { for (j = 0; j <= numX; j++) { p->set(d*j, 0.0f, d*i); vertices->push_back(osg::Vec3f(d*j, d*i, 0.0f)); p++; } } pointsGeom->setVertexArray(vertices); osg::Vec4Array* colors = new osg::Vec4Array; colors->push_back(osg::Vec4(1.0f,1.0f,0.0f,0.8f)); pointsGeom->setColorArray(colors); pointsGeom->setColorBinding(osg::Geometry::BIND_OVERALL); // set the normal in the same way color. osg::Vec3Array* normals = new osg::Vec3Array; normals->push_back(osg::Vec3(0.0f,-1.0f,0.0f)); pointsGeom->setNormalArray(normals); pointsGeom->setNormalBinding(osg::Geometry::BIND_OVERALL); osg::StateSet* stateSet = new osg::StateSet(); pointsGeom->setStateSet(stateSet); pointsGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POINTS,0,vertices->size())); osg::Point* point = new osg::Point; point->setDistanceAttenuation(osg::Vec3(0.0,0.0000,0.05f)); point->setSize(20.0f); stateSet->setAttribute(point); osg::PointSprite *sprite = new osg::PointSprite(); stateSet->setTextureAttributeAndModes(0, sprite, osg::StateAttribute::ON); // add the points geometry to the geode. _geo_cloth->addDrawable(pointsGeom); } if (texCoords) { mTempTexCoords = (float *)malloc(sizeof(float)*2*TEAR_MEMORY_FACTOR*desc.numVertices); float *f = mTempTexCoords; float dx = 1.0f; if (numX > 0) dx /= numX; float dy = 1.0f; if (numY > 0) dy /= numY; for (i = 0; i <= numY; i++) { for (j = 0; j <= numX; j++) { *f++ = j*dx; *f++ = i*dy; } } mNumTempTexCoords = desc.numVertices; } else { mNumTempTexCoords = 0; mTempTexCoords = NULL; } NxU32 *id = (NxU32*)desc.triangles; for (i = 0; i < numY; i++) { for (j = 0; j < numX; j++) { NxU32 i0 = i * (numX+1) + j; NxU32 i1 = i0 + 1; NxU32 i2 = i0 + (numX+1); NxU32 i3 = i2 + 1; if ((j+i)%2) { *id++ = i0; *id++ = i2; *id++ = i1; *id++ = i1; *id++ = i2; *id++ = i3; } else { *id++ = i0; *id++ = i2; *id++ = i3; *id++ = i0; *id++ = i3; *id++ = i1; } } } }
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 MyCloth::generateRegularMeshDesc(NxClothMeshDesc &desc, NxReal w, NxReal h, NxReal d, bool texCoords) { int numX = (int)(w / d) + 1; int numY = (int)(h / d) + 1; desc.numVertices = (numX+1) * (numY+1); desc.numTriangles = numX*numY*2; desc.pointStrideBytes = sizeof(NxVec3); desc.triangleStrideBytes = 3*sizeof(NxU32); desc.vertexMassStrideBytes = sizeof(NxReal); desc.vertexFlagStrideBytes = sizeof(NxU32); desc.points = (NxVec3*)malloc(sizeof(NxVec3)*desc.numVertices); desc.triangles = (NxU32*)malloc(sizeof(NxU32)*desc.numTriangles*3); desc.vertexMasses = 0; desc.vertexFlags = 0; desc.flags = 0; mMaxVertices = desc.numVertices; mMaxIndices = 3 * desc.numTriangles; int i,j; NxVec3 *p = (NxVec3*)desc.points; for (i = 0; i <= numY; i++) { for (j = 0; j <= numX; j++) { p->set(d*j, 0.0f, d*i); p++; } } if (texCoords) { mTempTexCoords = (GLfloat *)malloc(sizeof(GLfloat)*2*desc.numVertices); GLfloat *f = mTempTexCoords; GLfloat dx = 1.0f; if (numX > 0) dx /= numX; GLfloat dy = 1.0f; if (numY > 0) dy /= numY; for (i = 0; i <= numY; i++) { for (j = 0; j <= numX; j++) { *f++ = j*dx; *f++ = i*dy; } } mNumTempTexCoords = desc.numVertices; } else { mNumTempTexCoords = 0; mTempTexCoords = NULL; } NxU32 *id = (NxU32*)desc.triangles; for (i = 0; i < numY; i++) { for (j = 0; j < numX; j++) { NxU32 i0 = i * (numX+1) + j; NxU32 i1 = i0 + 1; NxU32 i2 = i0 + (numX+1); NxU32 i3 = i2 + 1; if ((j+i)%2) { *id++ = i0; *id++ = i2; *id++ = i1; *id++ = i1; *id++ = i2; *id++ = i3; } else { *id++ = i0; *id++ = i2; *id++ = i3; *id++ = i0; *id++ = i3; *id++ = i1; } } } }
void PxCloth::_initClothMesh() { // Make sure we can change the world. mWorld->releaseWriteLock(); _releaseMesh(); // Must have at least 2 verts. mPatchVerts.x = getMax( 2, mPatchVerts.x ); mPatchVerts.y = getMax( 2, mPatchVerts.y ); // Generate a uniform cloth patch, // w and h are the width and height, // d is the distance between vertices. mNumVertices = mPatchVerts.x * mPatchVerts.y; mNumIndices = (mPatchVerts.x-1) * (mPatchVerts.y-1) * 2; NxClothMeshDesc desc; desc.numVertices = mNumVertices; desc.numTriangles = mNumIndices; desc.pointStrideBytes = sizeof(NxVec3); desc.triangleStrideBytes = 3*sizeof(NxU32); desc.points = (NxVec3*)dMalloc(sizeof(NxVec3)*desc.numVertices); desc.triangles = (NxU32*)dMalloc(sizeof(NxU32)*desc.numTriangles*3); desc.flags = 0; U32 i,j; NxVec3 *p = (NxVec3*)desc.points; F32 patchWidth = mPatchSize.x / (F32)( mPatchVerts.x - 1 ); F32 patchHeight = mPatchSize.y / (F32)( mPatchVerts.y - 1 ); for (i = 0; i < mPatchVerts.y; i++) { for (j = 0; j < mPatchVerts.x; j++) { p->set( patchWidth * j, 0.0f, patchHeight * i ); p++; } } NxU32 *id = (NxU32*)desc.triangles; for (i = 0; i < mPatchVerts.y-1; i++) { for (j = 0; j < mPatchVerts.x-1; j++) { NxU32 i0 = i * mPatchVerts.x + j; NxU32 i1 = i0 + 1; NxU32 i2 = i0 + mPatchVerts.x; NxU32 i3 = i2 + 1; if ( (j+i) % 2 ) { *id++ = i0; *id++ = i2; *id++ = i1; *id++ = i1; *id++ = i2; *id++ = i3; } else { *id++ = i0; *id++ = i2; *id++ = i3; *id++ = i0; *id++ = i3; *id++ = i1; } } } NxCookingInterface *cooker = PxWorld::getCooking(); cooker->NxInitCooking(); // Ok... cook the mesh! NxCookingParams params; params.targetPlatform = PLATFORM_PC; params.skinWidth = 0.01f; params.hintCollisionSpeed = false; cooker->NxSetCookingParams( params ); PxMemStream cooked; if ( cooker->NxCookClothMesh( desc, cooked ) ) { cooked.resetPosition(); mClothMesh = gPhysicsSDK->createClothMesh( cooked ); } cooker->NxCloseCooking(); NxVec3 *ppoints = (NxVec3*)desc.points; NxU32 *triangs = (NxU32*)desc.triangles; dFree( ppoints ); dFree( triangs ); if ( mClothMesh ) _initReceiveBuffers(); }
// Using swept code & direct position update (no physics engine) // This function is the generic character controller logic, valid for all swept volumes void SweepTest::MoveCharacter( void* user_data, void* user_data2, SweptVolume& volume, const NxVec3& direction, NxU32 nb_boxes, const NxExtendedBounds3* boxes, const void** box_user_data, NxU32 nb_capsules, const NxExtendedCapsule* capsules, const void** capsule_user_data, NxU32 groups, float min_dist, NxU32& collision_flags, const NxGroupsMask* groupsMask, bool constrainedClimbingMode ) { mHitNonWalkable = false; NxU32 CollisionFlags = 0; const NxU32 MaxIter = mMaxIter; // 1 for "collide and stop" const NxU32 MaxIterUp = MaxIter; const NxU32 MaxIterSides = MaxIter; // const NxU32 MaxIterDown = gWalkExperiment ? MaxIter : 1; const NxU32 MaxIterDown = 1; // ### this causes the artificial gap on top of chars float StepOffset = mStepOffset; // Default step offset can be cancelled in some cases. // Save initial height Extended OriginalHeight = volume.mCenter[mUpDirection]; Extended OriginalBottomPoint = OriginalHeight - volume.mHalfHeight; // UBI // TEST! Disable auto-step when flying. Not sure this is really useful. if(direction[mUpDirection]>0.0f) StepOffset = 0.0f; // Decompose motion into 3 independent motions: up, side, down // - if the motion is purely down (gravity only), the up part is needed to fight accuracy issues. For example if the // character is already touching the geometry a bit, the down sweep test might have troubles. If we first move it above // the geometry, the problems disappear. // - if the motion is lateral (character moving forward under normal gravity) the decomposition provides the autostep feature // - if the motion is purely up, the down part can be skipped NxVec3 UpVector(0.0f, 0.0f, 0.0f); NxVec3 DownVector(0.0f, 0.0f, 0.0f); if(direction[mUpDirection]<0.0f) DownVector[mUpDirection] = direction[mUpDirection]; else UpVector[mUpDirection] = direction[mUpDirection]; NxVec3 SideVector = direction; SideVector[mUpDirection] = 0.0f; // If the side motion is zero, i.e. if the character is not really moving, disable auto-step. if(!SideVector.isZero()) UpVector[mUpDirection] += StepOffset; // ==========[ Initial volume query ]=========================== if(1) { NxVec3 MotionExtents = UpVector; MotionExtents.max(SideVector); MotionExtents.max(DownVector); NxExtendedBounds3 TemporalBox; volume.ComputeTemporalBox(*this, TemporalBox, volume.mCenter, MotionExtents); // Gather touched geoms UpdateTouchedGeoms(user_data, volume, nb_boxes, boxes, box_user_data, nb_capsules, capsules, capsule_user_data, groups, TemporalBox, groupsMask); } // ==========[ UP PASS ]=========================== mCachedTriIndexIndex = 0; const bool PerformUpPass = true; NxU32 NbCollisions=0; if(PerformUpPass) { // Prevent user callback for up motion. This up displacement is artificial, and only needed for auto-stepping. // If we call the user for this, we might eventually apply upward forces to objects resting on top of us, even // if we visually don't move. This produces weird-looking motions. mValidateCallback = false; // In the walk-experiment we explicitely want to ban any up motions, to avoid characters climbing slopes they shouldn't climb. // So let's bypass the whole up pass. if(!mWalkExperiment) { // ### MaxIter here seems to "solve" the V bug if(DoSweepTest(user_data, user_data2, nb_boxes, boxes, box_user_data, nb_capsules, capsules, capsule_user_data, volume, UpVector, MaxIterUp, &NbCollisions, groups, min_dist, groupsMask)) { if(NbCollisions) { CollisionFlags |= NXCC_COLLISION_UP; // Clamp step offset to make sure we don't undo more than what we did Extended Delta = volume.mCenter[mUpDirection] - OriginalHeight; if(Delta<StepOffset) { StepOffset=float(Delta); } } } } } // ==========[ SIDE PASS ]=========================== mCachedTriIndexIndex = 1; mValidateCallback = true; const bool PerformSidePass = true; if(PerformSidePass) { NbCollisions=0; if(DoSweepTest(user_data, user_data2, nb_boxes, boxes, box_user_data, nb_capsules, capsules, capsule_user_data, volume, SideVector, MaxIterSides, &NbCollisions, groups, min_dist, groupsMask)) { if(NbCollisions) CollisionFlags |= NXCC_COLLISION_SIDES; } } // ==========[ DOWN PASS ]=========================== mCachedTriIndexIndex = 2; const bool PerformDownPass = true; if(PerformDownPass) { NbCollisions=0; if(!SideVector.isZero()) // We disabled that before so we don't have to undo it in that case DownVector[mUpDirection] -= StepOffset; // Undo our artificial up motion mValidTri = false; // min_dist actually makes a big difference :( // AAARRRGGH: if we get culled because of min_dist here, mValidTri never becomes valid! if(DoSweepTest(user_data, user_data2, nb_boxes, boxes, box_user_data, nb_capsules, capsules, capsule_user_data, volume, DownVector, MaxIterDown, &NbCollisions, groups, min_dist, groupsMask, true)) { if(NbCollisions) { CollisionFlags |= NXCC_COLLISION_DOWN; if(mHandleSlope) // PT: I think the following fix shouldn't be performed when mHandleSlope is false. { // PT: the following code is responsible for a weird capsule behaviour, // when colliding against a highly tesselated terrain: // - with a large direction vector, the capsule gets stuck against some part of the terrain // - with a slower direction vector (but in the same direction!) the capsule manages to move // I will keep that code nonetheless, since it seems to be useful for them. // constrainedClimbingMode if ( constrainedClimbingMode && mContactPointHeight > OriginalBottomPoint + StepOffset) { mHitNonWalkable = true; if(!mWalkExperiment) return; } //~constrainedClimbingMode } } } // TEST: do another down pass if we're on a non-walkable poly // ### kind of works but still not perfect // ### could it be because we zero the Y impulse later? // ### also check clamped response vectors if(mHandleSlope && mValidTri && direction[mUpDirection]<0.0f) { NxVec3 Normal; #ifdef USE_CONTACT_NORMAL_FOR_SLOPE_TEST Normal = mCN; #else mTouched.normal(Normal); #endif // if(fabsf(Normal|NxVec3(0.0f, 1.0f, 0.0f))<cosf(45.0f*DEGTORAD)) if(Normal[mUpDirection]>=0.0f && Normal[mUpDirection]<mSlopeLimit) { mHitNonWalkable = true; // Early exit if we're going to run this again anyway... if(!mWalkExperiment) return; /* CatchScene()->GetRenderer()->AddLine(mTouched.mVerts[0], mTouched.mVerts[1], ARGB_YELLOW); CatchScene()->GetRenderer()->AddLine(mTouched.mVerts[0], mTouched.mVerts[2], ARGB_YELLOW); CatchScene()->GetRenderer()->AddLine(mTouched.mVerts[1], mTouched.mVerts[2], ARGB_YELLOW); */ // ==========[ WALK EXPERIMENT ]=========================== mNormalizeResponse=true; Extended Delta = volume.mCenter[mUpDirection] > OriginalHeight ? volume.mCenter[mUpDirection] - OriginalHeight : 0.0f; Delta += fabsf(direction[mUpDirection]); Extended Recover = Delta; NbCollisions=0; const Extended MD = Recover < min_dist ? Recover/float(MaxIter) : min_dist; NxVec3 RecoverPoint(0,0,0); RecoverPoint[mUpDirection]=-float(Recover); if(DoSweepTest(user_data, user_data2, nb_boxes, boxes, box_user_data, nb_capsules, capsules, capsule_user_data, volume, RecoverPoint, MaxIter, &NbCollisions, groups, float(MD), groupsMask)) { // if(NbCollisions) CollisionFlags |= COLLISION_Y_DOWN; // PT: why did we do this ? Removed for now. It creates a bug (non registered event) when we land on a steep poly. // However this might have been needed when we were sliding on those polygons, and we didn't want the land anim to // start while we were sliding. // if(NbCollisions) CollisionFlags &= ~NXCC_COLLISION_DOWN; } mNormalizeResponse=false; } } } // Setup new collision flags collision_flags = CollisionFlags; }
// 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; }
hsVectorStream* plPhysXCooking::IMakePolytope(const plMaxMeshExtractor::NeutralMesh& inMesh) { hsBool success=0; std::vector<hsPoint3> outCloud; hsPoint3 offset; int numPlanes=26; float planeMax[26]; int indexMax[26]; hsPoint3 AABBMin(FLT_MAX,FLT_MAX,FLT_MAX); hsPoint3 AABBMax(-FLT_MAX,-FLT_MAX,-FLT_MAX); //prep NxVec3* vectors = new NxVec3[26]; int curvec=0; for(int xcomp= -1;xcomp<2;xcomp++) { for(int ycomp= -1;ycomp<2;ycomp++) { for(int zcomp= -1;zcomp<2;zcomp++) { if(!((xcomp==0)&&(ycomp==0)&&(zcomp==0))) { vectors[curvec].set((float)(xcomp),(float)(ycomp),(float)(zcomp)); vectors[curvec].normalize(); planeMax[curvec]=(-FLT_MAX); //indexMax[curvec]=0; curvec++; } } } } /* for(int i=0;i<26;i++) {//make your max and mins planeMax[i]=(-FLT_MAX); } */ hsPoint3 centroid(0.0f,0.0f,0.0f); for(int i=0;i<inMesh.fNumVerts;i++) centroid+=inMesh.fVerts[i]; centroid=centroid/(float)inMesh.fNumVerts; //temp NxVec3* nxLocs=new NxVec3[inMesh.fNumVerts]; NxVec3* nxLocs2=new NxVec3[inMesh.fNumVerts]; for(int i=0;i<inMesh.fNumVerts;i++) { hsPoint3 temppt=inMesh.fVerts[i] - centroid; nxLocs[i]=plPXConvert::Point(temppt); } NxMat33 rot; NxVec3 eigen; PCA(nxLocs,inMesh.fNumVerts,rot); NxMat33 invrot; rot.getInverse(invrot); for(int i=0; i<inMesh.fNumVerts;i++) { nxLocs2[i]=invrot*nxLocs[i]; } for(int i=0;i<inMesh.fNumVerts;i++) { for(int plane=0;plane<26;plane++) { float dist=nxLocs2[i].dot(vectors[plane]); if(dist>=planeMax[plane]) { planeMax[plane]=dist; indexMax[plane]=i; } } } for(int i=0;i<inMesh.fNumVerts;i++) { AABBMin.fX = hsMinimum(nxLocs2[i].x, AABBMin.fX); AABBMin.fY = hsMinimum(nxLocs2[i].y, AABBMin.fY); AABBMin.fZ = hsMinimum(nxLocs2[i].z, AABBMin.fZ); AABBMax.fX = hsMaximum(nxLocs2[i].x, AABBMax.fX); AABBMax.fY = hsMaximum(nxLocs2[i].y, AABBMax.fY); AABBMax.fZ = hsMaximum(nxLocs2[i].z, AABBMax.fZ); } int resultingPoints=0; for(int i=0;i<26;i++) { for(int j=0;j<26;j++) { for(int k=0;k<26;k++) { NxVec3 res; if(ThreePlaneIntersect(vectors[i],nxLocs2[indexMax[i]],vectors[j],nxLocs2[indexMax[j]], vectors[k],nxLocs2[indexMax[k]],res)) { //check it is within all slabs bool within=true; int curplane=0; do { float intersecdist=res.dot(vectors[curplane]); if((intersecdist-planeMax[curplane])>0.0001) { within=false; } curplane++; } while((curplane<26)&&within); if(within) // if((res.x>=AABBMin.fX)&&(res.x<=AABBMax.fX)&& // (res.y>=AABBMin.fY)&&(res.y<=AABBMax.fY)&& // (res.z>=AABBMin.fZ)&&(res.z<=AABBMax.fZ)) { NxVec3 reverted; reverted=rot*res; reverted.x=reverted.x +centroid.fX; reverted.y=reverted.y +centroid.fY; reverted.z=reverted.z +centroid.fZ; hsPoint3 out; out=plPXConvert::Point(reverted); outCloud.push_back(out); } } } } } //planes discovered //this is'nt right //cleanup offset=centroid; delete[] vectors; hsPoint3* pointages=new hsPoint3[outCloud.size()]; for(int x=0;x<outCloud.size();x++)pointages[x]=outCloud[x]; hsVectorStream* vectorstrm; vectorstrm= CookHull(outCloud.size(),pointages,true); delete[] pointages; delete[] nxLocs; delete[] nxLocs2; return vectorstrm; }
// ---------------------------------------------------------------------- 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; }
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 ); }
int main(int argc, char **argv) { //init and PVD bool initialized = false; NxPhysicsSDK *physicsSDK = NxCreatePhysicsSDK(NX_PHYSICS_SDK_VERSION); if (!physicsSDK) return 0; else physicsSDK->getFoundationSDK().getRemoteDebugger()->connect("localhost", 5425); physicsSDK->setParameter(NX_CONTINUOUS_CD, true); initialized = true; //create a scene bool sceneInit = false; NxSceneDesc sceneDesc; sceneDesc.gravity.set(0, -9.81f, 0); gScene = physicsSDK->createScene(sceneDesc); if (gScene != NULL) sceneInit = true; //create a plane { NxActorDesc actorDesc; NxPlaneShapeDesc planeDesc; //planeDesc.normal = NxVec3(0, 0, 1); //planeDesc.d = -10.0f; actorDesc.shapes.pushBack(&planeDesc); gScene->createActor(actorDesc); } //create material NxMaterial *defaultMaterial = gScene->getMaterialFromIndex(0); defaultMaterial->setRestitution(0.3f); defaultMaterial->setStaticFriction(0.5f); defaultMaterial->setDynamicFriction(0.5f); //create a box { NxActorDesc actorDesc; NxBodyDesc bodyDesc; bodyDesc.angularDamping = 0.5; bodyDesc.linearVelocity = NxVec3(1, 0, 0); actorDesc.body = &bodyDesc; NxBoxShapeDesc boxDesc; boxDesc.dimensions = NxVec3(2.0f, 3.0f, 4.0f); actorDesc.shapes.pushBack(&boxDesc); actorDesc.density = 10.0f; actorDesc.globalPose.t = NxVec3(10.0f, 10.0f, 10.0f); gScene->createActor(actorDesc)->userData = NULL; } //create a cloth { // Create the objects in the scene NxActor* sphere1 = CreateSphere(NxVec3(-1, 0, -0.5), 1, 10); NxActor* box1 = CreateBox(NxVec3(1, 0, -1), NxVec3(1, 1, 1), 10); NxActor* box2 = CreateBox(NxVec3(0, 6.5, 0), NxVec3(5, 0.5, 0.5), 10); NxActor* box3 = CreateBox(NxVec3(0, 6.5, -7), NxVec3(5, 0.5, 0.5), 10); box2->setLinearDamping(5); box3->setLinearDamping(5); NxD6JointDesc d6Desc; d6Desc.actor[0] = NULL; d6Desc.actor[1] = box2; NxVec3 globalAnchor(0, 7, 0); d6Desc.localAnchor[0] = globalAnchor; box2->getGlobalPose().multiplyByInverseRT(globalAnchor, d6Desc.localAnchor[1]); box2->raiseBodyFlag(NX_BF_DISABLE_GRAVITY); box3->getGlobalPose().multiplyByInverseRT(globalAnchor, d6Desc.localAnchor[1]); box3->raiseBodyFlag(NX_BF_DISABLE_GRAVITY); d6Desc.localAxis[0] = NxVec3(1, 0, 0); d6Desc.localNormal[0] = NxVec3(0, 1, 0); d6Desc.localAxis[1] = NxVec3(1, 0, 0); d6Desc.localNormal[1] = NxVec3(0, 1, 0); d6Desc.twistMotion = NX_D6JOINT_MOTION_LOCKED; d6Desc.swing1Motion = NX_D6JOINT_MOTION_LOCKED; d6Desc.swing2Motion = NX_D6JOINT_MOTION_LOCKED; d6Desc.xMotion = NX_D6JOINT_MOTION_FREE; d6Desc.yMotion = NX_D6JOINT_MOTION_FREE; d6Desc.zMotion = NX_D6JOINT_MOTION_FREE; NxJoint* d6Joint = gScene->createJoint(d6Desc); NxClothDesc clothDesc; clothDesc.globalPose.t = NxVec3(4, 7, 0); clothDesc.thickness = 0.2; //clothDesc.density = 1; clothDesc.bendingStiffness = 0.5; clothDesc.stretchingStiffness = 1; //clothDesc.dampingCoefficient = 0.5; clothDesc.friction = 0.5; //clothDesc.collisionResponseCoefficient = 1; //clothDesc.attachmentResponseCoefficient = 1; //clothDesc.solverIterations = 5; //clothDesc.flags |= NX_CLF_STATIC; //clothDesc.flags |= NX_CLF_DISABLE_COLLISION; //clothDesc.flags |= NX_CLF_VISUALIZATION; //clothDesc.flags |= NX_CLF_GRAVITY; clothDesc.flags |= NX_CLF_BENDING; //clothDesc.flags |= NX_CLF_BENDING_ORTHO; clothDesc.flags |= NX_CLF_DAMPING; //clothDesc.flags |= NX_CLF_COMDAMPING; clothDesc.flags |= NX_CLF_COLLISION_TWOWAY; clothDesc.flags &= ~NX_CLF_HARDWARE; clothDesc.flags |= NX_CLF_FLUID_COLLISION; clothDesc.selfCollisionThickness = 10.0f; NxReal w = 8; NxReal h = 7; NxReal d = 0.05; NxClothMeshDesc meshDesc; bool mInitDone = false; int numX = (int)(w / d) + 1; int numY = (int)(h / d) + 1; meshDesc.numVertices = (numX + 1) * (numY + 1); meshDesc.numTriangles = numX*numY * 2; meshDesc.pointStrideBytes = sizeof(NxVec3); meshDesc.triangleStrideBytes = 3 * sizeof(NxU32); meshDesc.vertexMassStrideBytes = sizeof(NxReal); meshDesc.vertexFlagStrideBytes = sizeof(NxU32); meshDesc.points = (NxVec3*)malloc(sizeof(NxVec3)*meshDesc.numVertices); meshDesc.triangles = (NxU32*)malloc(sizeof(NxU32)*meshDesc.numTriangles * 3); meshDesc.vertexMasses = 0; meshDesc.vertexFlags = 0; meshDesc.flags = 0; int i, j; NxVec3 *p = (NxVec3*)meshDesc.points; for (i = 0; i <= numY; i++) { for (j = 0; j <= numX; j++) { p->set(-d*j, 0.0f, -d*i); p++; } } NxU32 *id = (NxU32*)meshDesc.triangles; for (i = 0; i < numY; i++) { for (j = 0; j < numX; j++) { NxU32 i0 = i * (numX + 1) + j; NxU32 i1 = i0 + 1; NxU32 i2 = i0 + (numX + 1); NxU32 i3 = i2 + 1; if ((j + i) % 2) { *id++ = i0; *id++ = i2; *id++ = i1; *id++ = i1; *id++ = i2; *id++ = i3; } else { *id++ = i0; *id++ = i2; *id++ = i3; *id++ = i0; *id++ = i3; *id++ = i1; } } } // if we want tearing we must tell the cooker // this way it will generate some space for particles that will be generated during tearing if (meshDesc.flags & NX_CLF_TEARABLE) meshDesc.flags |= NX_CLOTH_MESH_TEARABLE; //cooking static NxCookingInterface *gCooking = 0; gCooking = NxGetCookingLib(NX_PHYSICS_SDK_VERSION); gCooking->NxInitCooking(); gCooking->NxCookClothMesh(meshDesc, UserStream("e:\\cooked.bin", false)); //Meshdata Buffers NxMeshData mReceiveBuffers; // here we setup the buffers through which the SDK returns the dynamic cloth data // we reserve more memory for vertices than the initial mesh takes // because tearing creates new vertices // the SDK only tears cloth as long as there is room in these buffers NxU32 numVertices = meshDesc.numVertices; NxU32 numTriangles = meshDesc.numTriangles; NxU32 maxVertices = 2 * numVertices; mReceiveBuffers.verticesPosBegin = (NxVec3*)malloc(sizeof(NxVec3)*maxVertices); mReceiveBuffers.verticesNormalBegin = (NxVec3*)malloc(sizeof(NxVec3)*maxVertices); mReceiveBuffers.verticesPosByteStride = sizeof(NxVec3); mReceiveBuffers.verticesNormalByteStride = sizeof(NxVec3); mReceiveBuffers.maxVertices = maxVertices; mReceiveBuffers.numVerticesPtr = (NxU32*)malloc(sizeof(NxU32)); // the number of triangles is constant, even if the cloth is torn NxU32 maxIndices = 3 * numTriangles; mReceiveBuffers.indicesBegin = (NxU32*)malloc(sizeof(NxU32)*maxIndices); mReceiveBuffers.indicesByteStride = sizeof(NxU32); mReceiveBuffers.maxIndices = maxIndices; mReceiveBuffers.numIndicesPtr = (NxU32*)malloc(sizeof(NxU32)); // the parent index information would be needed if we used textured cloth NxU32 maxParentIndices = maxVertices; mReceiveBuffers.parentIndicesBegin = (NxU32*)malloc(sizeof(NxU32)*maxParentIndices); mReceiveBuffers.parentIndicesByteStride = sizeof(NxU32); mReceiveBuffers.maxParentIndices = maxParentIndices; mReceiveBuffers.numParentIndicesPtr = (NxU32*)malloc(sizeof(NxU32)); // init the buffers in case we want to draw the mesh // before the SDK as filled in the correct values *mReceiveBuffers.numVerticesPtr = 0; *mReceiveBuffers.numIndicesPtr = 0; clothDesc.clothMesh = physicsSDK->createClothMesh(UserStream("e:\\cooked.bin", true)); clothDesc.meshData = mReceiveBuffers; NxCloth *mCloth; mCloth = gScene->createCloth(clothDesc); mCloth->attachToShape(*box2->getShapes(), NX_CLOTH_ATTACHMENT_TWOWAY); mCloth->attachToShape(*box3->getShapes(), NX_CLOTH_ATTACHMENT_TWOWAY); } //create fluid 1 { //fluid = CreateFluid(NxVec3(0, 12, -3.5), 15, 0.1, gScene); } //create fluid 2 { //Create a set of initial particles ParticleSDK* initParticles = new ParticleSDK[max_particles]; unsigned initParticlesNum = 0; //Create particle filled sphere in buffer. NxVec3 fluidPos(0, 2, 0); NxVec3 offsetPos(0, 12, -3.5); float distance = 0.1f; //#ifdef __PPCGEKKO__ // unsigned sideNum = 12; //#else unsigned sideNum = 16; //#endif //Setup structure to pass initial particles. NxParticleData initParticleData; initParticlesNum = 0; initParticleData.numParticlesPtr = &initParticlesNum; initParticleData.bufferPos = &initParticles[0].position.x; initParticleData.bufferPosByteStride = sizeof(ParticleSDK); initParticleData.bufferVel = &initParticles[0].velocity.x; initParticleData.bufferVelByteStride = sizeof(ParticleSDK); CreateParticleSphere(initParticleData, max_particles, false, offsetPos, NxVec3(0, 0, 0), 0.0f, distance, sideNum); //Setup fluid descriptor NxFluidDesc fluidDesc; fluidDesc.maxParticles = max_particles; fluidDesc.kernelRadiusMultiplier = 2.0f; fluidDesc.restParticlesPerMeter = 10.0f; fluidDesc.motionLimitMultiplier = 3.0f; fluidDesc.packetSizeMultiplier = 8; fluidDesc.collisionDistanceMultiplier = 0.1; fluidDesc.stiffness = 50.0f; fluidDesc.viscosity = 40.0f; fluidDesc.restDensity = 1000.0f; fluidDesc.damping = 0.0f; fluidDesc.restitutionForStaticShapes = 0.0f; fluidDesc.dynamicFrictionForStaticShapes = 0.05f; fluidDesc.simulationMethod = NX_F_SPH; fluidDesc.flags &= ~NX_FF_HARDWARE; //Add initial particles to fluid creation. fluidDesc.initialParticleData = initParticleData; //Create user fluid. //- create NxFluid in NxScene //- setup the buffers to read from data from the SDK //- set NxFluid::userData field to MyFluid instance bool trackUserData = false; bool provideCollisionNormals = false; MyFluid* fluid = new MyFluid(gScene, fluidDesc, trackUserData, provideCollisionNormals, NxVec3(0.4f, 0.5f, 0.9f), 0.03f); assert(fluid); gMyFluids.pushBack(fluid); } //simulate for (int i = 0; i < 3000; i++) { gScene->simulate(1.0f / 60.f); gScene->flushStream(); //GetPhysicsResults gScene->fetchResults(NX_RIGID_BODY_FINISHED, true); // update fluid status if (i == 400) { MyFluid* fluid = gMyFluids[0]; const ParticleSDK* particles = fluid->getParticles(); unsigned particlesNum = fluid->getParticlesNum(); if (!gUpdates) { gUpdates = new ParticleUpdateSDK[max_particles]; } for (unsigned i = 0; i < particlesNum; i++) { ParticleUpdateSDK& update = gUpdates[i]; NxVec3& force = update.force; force.set(0, 0, 0); NxU32& flags = update.flags; if (i >= particlesNum/2) { flags = 0; flags |= NX_FP_DELETE; } else { flags = 0; } } //在这里更改粒子的属性 NxParticleUpdateData updateData; updateData.bufferFlag = &gUpdates[0].flags; updateData.bufferFlagByteStride = sizeof(ParticleUpdateSDK); fluid->getNxFluid()->updateParticles(updateData); } } //release if (physicsSDK != NULL) { if (gScene != NULL) physicsSDK->releaseScene(*gScene); gScene = NULL; NxReleasePhysicsSDK(physicsSDK); physicsSDK = NULL; } return 1; }
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; } }
void Controller::move(SweptVolume& volume, const NxVec3& disp, NxU32 activeGroups, NxF32 minDist, NxU32& collisionFlags, NxF32 sharpness, const NxGroupsMask* groupsMask, bool constrainedClimbingMode) { // Dynamic-load the utility library if(!gUtilLib) gUtilLib = NxGetUtilLib(); assert(gUtilLib); if(!gUtilLib) return; SweepTest* ST = &cctModule; // Init CCT with per-controller settings ST->debugData = manager->debugData; ST->mSkinWidth = skinWidth; ST->mStepOffset = stepOffset; ST->mUpDirection = upDirection; ST->mHandleSlope = handleSlope; ST->mSlopeLimit = slopeLimit; ST->mFirstUpdate = true; /////////// Controller** boxUserData = NULL; NxExtendedBounds3* boxes = NULL; NxU32 nbBoxes = 0; Controller** capsuleUserData = NULL; NxExtendedCapsule* capsules = NULL; NxU32 nbCapsules = 0; if(1) { // Experiment - to do better NxU32 nbControllers = manager->getNbControllers(); Controller** controllers = manager->getControllers(); boxes = (NxExtendedBounds3*)NxAlloca(nbControllers*sizeof(NxExtendedBounds3)); capsules = (NxExtendedCapsule*)NxAlloca(nbControllers*sizeof(NxExtendedCapsule)); // It's evil to waste that ram boxUserData = (Controller**)NxAlloca(nbControllers*sizeof(Controller*)); capsuleUserData = (Controller**)NxAlloca(nbControllers*sizeof(Controller*)); while(nbControllers--) { Controller* currentController = *controllers++; if(currentController==this) continue; NxActor* pActor = currentController->getActor(); int nbShapes = pActor->getNbShapes(); NX_ASSERT( nbShapes == 1 ); NxShape* pCurrentShape= pActor->getShapes()[0]; // Depending on user settings the current controller can be: // - discarded // - always kept // - or tested against filtering flags NxCCTInteractionFlag interactionFlag = currentController->getInteraction(); bool keepController = true; if(interactionFlag==NXIF_INTERACTION_EXCLUDE) keepController = false; else if(interactionFlag==NXIF_INTERACTION_USE_FILTER) keepController = (activeGroups & ( 1 << pCurrentShape->getGroup()))!=0; if(keepController) { if(currentController->type==NX_CONTROLLER_BOX) { currentController->getWorldBox(boxes[nbBoxes]); boxUserData[nbBoxes++] = currentController; } else if(currentController->type==NX_CONTROLLER_CAPSULE) { CapsuleController* CC = static_cast<CapsuleController*>(currentController); NxExtendedVec3 p0 = CC->position; NxExtendedVec3 p1 = CC->position; p0[ST->mUpDirection] -= CC->height*0.5f; p1[ST->mUpDirection] += CC->height*0.5f; capsules[nbCapsules].p0 = p0; capsules[nbCapsules].p1 = p1; capsules[nbCapsules].radius = CC->radius; capsuleUserData[nbCapsules++] = currentController; } else ASSERT(0); } } } /////////// ST->mWalkExperiment = false; NxExtendedVec3 Backup = volume.mCenter; ST->MoveCharacter(scene, (Controller*)this, volume, disp, nbBoxes, nbBoxes ? boxes : NULL, nbBoxes ? (const void**)boxUserData : NULL, nbCapsules, nbCapsules ? capsules : NULL, nbCapsules ? (const void**)capsuleUserData : NULL, activeGroups, minDist, collisionFlags, groupsMask, constrainedClimbingMode); if(ST->mHitNonWalkable) { // A bit slow, but everything else I tried was less convincing... ST->mWalkExperiment = true; volume.mCenter = Backup; ST->MoveCharacter(scene, (Controller*)this, volume, disp, nbBoxes, nbBoxes ? boxes : NULL, nbBoxes ? (const void**)boxUserData : NULL, nbCapsules, nbCapsules ? capsules : NULL, nbCapsules ? (const void**)capsuleUserData : NULL, activeGroups, minDist, collisionFlags, groupsMask, constrainedClimbingMode); ST->mWalkExperiment = false; } if(sharpness<0.0f) volume.mCenter = Backup; // Copy results back position = volume.mCenter; NxVec3 Delta = Backup - volume.mCenter; NxF32 deltaM2 = Delta.magnitudeSquared(); if(deltaM2!=0.0f) { // Update kinematic actor if(kineActor) kineActor->moveGlobalPosition(NxVec3((float)position.x, (float)position.y, (float)position.z)); } filteredPosition = position; sharpness = fabsf(sharpness); // Apply feedback filter if needed if(sharpness<1.0f) filteredPosition[upDirection] = feedbackFilter(position[upDirection], memory, sharpness); // if(manager->debugData) // manager->debugData->addAABB(cctModule.mCachedTBV, NX_ARGB_YELLOW); }
float * NovodexPhysicSystem::getGravity() const { static NxVec3 g(0,0,0); m_scene->getGravity(g); return g.get(); }