// Call the physics engine to do one 'timeStep' and collect collisions and updates // into ObjectsWithCollisions and ObjectsWithUpdates data structures. private void DoPhysicsStep(float timeStep) { // prevent simulation until we've been initialized if (!m_initialized) { return; } LastTimeStep = timeStep; int updatedEntityCount = 0; int collidersCount = 0; int beforeTime = Util.EnvironmentTickCount(); int simTime = 0; int numTaints = _taintOperations.Count; InTaintTime = true; // Only used for debugging so locking is not necessary. // update the prim states while we know the physics engine is not busy ProcessTaints(); // Some of the physical objects requre individual, pre-step calls // (vehicles and avatar movement, in particular) TriggerPreStepEvent(timeStep); // the prestep actions might have added taints numTaints += _taintOperations.Count; ProcessTaints(); InTaintTime = false; // Only used for debugging so locking is not necessary. // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. // Only enable this in a limited test world with few objects. if (m_physicsPhysicalDumpEnabled) { PE.DumpAllInfo(World); } // step the physical world one interval m_simulationStep++; int numSubSteps = 0; try { numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount); } catch (Exception e) { m_log.WarnFormat("{0},PhysicsStep Exception: nTaints={1}, substeps={2}, updates={3}, colliders={4}, e={5}", LogHeader, numTaints, numSubSteps, updatedEntityCount, collidersCount, e); DetailLog("{0},PhysicsStepException,call, nTaints={1}, substeps={2}, updates={3}, colliders={4}", DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount); updatedEntityCount = 0; collidersCount = 0; } // Make the physics engine dump useful statistics periodically if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0)) { PE.DumpPhysicsStatistics(World); } // Get a value for 'now' so all the collision and update routines don't have to get their own. SimulationNowTime = Util.EnvironmentTickCount(); // Send collision information to the colliding objects. The objects decide if the collision // is 'real' (like linksets don't collide with themselves) and the individual objects // know if the simulator has subscribed to collisions. lock (CollisionLock) { if (collidersCount > 0) { for (int ii = 0; ii < collidersCount; ii++) { uint cA = m_collisionArray[ii].aID; uint cB = m_collisionArray[ii].bID; Vector3 point = m_collisionArray[ii].point; Vector3 normal = m_collisionArray[ii].normal; float penetration = m_collisionArray[ii].penetration; SendCollision(cA, cB, point, normal, penetration); SendCollision(cB, cA, point, -normal, penetration); } } } // If any of the objects had updated properties, tell the managed objects about the update // and remember that there was a change so it will be passed to the simulator. lock (UpdateLock) { if (updatedEntityCount > 0) { for (int ii = 0; ii < updatedEntityCount; ii++) { EntityProperties entprop = m_updateArray[ii]; BSPhysObject pobj; if (PhysObjects.TryGetValue(entprop.ID, out pobj)) { if (pobj.IsInitialized) { pobj.UpdateProperties(entprop); } } } } } // Some actors want to know when the simulation step is complete. TriggerPostStepEvent(timeStep); simTime = Util.EnvironmentTickCountSubtract(beforeTime); if (PhysicsLogging.Enabled) { DetailLog("{0},DoPhysicsStep,complete,frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}", DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount, ObjectsWithCollisions.Count); } // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. // Only enable this in a limited test world with few objects. if (m_physicsPhysicalDumpEnabled) { PE.DumpAllInfo(World); } // The physics engine returns the number of milliseconds it simulated this call. // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. // Multiply by a fixed nominal frame rate to give a rate similar to the simulator (usually 55). m_simulatedTime += (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate; }
// Simulate one timestep public override float Simulate(float timeStep) { // prevent simulation until we've been initialized if (!m_initialized) { return(5.0f); } LastTimeStep = timeStep; int updatedEntityCount = 0; int collidersCount = 0; int beforeTime = 0; int simTime = 0; // update the prim states while we know the physics engine is not busy int numTaints = _taintOperations.Count; InTaintTime = true; // Only used for debugging so locking is not necessary. ProcessTaints(); // Some of the physical objects requre individual, pre-step calls TriggerPreStepEvent(timeStep); // the prestep actions might have added taints numTaints += _taintOperations.Count; ProcessTaints(); InTaintTime = false; // Only used for debugging so locking is not necessary. // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. // Only enable this in a limited test world with few objects. if (m_physicsPhysicalDumpEnabled) { PE.DumpAllInfo(World); } // step the physical world one interval m_simulationStep++; int numSubSteps = 0; try { if (PhysicsLogging.Enabled) { beforeTime = Util.EnvironmentTickCount(); } numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount); if (PhysicsLogging.Enabled) { simTime = Util.EnvironmentTickCountSubtract(beforeTime); DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}", DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount, ObjectsWithCollisions.Count); } } catch (Exception e) { m_log.WarnFormat("{0},PhysicsStep Exception: nTaints={1}, substeps={2}, updates={3}, colliders={4}, e={5}", LogHeader, numTaints, numSubSteps, updatedEntityCount, collidersCount, e); DetailLog("{0},PhysicsStepException,call, nTaints={1}, substeps={2}, updates={3}, colliders={4}", DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount); updatedEntityCount = 0; collidersCount = 0; } if ((m_simulationStep % PhysicsMetricDumpFrames) == 0) { PE.DumpPhysicsStatistics(World); } // Get a value for 'now' so all the collision and update routines don't have to get their own. SimulationNowTime = Util.EnvironmentTickCount(); // If there were collisions, process them by sending the event to the prim. // Collisions must be processed before updates. if (collidersCount > 0) { for (int ii = 0; ii < collidersCount; ii++) { uint cA = m_collisionArray[ii].aID; uint cB = m_collisionArray[ii].bID; Vector3 point = m_collisionArray[ii].point; Vector3 normal = m_collisionArray[ii].normal; SendCollision(cA, cB, point, normal, 0.01f); SendCollision(cB, cA, point, -normal, 0.01f); } } // The above SendCollision's batch up the collisions on the objects. // Now push the collisions into the simulator. if (ObjectsWithCollisions.Count > 0) { foreach (BSPhysObject bsp in ObjectsWithCollisions) { if (!bsp.SendCollisions()) { // If the object is done colliding, see that it's removed from the colliding list ObjectsWithNoMoreCollisions.Add(bsp); } } } // This is a kludge to get avatar movement updates. // The simulator expects collisions for avatars even if there are have been no collisions. // The event updates avatar animations and stuff. // If you fix avatar animation updates, remove this overhead and let normal collision processing happen. foreach (BSPhysObject bsp in m_avatars) { if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice { bsp.SendCollisions(); } } // Objects that are done colliding are removed from the ObjectsWithCollisions list. // Not done above because it is inside an iteration of ObjectWithCollisions. // This complex collision processing is required to create an empty collision // event call after all real collisions have happened on an object. This enables // the simulator to generate the 'collision end' event. if (ObjectsWithNoMoreCollisions.Count > 0) { foreach (BSPhysObject po in ObjectsWithNoMoreCollisions) { ObjectsWithCollisions.Remove(po); } ObjectsWithNoMoreCollisions.Clear(); } // Done with collisions. // If any of the objects had updated properties, tell the object it has been changed by the physics engine if (updatedEntityCount > 0) { for (int ii = 0; ii < updatedEntityCount; ii++) { EntityProperties entprop = m_updateArray[ii]; BSPhysObject pobj; if (PhysObjects.TryGetValue(entprop.ID, out pobj)) { pobj.UpdateProperties(entprop); } } } TriggerPostStepEvent(timeStep); // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. // Only enable this in a limited test world with few objects. if (m_physicsPhysicalDumpEnabled) { PE.DumpAllInfo(World); } // The physics engine returns the number of milliseconds it simulated this call. // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. // Multiply by a fixed nominal frame rate to give a rate similar to the simulator (usually 55). return((float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate); }