diff options
Diffstat (limited to 'OpenSim')
-rw-r--r-- | OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 65 | ||||
-rwxr-xr-x | OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt | 33 |
2 files changed, 66 insertions, 32 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index 912aadd..77ec76d 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | |||
@@ -91,6 +91,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
91 | private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body | 91 | private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body |
92 | 92 | ||
93 | //Deflection properties | 93 | //Deflection properties |
94 | private BSVMotor m_angularDeflectionMotor = new BSVMotor("AngularDeflection"); | ||
94 | private float m_angularDeflectionEfficiency = 0; | 95 | private float m_angularDeflectionEfficiency = 0; |
95 | private float m_angularDeflectionTimescale = 0; | 96 | private float m_angularDeflectionTimescale = 0; |
96 | private float m_linearDeflectionEfficiency = 0; | 97 | private float m_linearDeflectionEfficiency = 0; |
@@ -102,6 +103,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
102 | private float m_bankingTimescale = 0; | 103 | private float m_bankingTimescale = 0; |
103 | 104 | ||
104 | //Hover and Buoyancy properties | 105 | //Hover and Buoyancy properties |
106 | private BSVMotor m_hoverMotor = new BSVMotor("Hover"); | ||
105 | private float m_VhoverHeight = 0f; | 107 | private float m_VhoverHeight = 0f; |
106 | private float m_VhoverEfficiency = 0f; | 108 | private float m_VhoverEfficiency = 0f; |
107 | private float m_VhoverTimescale = 0f; | 109 | private float m_VhoverTimescale = 0f; |
@@ -118,6 +120,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
118 | // Timescale > cutoff means no vert attractor. | 120 | // Timescale > cutoff means no vert attractor. |
119 | private float m_verticalAttractionTimescale = 510f; | 121 | private float m_verticalAttractionTimescale = 510f; |
120 | 122 | ||
123 | // Just some recomputed constants: | ||
124 | static readonly float PIOverFour = ((float)Math.PI) / 4f; | ||
125 | static readonly float PIOverTwo = ((float)Math.PI) / 2f; | ||
126 | |||
121 | public BSDynamics(BSScene myScene, BSPrim myPrim) | 127 | public BSDynamics(BSScene myScene, BSPrim myPrim) |
122 | { | 128 | { |
123 | PhysicsScene = myScene; | 129 | PhysicsScene = myScene; |
@@ -563,9 +569,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
563 | // Vehicles report collision events so we know when it's on the ground | 569 | // Vehicles report collision events so we know when it's on the ground |
564 | BulletSimAPI.AddToCollisionFlags2(Prim.PhysBody.ptr, CollisionFlags.BS_VEHICLE_COLLISIONS); | 570 | BulletSimAPI.AddToCollisionFlags2(Prim.PhysBody.ptr, CollisionFlags.BS_VEHICLE_COLLISIONS); |
565 | 571 | ||
566 | // DEBUG DEBUG DEBUG: use uniform inertia to smooth movement added by Bullet | ||
567 | // Vector3 localInertia = new Vector3(1f, 1f, 1f); | ||
568 | // Vector3 localInertia = new Vector3(m_vehicleMass, m_vehicleMass, m_vehicleMass); | ||
569 | Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(Prim.PhysShape.ptr, m_vehicleMass); | 572 | Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(Prim.PhysShape.ptr, m_vehicleMass); |
570 | BulletSimAPI.SetMassProps2(Prim.PhysBody.ptr, m_vehicleMass, localInertia); | 573 | BulletSimAPI.SetMassProps2(Prim.PhysBody.ptr, m_vehicleMass, localInertia); |
571 | BulletSimAPI.UpdateInertiaTensor2(Prim.PhysBody.ptr); | 574 | BulletSimAPI.UpdateInertiaTensor2(Prim.PhysBody.ptr); |
@@ -613,7 +616,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
613 | private Quaternion? m_knownOrientation; | 616 | private Quaternion? m_knownOrientation; |
614 | private Vector3? m_knownRotationalVelocity; | 617 | private Vector3? m_knownRotationalVelocity; |
615 | private Vector3 m_knownRotationalForce; | 618 | private Vector3 m_knownRotationalForce; |
616 | private float? m_knownForwardSpeed; | 619 | private Vector3? m_knownForwardVelocity; // vehicle relative forward speed |
617 | 620 | ||
618 | private const int m_knownChangedPosition = 1 << 0; | 621 | private const int m_knownChangedPosition = 1 << 0; |
619 | private const int m_knownChangedVelocity = 1 << 1; | 622 | private const int m_knownChangedVelocity = 1 << 1; |
@@ -632,7 +635,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
632 | m_knownOrientation = null; | 635 | m_knownOrientation = null; |
633 | m_knownRotationalVelocity = null; | 636 | m_knownRotationalVelocity = null; |
634 | m_knownRotationalForce = Vector3.Zero; | 637 | m_knownRotationalForce = Vector3.Zero; |
635 | m_knownForwardSpeed = null; | 638 | m_knownForwardVelocity = null; |
636 | m_knownChanged = 0; | 639 | m_knownChanged = 0; |
637 | } | 640 | } |
638 | private void PushKnownChanged() | 641 | private void PushKnownChanged() |
@@ -755,13 +758,21 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
755 | m_knownRotationalForce += aForce; | 758 | m_knownRotationalForce += aForce; |
756 | m_knownChanged |= m_knownChangedRotationalForce; | 759 | m_knownChanged |= m_knownChangedRotationalForce; |
757 | } | 760 | } |
761 | // Vehicle relative forward velocity | ||
762 | private Vector3 VehicleForwardVelocity | ||
763 | { | ||
764 | get | ||
765 | { | ||
766 | if (m_knownForwardVelocity == null) | ||
767 | m_knownForwardVelocity = VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleOrientation)); | ||
768 | return (Vector3)m_knownForwardVelocity; | ||
769 | } | ||
770 | } | ||
758 | private float VehicleForwardSpeed | 771 | private float VehicleForwardSpeed |
759 | { | 772 | { |
760 | get | 773 | get |
761 | { | 774 | { |
762 | if (m_knownForwardSpeed == null) | 775 | return VehicleForwardVelocity.X; |
763 | m_knownForwardSpeed = (VehicleVelocity * Quaternion.Inverse(VehicleOrientation)).X; | ||
764 | return (float)m_knownForwardSpeed; | ||
765 | } | 776 | } |
766 | } | 777 | } |
767 | 778 | ||
@@ -1025,7 +1036,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1025 | // set directly on the vehicle. | 1036 | // set directly on the vehicle. |
1026 | private void MoveAngular(float pTimestep) | 1037 | private void MoveAngular(float pTimestep) |
1027 | { | 1038 | { |
1028 | // The user wants how many radians per second angular change? | 1039 | // The user wants this many radians per second angular change? |
1029 | Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep); | 1040 | Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep); |
1030 | 1041 | ||
1031 | // ================================================================== | 1042 | // ================================================================== |
@@ -1137,27 +1148,23 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1137 | // Y error means needed rotation around X axis and visa versa. | 1148 | // Y error means needed rotation around X axis and visa versa. |
1138 | // Since the error goes from zero to one, the asin is the corresponding angle. | 1149 | // Since the error goes from zero to one, the asin is the corresponding angle. |
1139 | ret.X = (float)Math.Asin(verticalError.Y); | 1150 | ret.X = (float)Math.Asin(verticalError.Y); |
1140 | ret.Y = (float)Math.Asin(verticalError.X); | 1151 | // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.) |
1152 | ret.Y = -(float)Math.Asin(verticalError.X); | ||
1141 | 1153 | ||
1142 | // If verticalError.Z is negative, the vehicle is upside down. Add additional push. | 1154 | // If verticalError.Z is negative, the vehicle is upside down. Add additional push. |
1143 | if (verticalError.Z < 0f) | 1155 | if (verticalError.Z < 0f) |
1144 | { | 1156 | { |
1145 | ret.X += (float)Math.PI / 4f; | 1157 | ret.X += PIOverFour; |
1146 | ret.Y += (float)Math.PI / 4f; | 1158 | ret.Y += PIOverFour; |
1147 | } | 1159 | } |
1148 | 1160 | ||
1149 | // Put the signs back on so the rotation is in the correct direction. | ||
1150 | ret.X *= (float)Math.Sign(verticalError.Y); | ||
1151 | // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.) | ||
1152 | ret.Y *= -(float)Math.Sign(verticalError.X); | ||
1153 | |||
1154 | // 'ret' is now the necessary velocity to correct tilt in one second. | 1161 | // 'ret' is now the necessary velocity to correct tilt in one second. |
1155 | // Correction happens over a number of seconds. | 1162 | // Correction happens over a number of seconds. |
1156 | Vector3 unscaledContrib = ret; | 1163 | Vector3 unscaledContrib = ret; |
1157 | ret /= m_verticalAttractionTimescale; | 1164 | ret /= m_verticalAttractionTimescale; |
1158 | 1165 | ||
1159 | VDetailLog("{0}, MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},eff={3},vertAttr={4}", | 1166 | VDetailLog("{0}, MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},eff={3},ts={4},vertAttr={5}", |
1160 | Prim.LocalID, verticalError, unscaledContrib, m_verticalAttractionEfficiency, ret); | 1167 | Prim.LocalID, verticalError, unscaledContrib, m_verticalAttractionEfficiency, m_verticalAttractionTimescale, ret); |
1161 | } | 1168 | } |
1162 | return ret; | 1169 | return ret; |
1163 | } | 1170 | } |
@@ -1170,6 +1177,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1170 | public Vector3 ComputeAngularDeflection() | 1177 | public Vector3 ComputeAngularDeflection() |
1171 | { | 1178 | { |
1172 | Vector3 ret = Vector3.Zero; | 1179 | Vector3 ret = Vector3.Zero; |
1180 | return ret; // DEBUG DEBUG DEBUG | ||
1181 | // Disable angular deflection for the moment. | ||
1182 | // Since angularMotorUp and angularDeflection are computed independently, they will calculate | ||
1183 | // approximately the same X or Y correction. When added together (when contributions are combined) | ||
1184 | // this creates an over-correction and then wabbling as the target is overshot. | ||
1185 | // TODO: rethink how the different correction computations inter-relate. | ||
1173 | 1186 | ||
1174 | if (m_angularDeflectionEfficiency != 0) | 1187 | if (m_angularDeflectionEfficiency != 0) |
1175 | { | 1188 | { |
@@ -1181,15 +1194,24 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1181 | Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation; | 1194 | Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation; |
1182 | pointingDirection.Normalize(); | 1195 | pointingDirection.Normalize(); |
1183 | 1196 | ||
1184 | // The difference between what is and what should be | 1197 | // The difference between what is and what should be. |
1185 | Vector3 deflectionError = movingDirection - pointingDirection; | 1198 | Vector3 deflectionError = movingDirection - pointingDirection; |
1186 | 1199 | ||
1200 | // Don't try to correct very large errors (not our job) | ||
1201 | if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = 0f; | ||
1202 | if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = 0f; | ||
1203 | if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = 0f; | ||
1204 | |||
1205 | // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError); | ||
1206 | |||
1187 | // Scale the correction by recovery timescale and efficiency | 1207 | // Scale the correction by recovery timescale and efficiency |
1188 | ret = (-deflectionError * VehicleForwardSpeed) * m_angularDeflectionEfficiency; | 1208 | ret = (-deflectionError) * m_angularDeflectionEfficiency; |
1189 | ret /= m_angularDeflectionTimescale; | 1209 | ret /= m_angularDeflectionTimescale; |
1190 | 1210 | ||
1191 | VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}", | 1211 | VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}", |
1192 | Prim.LocalID, movingDirection, pointingDirection, deflectionError, ret); | 1212 | Prim.LocalID, movingDirection, pointingDirection, deflectionError, ret); |
1213 | VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3}", | ||
1214 | Prim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale); | ||
1193 | } | 1215 | } |
1194 | return ret; | 1216 | return ret; |
1195 | } | 1217 | } |
@@ -1305,6 +1327,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1305 | private float ClampInRange(float low, float val, float high) | 1327 | private float ClampInRange(float low, float val, float high) |
1306 | { | 1328 | { |
1307 | return Math.Max(low, Math.Min(val, high)); | 1329 | return Math.Max(low, Math.Min(val, high)); |
1330 | // return Utils.Clamp(val, low, high); | ||
1308 | } | 1331 | } |
1309 | 1332 | ||
1310 | // Invoke the detailed logger and output something if it's enabled. | 1333 | // Invoke the detailed logger and output something if it's enabled. |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt index ad4e42b..8a9aec9 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt | |||
@@ -8,9 +8,10 @@ Enable vehicle border crossings (at least as poorly as ODE) | |||
8 | Vehicle recreated in new sim at small Z value (offset from root value?) (DONE) | 8 | Vehicle recreated in new sim at small Z value (offset from root value?) (DONE) |
9 | Calibrate turning radius (DONE) | 9 | Calibrate turning radius (DONE) |
10 | limitMotorUp calibration (more down?) | 10 | limitMotorUp calibration (more down?) |
11 | study PID motors (include 'efficiency' implementation | 11 | study PID motors (include 'efficiency' implementation (DONE) |
12 | Add to avatar movement | 12 | Add to avatar movement |
13 | 13 | ||
14 | |||
14 | CRASHES | 15 | CRASHES |
15 | ================================================= | 16 | ================================================= |
16 | 20121129.1411: editting/moving phys object across region boundries causes crash | 17 | 20121129.1411: editting/moving phys object across region boundries causes crash |
@@ -25,7 +26,6 @@ CRASHES | |||
25 | VEHICLES TODO LIST: | 26 | VEHICLES TODO LIST: |
26 | ================================================= | 27 | ================================================= |
27 | Border crossing with linked vehicle causes crash | 28 | Border crossing with linked vehicle causes crash |
28 | Neb vehicle taking > 25ms of physics time!! | ||
29 | Vehicles (Move smoothly) | 29 | Vehicles (Move smoothly) |
30 | Add vehicle collisions so IsColliding is properly reported. | 30 | Add vehicle collisions so IsColliding is properly reported. |
31 | Needed for banking, limitMotorUp, movementLimiting, ... | 31 | Needed for banking, limitMotorUp, movementLimiting, ... |
@@ -34,28 +34,25 @@ Cannot edit/move a vehicle being ridden: it jumps back to the origional position | |||
34 | Neb car jiggling left and right | 34 | Neb car jiggling left and right |
35 | Happens on terrain and any other mesh object. Flat cubes are much smoother. | 35 | Happens on terrain and any other mesh object. Flat cubes are much smoother. |
36 | This has been reduced but not eliminated. | 36 | This has been reduced but not eliminated. |
37 | Light cycle falling over when driving | ||
38 | Implement referenceFrame for all the motion routines. | 37 | Implement referenceFrame for all the motion routines. |
39 | Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE. | 38 | Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE. |
40 | Verify that angular motion specified around Z moves in the vehicle coordinates. | 39 | Verify that angular motion specified around Z moves in the vehicle coordinates. |
41 | Verify llGetVel() is returning a smooth and good value for vehicle movement. | 40 | Verify llGetVel() is returning a smooth and good value for vehicle movement. |
42 | llGetVel() should return the root's velocity if requested in a child prim. | 41 | llGetVel() should return the root's velocity if requested in a child prim. |
43 | Implement function efficiency for lineaar and angular motion. | 42 | Implement function efficiency for lineaar and angular motion. |
44 | Should vehicle angular/linear movement friction happen after all the components | ||
45 | or does it only apply to the basic movement? | ||
46 | After getting off a vehicle, the root prim is phantom (can be walked through) | 43 | After getting off a vehicle, the root prim is phantom (can be walked through) |
47 | Need to force a position update for the root prim after compound shape destruction | 44 | Need to force a position update for the root prim after compound shape destruction |
48 | Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint) | 45 | Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint) |
49 | For limitMotorUp, use raycast down to find if vehicle is in the air. | 46 | For limitMotorUp, use raycast down to find if vehicle is in the air. |
50 | Remove vehicle angular velocity zeroing in BSPrim.UpdateProperties(). | 47 | Remove vehicle angular velocity zeroing in BSPrim.UpdateProperties(). |
51 | A kludge that isn't fixing the real problem of Bullet adding extra motion. | 48 | A kludge that isn't fixing the real problem of Bullet adding extra motion. |
49 | Incorporate inter-relationship of angular corrections. For instance, angularDeflection | ||
50 | and angularMotorUp will compute same X or Y correction. When added together | ||
51 | creates over-correction and over-shoot and wabbling. | ||
52 | 52 | ||
53 | BULLETSIM TODO LIST: | 53 | BULLETSIM TODO LIST: |
54 | ================================================= | 54 | ================================================= |
55 | Revisit CollisionMargin. Builders notice the 0.04 spacing between prims. | 55 | Revisit CollisionMargin. Builders notice the 0.04 spacing between prims. |
56 | Avatar height off after unsitting (floats off ground) | ||
57 | Editting appearance then moving restores. | ||
58 | Must not be initializing height when recreating capsule after unsit. | ||
59 | Duplicating a physical prim causes old prim to jump away | 56 | Duplicating a physical prim causes old prim to jump away |
60 | Dup a phys prim and the original become unselected and thus interacts w/ selected prim. | 57 | Dup a phys prim and the original become unselected and thus interacts w/ selected prim. |
61 | Scenes with hundred of thousands of static objects take a lot of physics CPU time. | 58 | Scenes with hundred of thousands of static objects take a lot of physics CPU time. |
@@ -83,6 +80,8 @@ Add osGetPhysicsEngineName() so scripters can tell whether BulletSim or ODE | |||
83 | Linkset.Position and Linkset.Orientation requre rewrite to properly return | 80 | Linkset.Position and Linkset.Orientation requre rewrite to properly return |
84 | child position. LinksetConstraint acts like it's at taint time!! | 81 | child position. LinksetConstraint acts like it's at taint time!! |
85 | Implement LockAngularMotion -- implements llSetStatus(ROTATE_AXIS_*, T/F) | 82 | Implement LockAngularMotion -- implements llSetStatus(ROTATE_AXIS_*, T/F) |
83 | Should the different PID factors have non-equal contributions for different | ||
84 | values of Efficiency? | ||
86 | 85 | ||
87 | LINKSETS | 86 | LINKSETS |
88 | ====================================================== | 87 | ====================================================== |
@@ -100,17 +99,16 @@ Disable activity of passive linkset children. | |||
100 | Since the linkset is a compound object, the old prims are left lying | 99 | Since the linkset is a compound object, the old prims are left lying |
101 | around and need to be phantomized so they don't collide, ... | 100 | around and need to be phantomized so they don't collide, ... |
102 | Speed up creation of large physical linksets | 101 | Speed up creation of large physical linksets |
103 | For instance, sitting in Neb's car (130 prims) takes several seconds to become physical | 102 | For instance, sitting in Neb's car (130 prims) takes several seconds to become physical. |
103 | REALLY bad for very large physical linksets (freezes the sim for many seconds). | ||
104 | Eliminate collisions between objects in a linkset. (LinksetConstraint) | 104 | Eliminate collisions between objects in a linkset. (LinksetConstraint) |
105 | Have UserPointer point to struct with localID and linksetID? | 105 | Have UserPointer point to struct with localID and linksetID? |
106 | Objects in original linkset still collide with each other? | 106 | Objects in original linkset still collide with each other? |
107 | 107 | ||
108 | MORE | 108 | MORE |
109 | ====================================================== | 109 | ====================================================== |
110 | Find/remove avatar collision with ID=0. | ||
111 | Test avatar walking up stairs. How does compare with SL. | 110 | Test avatar walking up stairs. How does compare with SL. |
112 | Radius of the capsule affects ability to climb edges. | 111 | Radius of the capsule affects ability to climb edges. |
113 | Tune terrain/object friction to be closer to SL. | ||
114 | Debounce avatar contact so legs don't keep folding up when standing. | 112 | Debounce avatar contact so legs don't keep folding up when standing. |
115 | Implement LSL physics controls. Like STATUS_ROTATE_X. | 113 | Implement LSL physics controls. Like STATUS_ROTATE_X. |
116 | Add border extensions to terrain to help region crossings and objects leaving region. | 114 | Add border extensions to terrain to help region crossings and objects leaving region. |
@@ -203,3 +201,16 @@ Single prim vehicles don't seem to properly vehiclize. | |||
203 | Add material type linkage and input all the material property definitions. | 201 | Add material type linkage and input all the material property definitions. |
204 | Skeleton classes and table are in the sources but are not filled or used. | 202 | Skeleton classes and table are in the sources but are not filled or used. |
205 | (Resolution: | 203 | (Resolution: |
204 | Neb vehicle taking > 25ms of physics time!! | ||
205 | (Resolution: compound linksets were being rebuild WAY too often) | ||
206 | Avatar height off after unsitting (floats off ground) | ||
207 | Editting appearance then moving restores. | ||
208 | Must not be initializing height when recreating capsule after unsit. | ||
209 | (Resolution: confusion of scale vs size for native objects removed) | ||
210 | Light cycle falling over when driving (Resolution: implemented angularMotorUp) | ||
211 | Should vehicle angular/linear movement friction happen after all the components | ||
212 | or does it only apply to the basic movement? | ||
213 | (Resolution: friction added before returning newly computed motor value. | ||
214 | What is expected by some vehicles (turning up friction to moderate speed)) | ||
215 | Tune terrain/object friction to be closer to SL. | ||
216 | (Resolution: added material type with friction and resolution) | ||