예제 #1
0
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);
                    }
                }
            }
        }
    }
}
예제 #2
0
//
// 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;
		}
	}
}
예제 #3
0
//
// 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;
		}
	}

}