aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region')
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs3
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs439
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSMotors.cs37
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs22
4 files changed, 296 insertions, 205 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs b/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs
index af54c1a..b735c61 100644
--- a/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs
@@ -81,7 +81,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Groups
81 } 81 }
82 82
83 if (groupsConfig.GetString("Module", "Default") != "Default") 83 if (groupsConfig.GetString("Module", "Default") != "Default")
84 {
85 m_Enabled = false;
84 return; 86 return;
87 }
85 } 88 }
86 89
87 } 90 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index 6ff8a48..74eb9ab 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -125,6 +125,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
125 // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity. 125 // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity.
126 126
127 //Attractor properties 127 //Attractor properties
128 private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction");
128 private float m_verticalAttractionEfficiency = 1.0f; // damped 129 private float m_verticalAttractionEfficiency = 1.0f; // damped
129 private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor. 130 private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor.
130 131
@@ -197,9 +198,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
197 break; 198 break;
198 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: 199 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
199 m_verticalAttractionEfficiency = Math.Max(0.1f, Math.Min(pValue, 1f)); 200 m_verticalAttractionEfficiency = Math.Max(0.1f, Math.Min(pValue, 1f));
201 m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency;
200 break; 202 break;
201 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: 203 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
202 m_verticalAttractionTimescale = Math.Max(pValue, 0.01f); 204 m_verticalAttractionTimescale = Math.Max(pValue, 0.01f);
205 m_verticalAttractionMotor.TimeScale = m_verticalAttractionTimescale;
203 break; 206 break;
204 207
205 // These are vector properties but the engine lets you use a single float value to 208 // These are vector properties but the engine lets you use a single float value to
@@ -314,7 +317,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
314 m_VhoverEfficiency = 0; 317 m_VhoverEfficiency = 0;
315 m_VhoverTimescale = 0; 318 m_VhoverTimescale = 0;
316 m_VehicleBuoyancy = 0; 319 m_VehicleBuoyancy = 0;
317 320
318 m_linearDeflectionEfficiency = 1; 321 m_linearDeflectionEfficiency = 1;
319 m_linearDeflectionTimescale = 1; 322 m_linearDeflectionTimescale = 1;
320 323
@@ -363,8 +366,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
363 m_bankingMix = 1; 366 m_bankingMix = 1;
364 367
365 m_referenceFrame = Quaternion.Identity; 368 m_referenceFrame = Quaternion.Identity;
366 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY 369 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
367 | VehicleFlag.HOVER_TERRAIN_ONLY 370 | VehicleFlag.HOVER_TERRAIN_ONLY
368 | VehicleFlag.HOVER_GLOBAL_HEIGHT 371 | VehicleFlag.HOVER_GLOBAL_HEIGHT
369 | VehicleFlag.HOVER_UP_ONLY); 372 | VehicleFlag.HOVER_UP_ONLY);
370 m_flags |= (VehicleFlag.NO_DEFLECTION_UP 373 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
@@ -530,12 +533,22 @@ namespace OpenSim.Region.Physics.BulletSPlugin
530 Refresh(); 533 Refresh();
531 534
532 m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale, 535 m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale,
533 m_linearMotorDecayTimescale, m_linearFrictionTimescale, 1f); 536 m_linearMotorDecayTimescale, m_linearFrictionTimescale,
537 1f);
534 m_linearMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) 538 m_linearMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
539
535 m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, 540 m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale,
536 m_angularMotorDecayTimescale, m_angularFrictionTimescale, 1f); 541 m_angularMotorDecayTimescale, m_angularFrictionTimescale,
542 1f);
537 m_angularMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) 543 m_angularMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
538 544
545 m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale,
546 BSMotor.Infinite, BSMotor.InfiniteVector,
547 m_verticalAttractionEfficiency);
548 // Z goes away and we keep X and Y
549 m_verticalAttractionMotor.FrictionTimescale = new Vector3(BSMotor.Infinite, BSMotor.Infinite, 0.1f);
550 m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
551
539 // m_bankingMotor = new BSVMotor("BankingMotor", ...); 552 // m_bankingMotor = new BSVMotor("BankingMotor", ...);
540 } 553 }
541 554
@@ -562,7 +575,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
562 Vector3 localInertia = new Vector3(m_vehicleMass, m_vehicleMass, m_vehicleMass); 575 Vector3 localInertia = new Vector3(m_vehicleMass, m_vehicleMass, m_vehicleMass);
563 BulletSimAPI.SetMassProps2(Prim.PhysBody.ptr, m_vehicleMass, localInertia); 576 BulletSimAPI.SetMassProps2(Prim.PhysBody.ptr, m_vehicleMass, localInertia);
564 577
565 VDetailLog("{0},BSDynamics.Refresh,frict={1},inert={2},aDamp={3}", 578 VDetailLog("{0},BSDynamics.Refresh,frict={1},inert={2},aDamp={3}",
566 Prim.LocalID, friction, localInertia, angularDamping); 579 Prim.LocalID, friction, localInertia, angularDamping);
567 } 580 }
568 } 581 }
@@ -617,13 +630,64 @@ namespace OpenSim.Region.Physics.BulletSPlugin
617 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; 630 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
618 Vector3 grav = Prim.PhysicsScene.DefaultGravity * (1f - m_VehicleBuoyancy); 631 Vector3 grav = Prim.PhysicsScene.DefaultGravity * (1f - m_VehicleBuoyancy);
619 632
620 // Current vehicle position
621 Vector3 pos = Prim.ForcePosition; 633 Vector3 pos = Prim.ForcePosition;
634 float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
635
636 Vector3 terrainHeightContribution = ComputeLinearTerrainHeightCorrection(pTimestep, ref pos, terrainHeight);
637
638 Vector3 hoverContribution = ComputeLinearHover(pTimestep, ref pos, terrainHeight);
639
640 ComputeLinearBlockingEndPoint(pTimestep, ref pos);
641
642 Vector3 limitMotorUpContribution = ComputeLinearMotorUp(pTimestep, pos, terrainHeight);
643
644 // ==================================================================
645 Vector3 newVelocity = linearMotorContribution
646 + terrainHeightContribution
647 + hoverContribution
648 + limitMotorUpContribution;
649
650 // If not changing some axis, reduce out velocity
651 if ((m_flags & (VehicleFlag.NO_X)) != 0)
652 newVelocity.X = 0;
653 if ((m_flags & (VehicleFlag.NO_Y)) != 0)
654 newVelocity.Y = 0;
655 if ((m_flags & (VehicleFlag.NO_Z)) != 0)
656 newVelocity.Z = 0;
622 657
623 // ================================================================== 658 // ==================================================================
624 Vector3 terrainHeightContribution = Vector3.Zero; 659 // Clamp REALLY high or low velocities
660 float newVelocityLengthSq = newVelocity.LengthSquared();
661 if (newVelocityLengthSq > 1e6f)
662 {
663 newVelocity /= newVelocity.Length();
664 newVelocity *= 1000f;
665 }
666 else if (newVelocityLengthSq < 1e-6f)
667 newVelocity = Vector3.Zero;
668
669 // ==================================================================
670 // Stuff new linear velocity into the vehicle
671 Prim.ForceVelocity = newVelocity;
672 // Prim.ApplyForceImpulse((m_newVelocity - Prim.Velocity) * m_vehicleMass, false); // DEBUG DEBUG
673
674 // Other linear forces are applied as forces.
675 Vector3 totalDownForce = grav * m_vehicleMass;
676 if (totalDownForce != Vector3.Zero)
677 {
678 Prim.AddForce(totalDownForce, false);
679 }
680
681 VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},primVel={4},totalDown={5}",
682 Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector,
683 newVelocity, Prim.Velocity, totalDownForce);
684
685 } // end MoveLinear()
686
687 public Vector3 ComputeLinearTerrainHeightCorrection(float pTimestep, ref Vector3 pos, float terrainHeight)
688 {
689 Vector3 ret = Vector3.Zero;
625 // If below the terrain, move us above the ground a little. 690 // If below the terrain, move us above the ground a little.
626 float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
627 // Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset. 691 // Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset.
628 // TODO: Add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass. 692 // TODO: Add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass.
629 // Vector3 rotatedSize = m_prim.Size * m_prim.ForceOrientation; 693 // Vector3 rotatedSize = m_prim.Size * m_prim.ForceOrientation;
@@ -635,10 +699,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
635 Prim.ForcePosition = pos; 699 Prim.ForcePosition = pos;
636 VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos); 700 VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos);
637 } 701 }
702 return ret;
703 }
704
705 public Vector3 ComputeLinearHover(float pTimestep, ref Vector3 pos, float terrainHeight)
706 {
707 Vector3 ret = Vector3.Zero;
638 708
639 // ==================================================================
640 Vector3 hoverContribution = Vector3.Zero;
641 // Check if hovering
642 // m_VhoverEfficiency: 0=bouncy, 1=totally damped 709 // m_VhoverEfficiency: 0=bouncy, 1=totally damped
643 // m_VhoverTimescale: time to achieve height 710 // m_VhoverTimescale: time to achieve height
644 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) 711 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
@@ -679,24 +746,29 @@ namespace OpenSim.Region.Physics.BulletSPlugin
679 // Replace Vertical speed with correction figure if significant 746 // Replace Vertical speed with correction figure if significant
680 if (verticalError > 0.01f) 747 if (verticalError > 0.01f)
681 { 748 {
682 hoverContribution = new Vector3(0f, 0f, verticalCorrectionVelocity); 749 ret = new Vector3(0f, 0f, verticalCorrectionVelocity);
683 //KF: m_VhoverEfficiency is not yet implemented 750 //KF: m_VhoverEfficiency is not yet implemented
684 } 751 }
685 else if (verticalError < -0.01) 752 else if (verticalError < -0.01)
686 { 753 {
687 hoverContribution = new Vector3(0f, 0f, -verticalCorrectionVelocity); 754 ret = new Vector3(0f, 0f, -verticalCorrectionVelocity);
688 } 755 }
689 } 756 }
690 757
691 VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", 758 VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}",
692 Prim.LocalID, pos, hoverContribution, m_VhoverHeight, m_VhoverTargetHeight); 759 Prim.LocalID, pos, ret, m_VhoverHeight, m_VhoverTargetHeight);
693 } 760 }
694 761
695 // ================================================================== 762 return ret;
763 }
764
765 public bool ComputeLinearBlockingEndPoint(float pTimestep, ref Vector3 pos)
766 {
767 bool changed = false;
768
696 Vector3 posChange = pos - m_lastPositionVector; 769 Vector3 posChange = pos - m_lastPositionVector;
697 if (m_BlockingEndPoint != Vector3.Zero) 770 if (m_BlockingEndPoint != Vector3.Zero)
698 { 771 {
699 bool changed = false;
700 if (pos.X >= (m_BlockingEndPoint.X - (float)1)) 772 if (pos.X >= (m_BlockingEndPoint.X - (float)1))
701 { 773 {
702 pos.X -= posChange.X + 1; 774 pos.X -= posChange.X + 1;
@@ -729,9 +801,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
729 Prim.LocalID, m_BlockingEndPoint, posChange, pos); 801 Prim.LocalID, m_BlockingEndPoint, posChange, pos);
730 } 802 }
731 } 803 }
804 return changed;
805 }
732 806
733 // ================================================================== 807 public Vector3 ComputeLinearMotorUp(float pTimestep, Vector3 pos, float terrainHeight)
734 Vector3 limitMotorUpContribution = Vector3.Zero; 808 {
809 Vector3 ret = Vector3.Zero;
735 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) 810 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
736 { 811 {
737 // If the vehicle is motoring into the sky, get it going back down. 812 // If the vehicle is motoring into the sky, get it going back down.
@@ -740,58 +815,17 @@ namespace OpenSim.Region.Physics.BulletSPlugin
740 { 815 {
741 // downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep); 816 // downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep);
742 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); 817 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale);
743 limitMotorUpContribution = new Vector3(0, 0, -distanceAboveGround); 818 ret = new Vector3(0, 0, -distanceAboveGround);
744 } 819 }
745 // TODO: this calculation is all wrong. From the description at 820 // TODO: this calculation is all wrong. From the description at
746 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce 821 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce
747 // has a decay factor. This says this force should 822 // has a decay factor. This says this force should
748 // be computed with a motor. 823 // be computed with a motor.
749 VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}", 824 VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}",
750 Prim.LocalID, distanceAboveGround, limitMotorUpContribution); 825 Prim.LocalID, distanceAboveGround, ret);
751 }
752
753 // ==================================================================
754 Vector3 newVelocity = linearMotorContribution
755 + terrainHeightContribution
756 + hoverContribution
757 + limitMotorUpContribution;
758
759 // If not changing some axis, reduce out velocity
760 if ((m_flags & (VehicleFlag.NO_X)) != 0)
761 newVelocity.X = 0;
762 if ((m_flags & (VehicleFlag.NO_Y)) != 0)
763 newVelocity.Y = 0;
764 if ((m_flags & (VehicleFlag.NO_Z)) != 0)
765 newVelocity.Z = 0;
766
767 // ==================================================================
768 // Clamp REALLY high or low velocities
769 float newVelocityLengthSq = newVelocity.LengthSquared();
770 if (newVelocityLengthSq > 1e6f)
771 {
772 newVelocity /= newVelocity.Length();
773 newVelocity *= 1000f;
774 } 826 }
775 else if (newVelocityLengthSq < 1e-6f) 827 return ret;
776 newVelocity = Vector3.Zero; 828 }
777
778 // ==================================================================
779 // Stuff new linear velocity into the vehicle
780 Prim.ForceVelocity = newVelocity;
781 // Prim.ApplyForceImpulse((m_newVelocity - Prim.Velocity) * m_vehicleMass, false); // DEBUG DEBUG
782
783 // Other linear forces are applied as forces.
784 Vector3 totalDownForce = grav * m_vehicleMass;
785 if (totalDownForce != Vector3.Zero)
786 {
787 Prim.AddForce(totalDownForce, false);
788 }
789
790 VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},primVel={4},totalDown={5}",
791 Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector,
792 newVelocity, Prim.Velocity, totalDownForce);
793
794 } // end MoveLinear()
795 829
796 // ======================================================================= 830 // =======================================================================
797 // ======================================================================= 831 // =======================================================================
@@ -829,130 +863,25 @@ namespace OpenSim.Region.Physics.BulletSPlugin
829 Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep); 863 Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep);
830 864
831 // ================================================================== 865 // ==================================================================
832 Vector3 verticalAttractionContribution = Vector3.Zero; 866 // NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
833 // If vertical attaction timescale is reasonable and we applied an angular force last time... 867 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
834 if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero)
835 {
836 float VAservo = pTimestep * 0.2f / m_verticalAttractionTimescale;
837 if (Prim.IsColliding)
838 VAservo = pTimestep * 0.05f / m_verticalAttractionTimescale;
839
840 VAservo *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
841
842 // Create a vector of the vehicle "up" in world coordinates
843 Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation;
844 // verticalError.X and .Y are the World error amounts. They are 0 when there is no
845 // error (Vehicle Body is 'vertical'), and .Z will be 1. As the body leans to its
846 // side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall
847 // and .Z will go negative. Similar for tilt and |.Y|. .X and .Y must be
848 // modulated to prevent a stable inverted body.
849
850 // Error is 0 (no error) to +/- 2 (max error)
851 verticalError.X = Math.Max(-2f, Math.Min(verticalError.X, 2f));
852 verticalError.Y = Math.Max(-2f, Math.Min(verticalError.Y, 2f));
853
854 // scale it by VAservo (timestep and timescale)
855 verticalError = verticalError * VAservo;
856
857 // As the body rotates around the X axis, then verticalError.Y increases; Rotated around Y
858 // then .X increases, so change Body angular velocity X based on Y, and Y based on X.
859 // Z is not changed.
860 verticalAttractionContribution.X = verticalError.Y;
861 verticalAttractionContribution.Y = - verticalError.X;
862 verticalAttractionContribution.Z = 0f;
863
864 // scaling appears better usingsquare-law
865 Vector3 angularVelocity = Prim.ForceRotationalVelocity;
866 float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
867 verticalAttractionContribution.X += bounce * angularVelocity.X;
868 verticalAttractionContribution.Y += bounce * angularVelocity.Y;
869
870 VDetailLog("{0},MoveAngular,verticalAttraction,VAservo={1},effic={2},verticalError={3},bounce={4},vertattr={5}",
871 Prim.LocalID, VAservo, m_verticalAttractionEfficiency, verticalError, bounce, verticalAttractionContribution);
872
873 }
874
875 // ==================================================================
876 Vector3 deflectionContribution = Vector3.Zero;
877 if (m_angularDeflectionEfficiency != 0)
878 { 868 {
879 // Compute a scaled vector that points in the preferred axis (X direction) 869 angularMotorContribution.X = 0f;
880 Vector3 scaledDefaultDirection = 870 angularMotorContribution.Y = 0f;
881 new Vector3((pTimestep * 10 * (m_angularDeflectionEfficiency / m_angularDeflectionTimescale)), 0, 0); 871 VDetailLog("{0},MoveAngular,noDeflectionUp,angularMotorContrib={1}", Prim.LocalID, angularMotorContribution);
882 // Adding the current vehicle orientation and reference frame displaces the orientation to the frame.
883 // Rotate the scaled default axix relative to the actual vehicle direction giving where it should point.
884 Vector3 preferredAxisOfMotion = scaledDefaultDirection * Quaternion.Add(Prim.ForceOrientation, m_referenceFrame);
885
886 // Scale by efficiency and timescale
887 deflectionContribution = (preferredAxisOfMotion * (m_angularDeflectionEfficiency) / m_angularDeflectionTimescale) * pTimestep;
888
889 VDetailLog("{0},MoveAngular,Deflection,perfAxis={1},deflection={2}",
890 Prim.LocalID, preferredAxisOfMotion, deflectionContribution);
891 // This deflection computation is not correct.
892 deflectionContribution = Vector3.Zero;
893 } 872 }
894 873
895 // ================================================================== 874 Vector3 verticalAttractionContribution = ComputeAngularVerticalAttraction(pTimestep);
896 Vector3 bankingContribution = Vector3.Zero;
897 if (m_bankingEfficiency != 0)
898 {
899 Vector3 dir = Vector3.One * Prim.ForceOrientation;
900 float mult = (m_bankingMix*m_bankingMix)*-1*(m_bankingMix < 0 ? -1 : 1);
901 //Changes which way it banks in and out of turns
902
903 //Use the square of the efficiency, as it looks much more how SL banking works
904 float effSquared = (m_bankingEfficiency*m_bankingEfficiency);
905 if (m_bankingEfficiency < 0)
906 effSquared *= -1; //Keep the negative!
907 875
908 float mix = Math.Abs(m_bankingMix); 876 Vector3 deflectionContribution = ComputeAngularDeflection(pTimestep);
909 if (m_angularMotorVelocity.X == 0)
910 {
911 // The vehicle is stopped
912 /*if (!parent.Orientation.ApproxEquals(this.m_referenceFrame, 0.25f))
913 {
914 Vector3 axisAngle;
915 float angle;
916 parent.Orientation.GetAxisAngle(out axisAngle, out angle);
917 Vector3 rotatedVel = parent.Velocity * parent.Orientation;
918 if ((rotatedVel.X < 0 && axisAngle.Y > 0) || (rotatedVel.X > 0 && axisAngle.Y < 0))
919 m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (1f) * 10;
920 else
921 m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (-1f) * 10;
922 }*/
923 }
924 else
925 {
926 bankingContribution.Z += (effSquared * (mult * mix)) * (m_angularMotorVelocity.X) * 4;
927 }
928 877
929 //If they are colliding, we probably shouldn't shove the prim around... probably 878 Vector3 bankingContribution = ComputeAngularBanking(pTimestep);
930 if (!Prim.IsColliding && Math.Abs(m_angularMotorVelocity.X) > mix)
931 {
932 float angVelZ = m_angularMotorVelocity.X*-1;
933 /*if(angVelZ > mix)
934 angVelZ = mix;
935 else if(angVelZ < -mix)
936 angVelZ = -mix;*/
937 //This controls how fast and how far the banking occurs
938 Vector3 bankingRot = new Vector3(angVelZ*(effSquared*mult), 0, 0);
939 if (bankingRot.X > 3)
940 bankingRot.X = 3;
941 else if (bankingRot.X < -3)
942 bankingRot.X = -3;
943 bankingRot *= Prim.ForceOrientation;
944 bankingContribution += bankingRot;
945 }
946 m_angularMotorVelocity.X *= m_bankingEfficiency == 1 ? 0.0f : 1 - m_bankingEfficiency;
947 VDetailLog("{0},MoveAngular,Banking,bEff={1},angMotVel={2},effSq={3},mult={4},mix={5},banking={6}",
948 Prim.LocalID, m_bankingEfficiency, m_angularMotorVelocity, effSquared, mult, mix, bankingContribution);
949 }
950 879
951 // ================================================================== 880 // ==================================================================
952 m_lastVertAttractor = verticalAttractionContribution; 881 m_lastVertAttractor = verticalAttractionContribution;
953 882
954 // Sum velocities 883 // Sum velocities
955 m_lastAngularVelocity = angularMotorContribution 884 m_lastAngularVelocity = angularMotorContribution
956 + verticalAttractionContribution 885 + verticalAttractionContribution
957 + bankingContribution 886 + bankingContribution
958 + deflectionContribution; 887 + deflectionContribution;
@@ -989,15 +918,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin
989 } 918 }
990 919
991 // ================================================================== 920 // ==================================================================
992 // NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
993 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
994 {
995 m_lastAngularVelocity.X = 0;
996 m_lastAngularVelocity.Y = 0;
997 VDetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity);
998 }
999
1000 // ==================================================================
1001 if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) 921 if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
1002 { 922 {
1003 m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. 923 m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero.
@@ -1011,7 +931,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1011 // Since we are stuffing the angular velocity directly into the object, the computed 931 // Since we are stuffing the angular velocity directly into the object, the computed
1012 // velocity needs to be scaled by the timestep. 932 // velocity needs to be scaled by the timestep.
1013 // Also remove any motion that is on the object so added motion is only from vehicle. 933 // Also remove any motion that is on the object so added motion is only from vehicle.
1014 Vector3 applyAngularForce = ((m_lastAngularVelocity * pTimestep) 934 Vector3 applyAngularForce = ((m_lastAngularVelocity * pTimestep)
1015 - Prim.ForceRotationalVelocity); 935 - Prim.ForceRotationalVelocity);
1016 // Unscale the force by the angular factor so it overwhelmes the Bullet additions. 936 // Unscale the force by the angular factor so it overwhelmes the Bullet additions.
1017 Prim.ForceRotationalVelocity = applyAngularForce; 937 Prim.ForceRotationalVelocity = applyAngularForce;
@@ -1025,6 +945,147 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1025 } 945 }
1026 } 946 }
1027 947
948 public Vector3 ComputeAngularVerticalAttraction(float pTimestep)
949 {
950 Vector3 ret = Vector3.Zero;
951
952 // If vertical attaction timescale is reasonable and we applied an angular force last time...
953 if (m_verticalAttractionTimescale < 500)
954 {
955 Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation;
956 verticalError.Normalize();
957 m_verticalAttractionMotor.SetCurrent(verticalError);
958 m_verticalAttractionMotor.SetTarget(Vector3.UnitZ);
959 ret = m_verticalAttractionMotor.Step(pTimestep);
960 /*
961 // Take a vector pointing up and convert it from world to vehicle relative coords.
962 Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation;
963 verticalError.Normalize();
964
965 // If vertical attraction correction is needed, the vector that was pointing up (UnitZ)
966 // is now leaning to one side (rotated around the X axis) and the Y value will
967 // go from zero (nearly straight up) to one (completely to the side) or leaning
968 // front-to-back (rotated around the Y axis) and the value of X will be between
969 // zero and one.
970 // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees.
971
972 // If verticalError.Z is negative, the vehicle is upside down. Add additional push.
973 if (verticalError.Z < 0f)
974 {
975 verticalError.X = 2f - verticalError.X;
976 verticalError.Y = 2f - verticalError.Y;
977 }
978
979 // Y error means needed rotation around X axis and visa versa.
980 verticalAttractionContribution.X = verticalError.Y;
981 verticalAttractionContribution.Y = - verticalError.X;
982 verticalAttractionContribution.Z = 0f;
983
984 // scale by the time scale and timestep
985 Vector3 unscaledContrib = verticalAttractionContribution;
986 verticalAttractionContribution /= m_verticalAttractionTimescale;
987 verticalAttractionContribution *= pTimestep;
988
989 // apply efficiency
990 Vector3 preEfficiencyContrib = verticalAttractionContribution;
991 float efficencySquared = m_verticalAttractionEfficiency * m_verticalAttractionEfficiency;
992 verticalAttractionContribution *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
993
994 VDetailLog("{0},MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},preEff={3},eff={4},effSq={5},vertAttr={6}",
995 Prim.LocalID, verticalError, unscaledContrib, preEfficiencyContrib,
996 m_verticalAttractionEfficiency, efficencySquared,
997 verticalAttractionContribution);
998 */
999
1000 }
1001 return ret;
1002 }
1003
1004 public Vector3 ComputeAngularDeflection(float pTimestep)
1005 {
1006 Vector3 ret = Vector3.Zero;
1007
1008 if (m_angularDeflectionEfficiency != 0)
1009 {
1010 // Compute a scaled vector that points in the preferred axis (X direction)
1011 Vector3 scaledDefaultDirection =
1012 new Vector3((pTimestep * 10 * (m_angularDeflectionEfficiency / m_angularDeflectionTimescale)), 0, 0);
1013 // Adding the current vehicle orientation and reference frame displaces the orientation to the frame.
1014 // Rotate the scaled default axix relative to the actual vehicle direction giving where it should point.
1015 Vector3 preferredAxisOfMotion = scaledDefaultDirection * Quaternion.Add(Prim.ForceOrientation, m_referenceFrame);
1016
1017 // Scale by efficiency and timescale
1018 ret = (preferredAxisOfMotion * (m_angularDeflectionEfficiency) / m_angularDeflectionTimescale) * pTimestep;
1019
1020 VDetailLog("{0},MoveAngular,Deflection,perfAxis={1},deflection={2}", Prim.LocalID, preferredAxisOfMotion, ret);
1021
1022 // This deflection computation is not correct.
1023 ret = Vector3.Zero;
1024 }
1025 return ret;
1026 }
1027
1028 public Vector3 ComputeAngularBanking(float pTimestep)
1029 {
1030 Vector3 ret = Vector3.Zero;
1031
1032 if (m_bankingEfficiency != 0)
1033 {
1034 Vector3 dir = Vector3.One * Prim.ForceOrientation;
1035 float mult = (m_bankingMix * m_bankingMix) * -1 * (m_bankingMix < 0 ? -1 : 1);
1036 //Changes which way it banks in and out of turns
1037
1038 //Use the square of the efficiency, as it looks much more how SL banking works
1039 float effSquared = (m_bankingEfficiency * m_bankingEfficiency);
1040 if (m_bankingEfficiency < 0)
1041 effSquared *= -1; //Keep the negative!
1042
1043 float mix = Math.Abs(m_bankingMix);
1044 if (m_angularMotorVelocity.X == 0)
1045 {
1046 // The vehicle is stopped
1047 /*if (!parent.Orientation.ApproxEquals(this.m_referenceFrame, 0.25f))
1048 {
1049 Vector3 axisAngle;
1050 float angle;
1051 parent.Orientation.GetAxisAngle(out axisAngle, out angle);
1052 Vector3 rotatedVel = parent.Velocity * parent.Orientation;
1053 if ((rotatedVel.X < 0 && axisAngle.Y > 0) || (rotatedVel.X > 0 && axisAngle.Y < 0))
1054 m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (1f) * 10;
1055 else
1056 m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (-1f) * 10;
1057 }*/
1058 }
1059 else
1060 {
1061 ret.Z += (effSquared * (mult * mix)) * (m_angularMotorVelocity.X) * 4;
1062 }
1063
1064 //If they are colliding, we probably shouldn't shove the prim around... probably
1065 if (!Prim.IsColliding && Math.Abs(m_angularMotorVelocity.X) > mix)
1066 {
1067 float angVelZ = m_angularMotorVelocity.X * -1;
1068 /*if(angVelZ > mix)
1069 angVelZ = mix;
1070 else if(angVelZ < -mix)
1071 angVelZ = -mix;*/
1072 //This controls how fast and how far the banking occurs
1073 Vector3 bankingRot = new Vector3(angVelZ * (effSquared * mult), 0, 0);
1074 if (bankingRot.X > 3)
1075 bankingRot.X = 3;
1076 else if (bankingRot.X < -3)
1077 bankingRot.X = -3;
1078 bankingRot *= Prim.ForceOrientation;
1079 ret += bankingRot;
1080 }
1081 m_angularMotorVelocity.X *= m_bankingEfficiency == 1 ? 0.0f : 1 - m_bankingEfficiency;
1082 VDetailLog("{0},MoveAngular,Banking,bEff={1},angMotVel={2},effSq={3},mult={4},mix={5},banking={6}",
1083 Prim.LocalID, m_bankingEfficiency, m_angularMotorVelocity, effSquared, mult, mix, ret);
1084 }
1085 return ret;
1086 }
1087
1088
1028 // This is from previous instantiations of XXXDynamics.cs. 1089 // This is from previous instantiations of XXXDynamics.cs.
1029 // Applies roll reference frame. 1090 // Applies roll reference frame.
1030 // TODO: is this the right way to separate the code to do this operation? 1091 // TODO: is this the right way to separate the code to do this operation?
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
index 480da2c..e91bfa8 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
@@ -7,6 +7,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
7{ 7{
8public abstract class BSMotor 8public abstract class BSMotor
9{ 9{
10 // Timescales and other things can be turned off by setting them to 'infinite'.
11 public const float Infinite = 10000f;
12 public readonly static Vector3 InfiniteVector = new Vector3(BSMotor.Infinite, BSMotor.Infinite, BSMotor.Infinite);
13
10 public BSMotor(string useName) 14 public BSMotor(string useName)
11 { 15 {
12 UseName = useName; 16 UseName = useName;
@@ -46,8 +50,9 @@ public class BSVMotor : BSMotor
46 public BSVMotor(string useName) 50 public BSVMotor(string useName)
47 : base(useName) 51 : base(useName)
48 { 52 {
49 TimeScale = TargetValueDecayTimeScale = Efficiency = 1f; 53 TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite;
50 FrictionTimescale = Vector3.Zero; 54 Efficiency = 1f;
55 FrictionTimescale = BSMotor.InfiniteVector;
51 CurrentValue = TargetValue = Vector3.Zero; 56 CurrentValue = TargetValue = Vector3.Zero;
52 } 57 }
53 public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency) 58 public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency)
@@ -78,23 +83,35 @@ public class BSVMotor : BSMotor
78 // Addition = (desiredVector - currentAppliedVector) / secondsItShouldTakeToComplete 83 // Addition = (desiredVector - currentAppliedVector) / secondsItShouldTakeToComplete
79 Vector3 addAmount = (TargetValue - CurrentValue)/TimeScale * timeStep; 84 Vector3 addAmount = (TargetValue - CurrentValue)/TimeScale * timeStep;
80 CurrentValue += addAmount; 85 CurrentValue += addAmount;
86
81 returnCurrent = CurrentValue; 87 returnCurrent = CurrentValue;
82 88
83 // The desired value reduces to zero when also reduces the difference with current. 89 // The desired value reduces to zero which also reduces the difference with current.
84 float decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; 90 // If the decay time is infinite, don't decay at all.
85 TargetValue *= (1f - decayFactor); 91 float decayFactor = 0f;
92 if (TargetValueDecayTimeScale != BSMotor.Infinite)
93 {
94 decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep;
95 TargetValue *= (1f - decayFactor);
96 }
86 97
87 Vector3 frictionFactor = Vector3.Zero; 98 Vector3 frictionFactor = Vector3.Zero;
88 frictionFactor = (Vector3.One / FrictionTimescale) * timeStep; 99 if (FrictionTimescale != BSMotor.InfiniteVector)
89 CurrentValue *= (Vector3.One - frictionFactor); 100 {
101 // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep;
102 frictionFactor.X = FrictionTimescale.X == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.X) * timeStep;
103 frictionFactor.Y = FrictionTimescale.Y == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.Y) * timeStep;
104 frictionFactor.Z = FrictionTimescale.Z == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.Z) * timeStep;
105 CurrentValue *= (Vector3.One - frictionFactor);
106 }
90 107
91 MDetailLog("{0},BSVMotor.Step,nonZero,{1},origTarget={2},origCurr={3},timeStep={4},timeScale={5},addAmnt={6},targetDecay={7},decayFact={8},fricTS={9},frictFact={10}", 108 MDetailLog("{0},BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},timeScale={5},addAmnt={6},targetDecay={7},decayFact={8},fricTS={9},frictFact={10}",
92 BSScene.DetailLogZero, UseName, origTarget, origCurrVal, 109 BSScene.DetailLogZero, UseName, origCurrVal, origTarget,
93 timeStep, TimeScale, addAmount, 110 timeStep, TimeScale, addAmount,
94 TargetValueDecayTimeScale, decayFactor, 111 TargetValueDecayTimeScale, decayFactor,
95 FrictionTimescale, frictionFactor); 112 FrictionTimescale, frictionFactor);
96 MDetailLog("{0},BSVMotor.Step,nonZero,{1},curr={2},target={3},add={4},decay={5},frict={6},ret={7}", 113 MDetailLog("{0},BSVMotor.Step,nonZero,{1},curr={2},target={3},add={4},decay={5},frict={6},ret={7}",
97 BSScene.DetailLogZero, UseName, TargetValue, CurrentValue, 114 BSScene.DetailLogZero, UseName, CurrentValue, TargetValue,
98 addAmount, decayFactor, frictionFactor, returnCurrent); 115 addAmount, decayFactor, frictionFactor, returnCurrent);
99 } 116 }
100 else 117 else
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
index d7afdeb..5f6675d 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
@@ -88,9 +88,11 @@ public sealed class BSTerrainMesh : BSTerrainPhys
88 // Something is very messed up and a crash is in our future. 88 // Something is very messed up and a crash is in our future.
89 return; 89 return;
90 } 90 }
91 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,indices={1},indSz={2},vertices={3},vertSz={4}",
92 ID, indicesCount, indices.Length, verticesCount, vertices.Length);
91 93
92 m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, 94 m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
93 indicesCount, indices, verticesCount, vertices), 95 indicesCount, indices, verticesCount, vertices),
94 BSPhysicsShapeType.SHAPE_MESH); 96 BSPhysicsShapeType.SHAPE_MESH);
95 if (m_terrainShape.ptr == IntPtr.Zero) 97 if (m_terrainShape.ptr == IntPtr.Zero)
96 { 98 {
@@ -122,10 +124,10 @@ public sealed class BSTerrainMesh : BSTerrainPhys
122 // Static objects are not very massive. 124 // Static objects are not very massive.
123 BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero); 125 BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero);
124 126
125 // Return the new terrain to the world of physical objects 127 // Put the new terrain to the world of physical objects
126 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr); 128 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr);
127 129
128 // redo its bounding box now that it is in the world 130 // Redo its bounding box now that it is in the world
129 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr); 131 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr);
130 132
131 BulletSimAPI.SetCollisionFilterMask2(m_terrainBody.ptr, 133 BulletSimAPI.SetCollisionFilterMask2(m_terrainBody.ptr,
@@ -188,6 +190,11 @@ public sealed class BSTerrainMesh : BSTerrainPhys
188 // Simple mesh creation which assumes magnification == 1. 190 // Simple mesh creation which assumes magnification == 1.
189 // TODO: do a more general solution that scales, adds new vertices and smoothes the result. 191 // TODO: do a more general solution that scales, adds new vertices and smoothes the result.
190 192
193 // Create an array of vertices that is sizeX+1 by sizeY+1 (note the loop
194 // from zero to <= sizeX). The triangle indices are then generated as two triangles
195 // per heightmap point. There are sizeX by sizeY of these squares. The extra row and
196 // column of vertices are used to complete the triangles of the last row and column
197 // of the heightmap.
191 try 198 try
192 { 199 {
193 // One vertice per heightmap value plus the vertices off the top and bottom edge. 200 // One vertice per heightmap value plus the vertices off the top and bottom edge.
@@ -200,16 +207,18 @@ public sealed class BSTerrainMesh : BSTerrainPhys
200 float magY = (float)sizeY / extentY; 207 float magY = (float)sizeY / extentY;
201 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}", 208 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}",
202 BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY); 209 BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY);
210 float minHeight = float.MaxValue;
203 // Note that sizeX+1 vertices are created since there is land between this and the next region. 211 // Note that sizeX+1 vertices are created since there is land between this and the next region.
204 for (int yy = 0; yy <= sizeY; yy++) 212 for (int yy = 0; yy <= sizeY; yy++)
205 { 213 {
206 for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we got through sizeX + 1 times 214 for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we go around sizeX + 1 times
207 { 215 {
208 int offset = yy * sizeX + xx; 216 int offset = yy * sizeX + xx;
209 // Extend the height from the height from the last row or column 217 // Extend the height with the height from the last row or column
210 if (yy == sizeY) offset -= sizeX; 218 if (yy == sizeY) offset -= sizeX;
211 if (xx == sizeX) offset -= 1; 219 if (xx == sizeX) offset -= 1;
212 float height = heightMap[offset]; 220 float height = heightMap[offset];
221 minHeight = Math.Min(minHeight, height);
213 vertices[verticesCount + 0] = (float)xx * magX + extentBase.X; 222 vertices[verticesCount + 0] = (float)xx * magX + extentBase.X;
214 vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y; 223 vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y;
215 vertices[verticesCount + 2] = height + extentBase.Z; 224 vertices[verticesCount + 2] = height + extentBase.Z;
@@ -222,7 +231,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
222 { 231 {
223 for (int xx = 0; xx < sizeX; xx++) 232 for (int xx = 0; xx < sizeX; xx++)
224 { 233 {
225 int offset = yy * sizeX + xx; 234 int offset = yy * (sizeX + 1) + xx;
226 // Each vertices is presumed to be the upper left corner of a box of two triangles 235 // Each vertices is presumed to be the upper left corner of a box of two triangles
227 indices[indicesCount + 0] = offset; 236 indices[indicesCount + 0] = offset;
228 indices[indicesCount + 1] = offset + 1; 237 indices[indicesCount + 1] = offset + 1;
@@ -233,6 +242,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
233 indicesCount += 6; 242 indicesCount += 6;
234 } 243 }
235 } 244 }
245
236 ret = true; 246 ret = true;
237 } 247 }
238 catch (Exception e) 248 catch (Exception e)