void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents) { bool playedCollisionSound { false }; for (Collision collision : collisionEvents) { // TODO: The plan is to handle MOTIONSTATE_TYPE_AVATAR, and then MOTIONSTATE_TYPE_MYAVATAR. As it is, other // people's avatars will have an id that doesn't match any entities, and one's own avatar will have // an id of null. Thus this code handles any collision in which one of the participating objects is // my avatar. (Other user machines will make a similar analysis and inject sound for their collisions.) if (collision.idA.isNull() || collision.idB.isNull()) { auto myAvatar = getMyAvatar(); myAvatar->collisionWithEntity(collision); if (!playedCollisionSound) { playedCollisionSound = true; auto collisionSound = myAvatar->getCollisionSound(); if (collisionSound) { const auto characterController = myAvatar->getCharacterController(); const float avatarVelocityChange = (characterController ? glm::length(characterController->getVelocityChange()) : 0.0f); const float velocityChange = glm::length(collision.velocityChange) + avatarVelocityChange; const float MIN_AVATAR_COLLISION_ACCELERATION = 2.4f; // walking speed const bool isSound = (collision.type == CONTACT_EVENT_TYPE_START) && (velocityChange > MIN_AVATAR_COLLISION_ACCELERATION); if (!isSound) { return; // No sense iterating for others. We only have one avatar. } // Your avatar sound is personal to you, so let's say the "mass" part of the kinetic energy is already accounted for. const float energy = velocityChange * velocityChange; const float COLLISION_ENERGY_AT_FULL_VOLUME = 10.0f; const float energyFactorOfFull = fmin(1.0f, energy / COLLISION_ENERGY_AT_FULL_VOLUME); // For general entity collisionSoundURL, playSound supports changing the pitch for the sound based on the size of the object, // but most avatars are roughly the same size, so let's not be so fancy yet. const float AVATAR_STRETCH_FACTOR = 1.0f; _collisionInjectors.remove_if([](const AudioInjectorPointer& injector) { return !injector; }); static const int MAX_INJECTOR_COUNT = 3; if (_collisionInjectors.size() < MAX_INJECTOR_COUNT) { AudioInjectorOptions options; options.stereo = collisionSound->isStereo(); options.position = myAvatar->getWorldPosition(); options.volume = energyFactorOfFull; options.pitch = 1.0f / AVATAR_STRETCH_FACTOR; auto injector = DependencyManager::get<AudioInjectorManager>()->playSound(collisionSound, options, true); _collisionInjectors.emplace_back(injector); } } } } } }
// // This method is a modified version of the FluidSimulator2d::updateVelocity // method to reflect sand behavior // void SandSimulator2d::updateVelocity( float dt ) { //FluidSimulator2d::updateVelocity(dt); //return; // store the velocity in the oldVelocity member of each cell so that we later can compute the change in velocity -------- for( stdext::hash_map<Cell::Coordinate, Cell, hash_compare>::iterator it = gridCells.begin(); it != gridCells.end(); ++it ) (*it).second.oldVelocity = (*it).second.velocity; // if advection is not done through particles (PIC/FLIP) if( !particleBasedAdvection ) // then we use a sem-lagrange method to advect velocities... advectGridVelocities( dt ); // apply external forces ---------------------------------- applyGravity( dt, 0.0f, -9.1f ); // apply viscosity ---------------------------------------- solveViscosity( dt ); // extrapolate velocities into surrounding buffer cells ------ extrapolateVelocities(); // set Boundary conditions ------- setBoundaryConditions(); // solve for pressure and make the velocity grid divergence free ---- solvePressure( dt ); // extrapolate velocity into buffer cells second time ----------------- extrapolateVelocities(); // set solid cell velocities ------------------------------ setBoundaryConditions(); // sand applySandModel( dt ); // extrapolate velocity into buffer cells second time ----------------- //extrapolateVelocities(); // set solid cell velocities ------------------------------ //setBoundaryConditions(); // compute the change in velocity using the oldVelocity member which we have stored at the beginning of this procedure ---------- for( stdext::hash_map<Cell::Coordinate, Cell, hash_compare>::iterator it = gridCells.begin(); it != gridCells.end(); ++it ) { (*it).second.velocityChange.x = (*it).second.velocity.x - (*it).second.oldVelocity.x; (*it).second.velocityChange.y = (*it).second.velocity.y - (*it).second.oldVelocity.y; } // if advection is not done through particles (PIC/FLIP) if( particleBasedAdvection ) { // update the velocities of the particles from the grid -------------------------------------- for( std::vector<Particle2d>::iterator it=markerParticles.begin(); it != markerParticles.end(); ++it ) { // the solution of PIC and FLIP are blended together according to a specified blendweight // FLIP math::Vec2f flipVelocity = (*it).velocity + getVelocityChange( (*it).position.x, (*it).position.y ); // PIC math::Vec2f picVelocity = getVelocity( (*it).position.x, (*it).position.y ); // FINAL (*it).velocity = PICFLIPWeight*flipVelocity + (1.0f - PICFLIPWeight)*picVelocity; } } }
// // This method is a modified version of the FluidSimulator2d::updateVelocity // method to reflect viscoelastic behavior // void ViscoElasticFluid2d::updateVelocity( float dt ) { //FluidSimulator2d::updateVelocity(dt); //return; // store the velocity in the oldVelocity member of each cell so that we later can compute the change in velocity -------- for( stdext::hash_map<Cell::Coordinate, Cell, hash_compare>::iterator it = gridCells.begin(); it != gridCells.end(); ++it ) (*it).second.oldVelocity = (*it).second.velocity; // update total strain for each fluid cell ------------------------------------------------------------------------------ // calculate T and accumulate new strain in E for( stdext::hash_map<Cell::Coordinate, Cell, hash_compare>::iterator it = gridCells.begin(); it != gridCells.end(); ++it ) { Cell *cell = &(*it).second; if( cell->type != Cell::Fluid ) continue; // first term T math::Matrix22f D = computeStrainRateTensor( cell ); cell->strainTensor += dt*D; // second term -kyr*... float norm = math::frobeniusNorm( cell->strainTensor ); math::Matrix22f plasticYielding = math::Matrix22f::Zero(); if( norm ) plasticYielding = plasticYieldRate*std::max<float>( 0, norm - elasticYieldPoint )*cell->strainTensor*(1.0f / norm); cell->strainTensor -= dt*plasticYielding; } // advect elastic strain tensor E ------------------------------------------------------------------------------- for( stdext::hash_map<Cell::Coordinate, Cell, hash_compare>::iterator it = gridCells.begin(); it != gridCells.end(); ++it ) // clear temp variable for the intermediate result (*it).second.temp = math::Matrix22f::Zero(); // now advect the tensor components for each fluid-cell for( stdext::hash_map<Cell::Coordinate, Cell, hash_compare>::iterator it = gridCells.begin(); it != gridCells.end(); ++it ) { Cell *cell = &(*it).second; float e11, e22, e12; e11 = cell->strainTensor.m[0][0]; e22 = cell->strainTensor.m[1][1]; e12 = cell->strainTensor.m[0][1]; if(cell->type == Cell::Fluid) { // track strain tensor components which lie at the cell center -> E[1][1] && E[2][2] math::Vec2f centerPos = traceParticle( math::Vec2f( (*it).first.i * cellSize+(cellSize/2.0f), (*it).first.j * cellSize+(cellSize/2.0f) ), dt ); e11 = getInterpolatedStrainTensorComponent( centerPos.x/cellSize - 0.5f, centerPos.y/cellSize - 0.5f, 0, 0 ); e22 = getInterpolatedStrainTensorComponent( centerPos.x/cellSize - 0.5f, centerPos.y/cellSize - 0.5f, 1, 1 ); } if( cell->xNeighboursFluid || cell->yNeighboursFluid ) { // track strain tensor components which lie at the cell edges -> E[1][2] math::Vec2f offPos = traceParticle( math::Vec2f( (*it).first.i * cellSize, (*it).first.j * cellSize ), dt ); e12 = getInterpolatedStrainTensorComponent( offPos.x/cellSize, offPos.y/cellSize, 0, 1 ); } cell->temp.m[0][0] = e11; cell->temp.m[1][1] = e22; cell->temp.m[0][1] = e12; cell->temp.m[1][0] = e12; } // copy the intermediate results to the final values for( stdext::hash_map<Cell::Coordinate, Cell, hash_compare>::iterator it = gridCells.begin(); it != gridCells.end(); ++it ) { if( (*it).second.type == Cell::Fluid ) (*it).second.strainTensor = (*it).second.temp; else (*it).second.strainTensor = (*it).second.temp; } // extrapolate elastic strain into air extrapolateStrain(); // advect velocities (if advection is not done through particles (PIC/FLIP) ) -------------------------------- if( !particleBasedAdvection ) // then we use a sem-lagrange method to advect velocities... advectGridVelocities( dt ); // apply external forces ------------------------------------------------------------------------------------ applyGravity( dt, 0.0f, -9.1f ); /* // stretch test for( stdext::hash_map<Cell::Coordinate, Cell, hash_compare>::iterator it = gridCells.begin(); it != gridCells.end(); ++it ) { Cell *cell = &it->second; // we have to advance velocity-components of all cells which border fluid cells if( cell->xNeighboursFluid ) { if( cell->center.x > 0.6f ) { cell->velocity.x += 10.0f*dt; //cell->velocity.y += 0.0f; }else if( cell->center.x < 0.4f ) { cell->velocity.x += -10.0f*dt; //cell->velocity.y += 0.0f; } } } */ // apply elastic strain force to u ----------------------------------------------------------------------------- for( stdext::hash_map<Cell::Coordinate, Cell, hash_compare>::iterator it = gridCells.begin(); it != gridCells.end(); ++it ) { Cell *cell = &(*it).second; cell->vonMisesEquivalentStress = 0.0f; if( cell->xNeighboursFluid || cell->yNeighboursFluid ) { math::Vec2f f = elasticModulus*computeDivE( cell ); if( cell->xNeighboursFluid ) cell->velocity.x += dt*f.x; if( cell->yNeighboursFluid ) cell->velocity.y += dt*f.y; // compute equivalent stress cell->stressTensor = -elasticModulus*cell->strainTensor; cell->vonMisesEquivalentStress = sqrt( 3.0f/2.0f ) * math::frobeniusNorm( cell->stressTensor ); } } // apply viscosity ---------------------------------------------------- solveViscosity( dt ); // extrapolate velocities into surrounding buffer cells --------------- extrapolateVelocities(); // set Boundary conditions -------------------------------------------- setBoundaryConditions(); // solve for pressure and make the velocity grid divergence free ------ solvePressure( dt ); // extrapolate velocity into buffer cells second time ----------------- extrapolateVelocities(); // set solid cell velocities ------------------------------------------ setBoundaryConditions(); // compute the change in velocity using the oldVelocity member which we have stored at the beginning of this procedure ---------- for( stdext::hash_map<Cell::Coordinate, Cell, hash_compare>::iterator it = gridCells.begin(); it != gridCells.end(); ++it ) { (*it).second.velocityChange.x = (*it).second.velocity.x - (*it).second.oldVelocity.x; (*it).second.velocityChange.y = (*it).second.velocity.y - (*it).second.oldVelocity.y; } // if advection is not done through particles (PIC/FLIP) if( particleBasedAdvection ) { // update the velocities of the particles from the grid -------------------------------------- for( std::vector<Particle2d>::iterator it=markerParticles.begin(); it != markerParticles.end(); ++it ) { // the solution of PIC and FLIP are blended together according to a specified blendweight // FLIP math::Vec2f flipVelocity = (*it).velocity + getVelocityChange( (*it).position.x, (*it).position.y ); // PIC math::Vec2f picVelocity = getVelocity( (*it).position.x, (*it).position.y ); // FINAL (*it).velocity = PICFLIPWeight*flipVelocity + (1.0f - PICFLIPWeight)*picVelocity; } } }