public void TickPhysicsInfluence( bool allowSplashes )
{
if( volumeBody == null )
return;
EngineRandom random = World.Instance.Random;
List<SubmergedCheckItem> submergedItems = listSubmergedCheckItemAllocator.Alloc();
Vec2 halfSize = Size * .5f;
Bounds volumeBounds = new Bounds(
new Vec3( Position.X - halfSize.X, Position.Y - halfSize.Y, Position.Z - physicsHeight ),
new Vec3( Position.X + halfSize.X, Position.Y + halfSize.Y, Position.Z ) );
Body[] bodies = PhysicsWorld.Instance.VolumeCast( volumeBounds,
(int)ContactGroup.CastOnlyDynamic );
foreach( Body body in bodies )
{
if( body.Static )
continue;
Mat3 bodyRotation = body.Rotation.ToMat3();
foreach( Shape shape in body.Shapes )
{
if( shape.ContactGroup == (int)ContactGroup.NoContact )
continue;
Vec3 shapePosition = body.Position + bodyRotation * shape.Position;
float volume = shape.Volume;
switch( shape.ShapeType )
{
case Shape.Type.Box:
{
BoxShape boxShape = (BoxShape)shape;
Quat shapeRotation = body.Rotation;
if( !shape.IsIdentityTransform )
shapeRotation *= shape.Rotation;
Vec3 halfD = boxShape.Dimensions * .5f;
float r = Math.Min( Math.Min( halfD.X, halfD.Y ), halfD.Z );
Vec3i stepsCount = new Vec3i( 1, 1, 1 );
if( halfD.X > r * .3f )
stepsCount.X = 2;
if( halfD.Y > r * .3f )
stepsCount.Y = 2;
if( halfD.Z > r * .3f )
stepsCount.Z = 2;
for( int z = 0; z < stepsCount.Z; z++ )
{
for( int y = 0; y < stepsCount.Y; y++ )
{
for( int x = 0; x < stepsCount.X; x++ )
{
Vec3 localPos = Vec3.Zero;
if( stepsCount.X == 2 )
localPos.X = ( x == 0 ) ? ( -halfD.X + r ) : ( halfD.X - r );
if( stepsCount.Y == 2 )
localPos.Y = ( y == 0 ) ? ( -halfD.Y + r ) : ( halfD.Y - r );
if( stepsCount.X == 2 )
localPos.Z = ( z == 0 ) ? ( -halfD.Z + r ) : ( halfD.Z - r );
Vec3 pos = shapePosition + shapeRotation * localPos;
submergedItems.Add( GetSphereSubmergedCoef( new Sphere( pos, r ) ) );
}
}
}
}
break;
case Shape.Type.Capsule:
{
CapsuleShape capsuleShape = (CapsuleShape)shape;
float r = capsuleShape.Radius;
float l = capsuleShape.Length;
Quat shapeRotation = body.Rotation;
if( !shape.IsIdentityTransform )
shapeRotation *= shape.Rotation;
Vec3 pos;
pos = shapePosition + shapeRotation * new Vec3( 0, 0, -l * .5f );
submergedItems.Add( GetSphereSubmergedCoef( new Sphere( pos, r ) ) );
pos = shapePosition + shapeRotation * new Vec3( 0, 0, l * .5f );
submergedItems.Add( GetSphereSubmergedCoef( new Sphere( pos, r ) ) );
}
break;
case Shape.Type.Sphere:
{
SphereShape sphereShape = (SphereShape)shape;
float r = sphereShape.Radius;
submergedItems.Add( GetSphereSubmergedCoef( new Sphere( shapePosition, r ) ) );
}
break;
case Shape.Type.Mesh:
{
MeshShape meshShape = (MeshShape)shape;
Bounds b;
if( meshShape.GetDataBounds( out b ) )
{
float r = b.GetRadius();
submergedItems.Add( GetSphereSubmergedCoef( new Sphere( shapePosition,
r ) ) );
}
}
break;
}
if( submergedItems.Count == 0 )
continue;
//calculate summary submerged coefficient and force center
float submergedCoef;
Vec3 submergedCenter;
{
if( submergedItems.Count != 1 )
{
submergedCoef = 0;
submergedCenter = Vec3.Zero;
float len = 0;
foreach( SubmergedCheckItem item in submergedItems )
len += item.coef;
if( len != 0 )
{
float invLen = 1.0f / len;
foreach( SubmergedCheckItem item in submergedItems )
{
submergedCoef += item.coef;
submergedCenter += item.center * ( item.coef * invLen );
}
submergedCoef /= (float)submergedItems.Count;
}
}
else
{
submergedCoef = submergedItems[ 0 ].coef;
submergedCenter = submergedItems[ 0 ].center;
}
}
//create splashes
if( allowSplashes && submergedItems.Count != 0 )
{
const float minimalBodyVelocity = 3;
const float minimalTimeBetweenSplashes = .25f;
float length = body.LinearVelocity.LengthFast();
if( length > minimalBodyVelocity )
{
int index = bodiesSplashOffTime.FindIndex( delegate( SplashOffItem item )
{
return item.body == body;
} );
if( index == -1 )
{
bool created = false;
Vec3 splashPosition = Vec3.Zero;
foreach( SubmergedCheckItem item in submergedItems )
{
if( item.coef > 0 && item.coef < 1 )
{
Vec3 pos = new Vec3( item.center.X, item.center.Y, Position.Z );
//no create splashes too much nearly
if( created && ( pos - splashPosition ).LengthFast() < .1f )
continue;
//create splash
splashPosition = pos;
CreateSplash( WaterPlaneType.SplashTypes.Body, splashPosition );
created = true;
}
}
if( created )
{
SplashOffItem item;
item.body = body;
item.remainingTime = minimalTimeBetweenSplashes;
bodiesSplashOffTime.Add( item );
}
}
}
}
submergedItems.Clear();
if( submergedCoef == 0 )
continue;
//add forces
float shapeDensity = GetShapeInfluenceDensity( shape );
if( shapeDensity == 0 )
continue;
float densityCoef = Type.PhysicsDensity / shapeDensity;
float mass = volume * shape.Density;
//buoyancy force
{
const float roughnessLinearCoef = .5f;
float coef = densityCoef * submergedCoef;
coef += random.NextFloatCenter() * roughnessLinearCoef;
Vec3 vector = -PhysicsWorld.Instance.Gravity * ( mass * coef );
body.AddForce( ForceType.GlobalAtGlobalPos, TickDelta, vector, submergedCenter );
}
//linear damping
{
float constCoef = 2;
float coef = submergedCoef * constCoef * densityCoef;
Vec3 vector = -body.LinearVelocity * mass * coef;
body.AddForce( ForceType.GlobalAtGlobalPos, TickDelta, vector, submergedCenter );
}
//angular damping
{
const float constCoef = .5f;
const float roughnessAngularCoef = .25f;
float coef = submergedCoef * constCoef;
Vec3 vector = -body.AngularVelocity * mass * coef;
float roughnessX = random.NextFloatCenter() * roughnessAngularCoef;
float roughnessY = random.NextFloatCenter() * roughnessAngularCoef;
float roughnessZ = random.NextFloatCenter() * roughnessAngularCoef;
vector += new Vec3( roughnessX, roughnessY, roughnessZ );
body.AddForce( ForceType.GlobalTorque, TickDelta, vector, Vec3.Zero );
}
}
}
listSubmergedCheckItemAllocator.Free( submergedItems );
}