///<summary> /// Forces an update of the pair's material properties. ///</summary> ///<param name="a">Material of the first member of the pair.</param> ///<param name="b">Material of the second member of the pair.</param> public override void UpdateMaterialProperties(Material a, Material b) { foreach (var pairHandler in subPairs.Values) { pairHandler.UpdateMaterialProperties(a, b); } }
internal CompoundChild(CompoundShape shape, EntityCollidable collisionInformation, Material material, int index) { this.shape = shape; this.collisionInformation = collisionInformation; Material = material; this.shapeIndex = index; }
protected virtual void OnMaterialChanged(Material newMaterial) { for (int i = 0; i < pairs.Count; i++) { pairs[i].UpdateMaterialProperties(); } }
///<summary> /// Computes the interaction properties between two materials. ///</summary> ///<param name="materialA">First material of the pair.</param> ///<param name="materialB">Second material of the pair.</param> ///<param name="properties">Interaction properties between two materials.</param> public static void GetInteractionProperties(Material materialA, Material materialB, out InteractionProperties properties) { MaterialBlender specialBlender; if (MaterialInteractions.TryGetValue(new MaterialPair(materialA, materialB), out specialBlender)) specialBlender(materialA, materialB, out properties); else MaterialBlender(materialA, materialB, out properties); }
/// <summary> /// Blender used to combine materials into a pair's interaction properties. /// </summary> /// <param name="a">Material associated with the first object to blend.</param> /// <param name="b">Material associated with the second object to blend.</param> /// <param name="properties">Blended material values.</param> public static void DefaultMaterialBlender(Material a, Material b, out InteractionProperties properties) { properties = new InteractionProperties { Bounciness = a.bounciness * b.bounciness, KineticFriction = a.kineticFriction * b.kineticFriction, StaticFriction = a.staticFriction * b.staticFriction }; }
///<summary> /// Constructs a new static mesh. ///</summary> ///<param name="vertices">Vertex positions of the mesh.</param> ///<param name="indices">Index list of the mesh.</param> public StaticMesh(Vector3[] vertices, int[] indices) { base.Shape = new StaticMeshShape(vertices, indices); collisionRules.group = CollisionRules.DefaultKinematicCollisionGroup; events = new ContactEventManager<StaticMesh>(this); material = new Material(); materialChangedDelegate = OnMaterialChanged; material.MaterialChanged += materialChangedDelegate; }
///<summary> /// Performs common initialization. ///</summary> protected StaticCollidable() { collisionRules.group = CollisionRules.DefaultKinematicCollisionGroup; //Note that the Events manager is not created here. That is left for subclasses to implement so that the type is more specific. //Entities can get away with having EntityCollidable specificity since you generally care more about the entity than the collidable, //but with static objects, the collidable is the only important object. It would be annoying to cast to the type you know it is every time //just to get access to some type-specific properties. material = new Material(); materialChangedDelegate = OnMaterialChanged; material.MaterialChanged += materialChangedDelegate; }
///<summary> /// Computes the interaction properties between two materials. ///</summary> ///<param name="materialA">First material of the pair.</param> ///<param name="materialB">Second material of the pair.</param> ///<param name="properties">Interaction properties between two materials.</param> public static void GetInteractionProperties(Material materialA, Material materialB, out InteractionProperties properties) { if (MaterialInteractions.TryGetValue(new MaterialPair(materialA, materialB), out properties)) { return; } properties = new InteractionProperties(); properties.StaticFriction = FrictionBlender(materialA.staticFriction, materialB.staticFriction, null); properties.KineticFriction = FrictionBlender(materialA.kineticFriction, materialB.kineticFriction, null); properties.Bounciness = BouncinessBlender(materialA.bounciness, materialB.bounciness, null); }
///<summary> /// Constructs a new InstancedMesh. ///</summary> ///<param name="meshShape">Shape to use for the instance.</param> ///<param name="worldTransform">Transform to use for the instance.</param> public InstancedMesh(InstancedMeshShape meshShape, AffineTransform worldTransform) { this.worldTransform = worldTransform; base.Shape = meshShape; collisionRules.group = CollisionRules.DefaultKinematicCollisionGroup; events = new ContactEventManager<InstancedMesh>(this); material = new Material(); materialChangedDelegate = OnMaterialChanged; material.MaterialChanged += materialChangedDelegate; }
///<summary> /// Blends the static friction of the two materials together. ///</summary> ///<param name="materialA">First material of the pair.</param> ///<param name="materialB">Second material of the pair.</param> ///<param name="blendedCoefficient">Blended friction coefficient.</param> public static void GetStaticFriction(Material materialA, Material materialB, out float blendedCoefficient) { InteractionProperties properties; if (materialA != null && materialB != null && MaterialInteractions.TryGetValue(new MaterialPair(materialA, materialB), out properties)) { blendedCoefficient = properties.StaticFriction; return; } blendedCoefficient = FrictionBlender(materialA.staticFriction, materialB.staticFriction, null); }
/// <summary> /// Finds a supporting entity, the contact location, and the contact normal. /// </summary> /// <param name="location">Contact point between the wheel and the support.</param> /// <param name="normal">Contact normal between the wheel and the support.</param> /// <param name="suspensionLength">Length of the suspension at the contact.</param> /// <param name="supportCollidable">Collidable supporting the wheel, if any.</param> /// <param name="entity">Entity supporting the wheel, if any.</param> /// <param name="material">Material of the support.</param> /// <returns>Whether or not any support was found.</returns> protected internal abstract bool FindSupport(out Vector3 location, out Vector3 normal, out float suspensionLength, out Collidable supportCollidable, out Entity entity, out Material material);
///<summary> /// Forces an update of the pair's material properties. ///</summary> public override void UpdateMaterialProperties(Material a, Material b) { ContactConstraint.UpdateMaterialProperties( a ?? (EntityA == null ? null : EntityA.material), b ?? (EntityB == null ? null : EntityB.material)); }
///<summary> /// Constructs a new Terrain. ///</summary> ///<param name="shape">Shape to use for the terrain.</param> ///<param name="worldTransform">Transform to use for the terrain.</param> public Terrain(TerrainShape shape, AffineTransform worldTransform) { this.worldTransform = worldTransform; Shape = shape; collisionRules.group = CollisionRules.DefaultKinematicCollisionGroup; material = new Material(); materialChangedDelegate = OnMaterialChanged; material.MaterialChanged += materialChangedDelegate; events = new ContactEventManager<Terrain>(this); }
/// <summary> /// Finds a supporting entity, the contact location, and the contact normal. /// </summary> /// <param name="location">Contact point between the wheel and the support.</param> /// <param name="normal">Contact normal between the wheel and the support.</param> /// <param name="suspensionLength">Length of the suspension at the contact.</param> /// <param name="supportingCollidable">Collidable supporting the wheel, if any.</param> /// <param name="entity">Supporting object.</param> /// <param name="material">Material of the wheel.</param> /// <returns>Whether or not any support was found.</returns> protected internal override bool FindSupport(out Vector3 location, out Vector3 normal, out float suspensionLength, out Collidable supportingCollidable, out Entity entity, out Material material) { suspensionLength = float.MaxValue; location = Toolbox.NoVector; supportingCollidable = null; entity = null; normal = Toolbox.NoVector; material = null; Collidable testCollidable; RayHit rayHit; bool hit = false; for (int i = 0; i < detector.CollisionInformation.pairs.Count; i++) { var pair = detector.CollisionInformation.pairs[i]; testCollidable = (pair.BroadPhaseOverlap.entryA == detector.CollisionInformation ? pair.BroadPhaseOverlap.entryB : pair.BroadPhaseOverlap.entryA) as Collidable; if (testCollidable != null) { if (CollisionRules.CollisionRuleCalculator(this, testCollidable) == CollisionRule.Normal && testCollidable.RayCast(new Ray(wheel.suspension.worldAttachmentPoint, wheel.suspension.worldDirection), wheel.suspension.restLength, out rayHit) && rayHit.T < suspensionLength) { suspensionLength = rayHit.T; EntityCollidable entityCollidable; if ((entityCollidable = testCollidable as EntityCollidable) != null) { entity = entityCollidable.Entity; material = entityCollidable.Entity.Material; } else { entity = null; supportingCollidable = testCollidable; var materialOwner = testCollidable as IMaterialOwner; if (materialOwner != null) material = materialOwner.Material; } location = rayHit.Location; normal = rayHit.Normal; hit = true; } } } if (hit) { if (suspensionLength > 0) normal.Normalize(); else Vector3.Negate(ref wheel.suspension.worldDirection, out normal); return true; } return false; }
protected void TryToAdd(Collidable a, Collidable b, Material materialA, Material materialB) { CollisionRule rule; if ((rule = CollisionRules.collisionRuleCalculator(a, b)) < CollisionRule.NoNarrowPhasePair) { //Clamp the rule to the parent's rule. Always use the more restrictive option. //Don't have to test for NoNarrowPhasePair rule on the parent's rule because then the parent wouldn't exist! if (rule < CollisionRule) rule = CollisionRule; var pair = new CollidablePair(a, b); if (!subPairs.ContainsKey(pair)) { var newPair = NarrowPhaseHelper.GetPairHandler(ref pair, rule); if (newPair != null) { newPair.UpdateMaterialProperties(materialA, materialB); //Override the materials, if necessary. newPair.Parent = this; subPairs.Add(pair, newPair); } } containedPairs.Add(pair); } }
protected void TryToAdd(Collidable a, Collidable b, Material materialA) { TryToAdd(a, b, materialA, null); }
///<summary> /// Forces an update of the pair's material properties. ///</summary> public override void UpdateMaterialProperties(Material a, Material b) { ContactConstraint.UpdateMaterialProperties( a == null ? EntityA == null ? null : EntityA.material : a, b == null ? EntityB == null ? null : EntityB.material : b); }
/// <summary> /// Finds a supporting entity, the contact location, and the contact normal. /// </summary> /// <param name="location">Contact point between the wheel and the support.</param> /// <param name="normal">Contact normal between the wheel and the support.</param> /// <param name="suspensionLength">Length of the suspension at the contact.</param> /// <param name="supportingCollidable">Collidable supporting the wheel, if any.</param> /// <param name="entity">Supporting object.</param> /// <param name="material">Material of the wheel.</param> /// <returns>Whether or not any support was found.</returns> protected internal override bool FindSupport(out Vector3 location, out Vector3 normal, out float suspensionLength, out Collidable supportingCollidable, out Entity entity, out Material material) { suspensionLength = float.MaxValue; location = Toolbox.NoVector; supportingCollidable = null; entity = null; normal = Toolbox.NoVector; material = null; Collidable testCollidable; RayHit rayHit; bool hit = false; Quaternion localSteeringTransform; Quaternion.CreateFromAxisAngle(ref wheel.suspension.localDirection, steeringAngle, out localSteeringTransform); var startingTransform = new RigidTransform { Position = wheel.suspension.worldAttachmentPoint, Orientation = Quaternion.Concatenate(Quaternion.Concatenate(LocalWheelOrientation, IncludeSteeringTransformInCast ? localSteeringTransform : Quaternion.Identity), wheel.vehicle.Body.orientation) }; Vector3 sweep; Vector3.Multiply(ref wheel.suspension.worldDirection, wheel.suspension.restLength, out sweep); for (int i = 0; i < detector.CollisionInformation.pairs.Count; i++) { var pair = detector.CollisionInformation.pairs[i]; testCollidable = (pair.BroadPhaseOverlap.entryA == detector.CollisionInformation ? pair.BroadPhaseOverlap.entryB : pair.BroadPhaseOverlap.entryA) as Collidable; if (testCollidable != null) { if (CollisionRules.CollisionRuleCalculator(this, testCollidable) == CollisionRule.Normal && testCollidable.ConvexCast(shape, ref startingTransform, ref sweep, out rayHit) && rayHit.T * wheel.suspension.restLength < suspensionLength) { suspensionLength = rayHit.T * wheel.suspension.restLength; EntityCollidable entityCollidable; if ((entityCollidable = testCollidable as EntityCollidable) != null) { entity = entityCollidable.Entity; material = entityCollidable.Entity.Material; } else { entity = null; supportingCollidable = testCollidable; var materialOwner = testCollidable as IMaterialOwner; if (materialOwner != null) material = materialOwner.Material; } location = rayHit.Location; normal = rayHit.Normal; hit = true; } } } if (hit) { if (suspensionLength > 0) { float dot; Vector3.Dot(ref normal, ref wheel.suspension.worldDirection, out dot); if (dot > 0) { //The cylinder cast produced a normal which is opposite of what we expect. Vector3.Negate(ref normal, out normal); } normal.Normalize(); } else Vector3.Negate(ref wheel.suspension.worldDirection, out normal); return true; } return false; }
protected Entity() { InitializeId(); BufferedStates = new EntityBufferedStates(this); material = new Material(); materialChangedDelegate = OnMaterialChanged; material.MaterialChanged += materialChangedDelegate; shapeChangedDelegate = OnShapeChanged; activityInformation = new SimulationIslandMember(this); }
void OnMaterialChanged(Material newMaterial) { for (int i = 0; i < collisionInformation.pairs.Count; i++) { collisionInformation.pairs[i].UpdateMaterialProperties(); } }
///<summary> /// Updates the material properties associated with the constraint. ///</summary> ///<param name="materialA">Material associated with the first entity of the pair.</param> ///<param name="materialB">Material associated with the second entity of the pair.</param> public void UpdateMaterialProperties(Material materialA, Material materialB) { if (materialA != null && materialB != null) MaterialManager.GetInteractionProperties(materialA, materialB, out materialInteraction); else if (materialA == null && materialB != null) { materialInteraction.KineticFriction = materialB.kineticFriction; materialInteraction.StaticFriction = materialB.staticFriction; materialInteraction.Bounciness = materialB.bounciness; } else if (materialA != null) { materialInteraction.KineticFriction = materialA.kineticFriction; materialInteraction.StaticFriction = materialA.staticFriction; materialInteraction.Bounciness = materialA.bounciness; } else { materialInteraction.KineticFriction = 0; materialInteraction.StaticFriction = 0; materialInteraction.Bounciness = 0; } }
///<summary> /// Forces an update of the pair's material properties. ///</summary> /// <param name="materialA">First material to use.</param> /// <param name="materialB">Second material to use.</param> public abstract void UpdateMaterialProperties(Material materialA, Material materialB);
///<summary> /// Blends the bounciness of the two materials together. ///</summary> ///<param name="materialA">First material of the pair.</param> ///<param name="materialB">Second material of the pair.</param> /// <param name="blender">Blender to use to blend the material properties.</param> ///<param name="blendedCoefficient">Blended bounciness coefficient.</param> public static void GetBounciness(Material materialA, Material materialB, PropertyBlender blender, out float blendedCoefficient) { InteractionProperties properties; if (materialA != null && materialB != null && MaterialInteractions.TryGetValue(new MaterialPair(materialA, materialB), out properties)) { blendedCoefficient = properties.Bounciness; return; } blendedCoefficient = blender(materialA.Bounciness, materialB.Bounciness, null); }