BulletSim: tweeking avatar capsule code in an attempt to have

asymmetrical avatar capsule work now that rotation is being passed
from the simulator. Turns out the Bullet capsule is just not very
functional: it doesn't scale properly, the implementation only half
does asymmetry and, in general, is hard to work with.
Avatar shape is about what it was before these changes.
Added initial data structures for avatar shape mesh.
0.7.5-pf-bulletsim
Robert Adams 2012-12-29 08:03:57 -08:00
parent 976023366f
commit db6c0363f0
4 changed files with 81 additions and 46 deletions

View File

@ -66,7 +66,6 @@ public sealed class BSCharacter : BSPhysObject
private float _buoyancy;
// The friction and velocity of the avatar is modified depending on whether walking or not.
private OMV.Vector3 _appliedVelocity; // the last velocity applied to the avatar
private float _currentFriction; // the friction currently being used (changed by setVelocity).
private BSVMotor _velocityMotor;
@ -85,27 +84,27 @@ public sealed class BSCharacter : BSPhysObject
_physicsActorType = (int)ActorTypes.Agent;
_position = pos;
_flying = isFlying;
_orientation = OMV.Quaternion.Identity;
_velocity = OMV.Vector3.Zero;
_buoyancy = ComputeBuoyancyFromFlying(isFlying);
_currentFriction = BSParam.AvatarStandingFriction;
_avatarDensity = BSParam.AvatarDensity;
// Old versions of ScenePresence passed only the height. If width and/or depth are zero,
// replace with the default values.
_size = size;
if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth;
if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth;
SetupMovementMotor();
_flying = isFlying;
_orientation = OMV.Quaternion.Identity;
_velocity = OMV.Vector3.Zero;
_appliedVelocity = OMV.Vector3.Zero;
_buoyancy = ComputeBuoyancyFromFlying(isFlying);
_currentFriction = BSParam.AvatarStandingFriction;
_avatarDensity = BSParam.AvatarDensity;
// The dimensions of the avatar capsule are kept in the scale.
// The dimensions of the physical capsule are kept in the scale.
// Physics creates a unit capsule which is scaled by the physics engine.
ComputeAvatarScale(_size);
Scale = ComputeAvatarScale(_size);
// set _avatarVolume and _mass based on capsule size, _density and Scale
ComputeAvatarVolumeAndMass();
SetupMovementMotor();
DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
@ -217,9 +216,21 @@ public sealed class BSCharacter : BSPhysObject
// 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force.
OMV.Vector3 moveForce = (stepVelocity - _velocity) * Mass / PhysicsScene.LastTimeStep;
DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}",
LocalID, stepVelocity, _velocity, Mass, moveForce);
AddForce(moveForce, false, true);
// If moveForce is very small, zero things so we don't keep sending microscopic updates to the user
float moveForceMagnitudeSquared = moveForce.LengthSquared();
if (moveForceMagnitudeSquared < 0.0001)
{
DetailLog("{0},BSCharacter.MoveMotor,zeroMovement,stepVel={1},vel={2},mass={3},magSq={4},moveForce={5}",
LocalID, stepVelocity, _velocity, Mass, moveForceMagnitudeSquared, moveForce);
ForceVelocity = OMV.Vector3.Zero;
}
else
{
DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}",
LocalID, stepVelocity, _velocity, Mass, moveForce);
AddForce(moveForce, false, true);
}
});
}
@ -238,14 +249,13 @@ public sealed class BSCharacter : BSPhysObject
}
set {
// When an avatar's size is set, only the height is changed.
_size = value;
// Old versions of ScenePresence passed only the height. If width and/or depth are zero,
// replace with the default values.
if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth;
if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth;
ComputeAvatarScale(_size);
Scale = ComputeAvatarScale(_size);
ComputeAvatarVolumeAndMass();
DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}",
LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
@ -521,8 +531,6 @@ public sealed class BSCharacter : BSPhysObject
BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction);
}
}
// Remember the set velocity so we can suppress the reduction by friction, ...
_appliedVelocity = value;
BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
BulletSimAPI.Activate2(PhysBody.ptr, true);
@ -554,11 +562,7 @@ public sealed class BSCharacter : BSPhysObject
// m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation);
PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate()
{
if (PhysBody.HasPhysicalBody)
{
// _position = BulletSimAPI.GetPosition2(BSBody.ptr);
BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
}
ForceOrientation = _orientation;
});
}
}
@ -573,7 +577,11 @@ public sealed class BSCharacter : BSPhysObject
set
{
_orientation = value;
BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
if (PhysBody.HasPhysicalBody)
{
// _position = BulletSimAPI.GetPosition2(BSBody.ptr);
BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
}
}
}
public override int PhysicsActorType {
@ -716,7 +724,7 @@ public sealed class BSCharacter : BSPhysObject
}
OMV.Vector3 addForce = force;
DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce);
// DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce);
PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate()
{
@ -740,21 +748,31 @@ public sealed class BSCharacter : BSPhysObject
public override void SetMomentum(OMV.Vector3 momentum) {
}
private void ComputeAvatarScale(OMV.Vector3 size)
private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size)
{
OMV.Vector3 newScale = size;
// newScale.X = PhysicsScene.Params.avatarCapsuleWidth;
// newScale.Y = PhysicsScene.Params.avatarCapsuleDepth;
OMV.Vector3 newScale;
// Bullet's capsule total height is the "passed height + radius * 2";
// The base capsule is 1 diameter and 2 height (passed radius=0.5, passed height = 1)
// The number we pass in for 'scaling' is the multiplier to get that base
// shape to be the size desired.
// So, when creating the scale for the avatar height, we take the passed height
// (size.Z) and remove the caps.
// Another oddity of the Bullet capsule implementation is that it presumes the Y
// dimension is the radius of the capsule. Even though some of the code allows
// for a asymmetrical capsule, other parts of the code presume it is cylindrical.
// From the total height, remove the capsule half spheres that are at each end
// The 1.15f came from ODE. Not sure what this factors in.
// newScale.Z = (size.Z * 1.15f) - (newScale.X + newScale.Y);
// Scale is multiplier of radius with one of "0.5"
newScale.X = size.X / 2f;
newScale.Y = size.Y / 2f;
// The total scale height is the central cylindar plus the caps on the two ends.
newScale.Z = size.Z + (Math.Min(size.X, size.Y) * 2f);
newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2)) / 2f;
// If smaller than the endcaps, just fake like we're almost that small
if (newScale.Z < 0)
newScale.Z = 0.1f;
// Convert diameters to radii and height to half height -- the way Bullet expects it.
Scale = newScale / 2f;
return newScale;
}
// set _avatarVolume and _mass based on capsule size, _density and Scale
@ -762,14 +780,14 @@ public sealed class BSCharacter : BSPhysObject
{
_avatarVolume = (float)(
Math.PI
* Scale.X
* Scale.Y // the area of capsule cylinder
* Scale.Z // times height of capsule cylinder
* Size.X / 2f
* Size.Y / 2f // the area of capsule cylinder
* Size.Z // times height of capsule cylinder
+ 1.33333333f
* Math.PI
* Scale.X
* Math.Min(Scale.X, Scale.Y)
* Scale.Y // plus the volume of the capsule end caps
* Size.X / 2f
* Math.Min(Size.X, Size.Y) / 2
* Size.Y / 2f // plus the volume of the capsule end caps
);
_mass = _avatarDensity * _avatarVolume;
}

View File

@ -420,8 +420,7 @@ public sealed class BSShapeCollection : IDisposable
if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE)
{
// an avatar capsule is close to a native shape (it is not shared)
GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE,
FixedShapeKey.KEY_CAPSULE, shapeCallback);
GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE, shapeCallback);
if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape);
ret = true;
haveShape = true;
@ -573,6 +572,9 @@ public sealed class BSShapeCollection : IDisposable
{
// The proper scale has been calculated in the prim.
newShape = new BulletShape(
// Bullet's capsule total height is the passed "height + (radius * 2)" so, the base
// capsule is radius of 0.5f (1 diameter) and height of two (1.0f + 0.5f * 2)".
// This must be taken into account when computing the scaling of the capsule.
BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale)
, shapeType);
if (DDetail) DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);

View File

@ -205,4 +205,17 @@ public class BSShapeCompound : BSShape
}
public override void Dereference(BSScene physicsScene) { }
}
public class BSShapeAvatar : BSShape
{
private static string LogHeader = "[BULLETSIM SHAPE AVATAR]";
public BSShapeAvatar() : base()
{
}
public static BSShape GetReference(BSPhysObject prim)
{
return new BSShapeNull();
}
public override void Dereference(BSScene physicsScene) { }
}
}

View File

@ -69,6 +69,7 @@ public enum BSPhysicsShapeType
SHAPE_TERRAIN = 21,
SHAPE_COMPOUND = 22,
SHAPE_HEIGHTMAP = 23,
SHAPE_AVATAR = 24,
};
// The native shapes have predefined shape hash keys
@ -79,7 +80,8 @@ public enum FixedShapeKey : ulong
KEY_SPHERE = 2,
KEY_CONE = 3,
KEY_CYLINDER = 4,
KEY_CAPSULE = 5,
KEY_CAPSULE = 5,
KEY_AVATAR = 6,
}
[StructLayout(LayoutKind.Sequential)]