Skip to content

Commit ded0036

Browse files
authored
Merge pull request #844 from cesarBLG/multiple-axles-visuals
Animate axles separately
2 parents 9c9d99e + 3f42c30 commit ded0036

File tree

2 files changed

+80
-44
lines changed
  • Source
    • Orts.Simulation/Simulation/RollingStocks/SubSystems/PowerTransmissions
    • RunActivity/Viewer3D/RollingStock

2 files changed

+80
-44
lines changed

Source/Orts.Simulation/Simulation/RollingStocks/SubSystems/PowerTransmissions/Axle.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,8 @@ public float SlipDerivationPercentpS
613613
/// </summary>
614614
public float SlipWarningTresholdPercent { set; get; }
615615

616+
public List<string> AnimatedParts = new List<string>();
617+
616618
/// <summary>
617619
/// Nonparametric constructor of Axle class instance
618620
/// - sets motor parameter to null
@@ -653,6 +655,12 @@ public void Parse(STFReader stf)
653655
case "weight":
654656
AxleWeightN = 9.81f * stf.ReadFloatBlock(STFReader.UNITS.Mass, null);
655657
break;
658+
case "animatedparts":
659+
foreach (var part in stf.ReadStringBlock("").ToUpper().Replace(" ", "").Split(','))
660+
{
661+
if (part != "") AnimatedParts.Add(part);
662+
}
663+
break;
656664
case "(":
657665
stf.SkipRestOfBlock();
658666
break;
@@ -664,6 +672,8 @@ public void Copy(Axle other)
664672
WheelRadiusM = other.WheelRadiusM;
665673
InertiaKgm2 = other.InertiaKgm2;
666674
AxleWeightN = other.AxleWeightN;
675+
AnimatedParts.Clear();
676+
AnimatedParts.AddRange(other.AnimatedParts);
667677
}
668678

669679
/// <summary>

Source/RunActivity/Viewer3D/RollingStock/MSTSWagonViewer.cs

Lines changed: 70 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,10 @@ public class MSTSWagonViewer : TrainCarViewer
5959

6060
// Wheels are rotated by hand instead of in the shape file.
6161
float WheelRotationR;
62-
List<int> WheelPartIndexes = new List<int>();
62+
Dictionary<int,List<int>> WheelPartIndexes = new Dictionary<int,List<int>>(); // List of wheels attached to each axle
6363

6464
// Everything else is animated through the shape file.
65-
AnimatedPart RunningGear;
65+
Dictionary<int,AnimatedPart> RunningGears; // List of animated parts linked to every axle
6666
AnimatedPart Pantograph1;
6767
AnimatedPart Pantograph2;
6868
AnimatedPart Pantograph3;
@@ -313,7 +313,12 @@ from data in effect.Value
313313
if (car.InteriorShapeFileName != null)
314314
InteriorShape = new AnimatedShape(viewer, wagonFolderSlash + car.InteriorShapeFileName + '\0' + wagonFolderSlash, car.WorldPosition, ShapeFlags.Interior, 30.0f);
315315

316-
RunningGear = new AnimatedPart(TrainCarShape);
316+
RunningGears = new Dictionary<int,AnimatedPart>();
317+
for (int i=-1; i<car.LocomotiveAxles.Count; i++)
318+
{
319+
RunningGears[i] = new AnimatedPart(TrainCarShape);
320+
WheelPartIndexes[i] = new List<int>();
321+
}
317322
Pantograph1 = new AnimatedPart(TrainCarShape);
318323
Pantograph2 = new AnimatedPart(TrainCarShape);
319324
Pantograph3 = new AnimatedPart(TrainCarShape);
@@ -424,6 +429,15 @@ void MatchMatrixToPart(MSTSWagon car, int matrix, int bogieMatrix)
424429
var matrixName = TrainCarShape.SharedShape.MatrixNames[matrix].ToUpper();
425430
// Gate all RunningGearPartIndexes on this!
426431
var matrixAnimated = TrainCarShape.SharedShape.Animations != null && TrainCarShape.SharedShape.Animations.Count > 0 && TrainCarShape.SharedShape.Animations[0].anim_nodes.Count > matrix && TrainCarShape.SharedShape.Animations[0].anim_nodes[matrix].controllers.Count > 0;
432+
int? LinkedAxleIndex = null;
433+
for (int i=0; i<car.LocomotiveAxles.Count; i++)
434+
{
435+
if (car.LocomotiveAxles[i].AnimatedParts.Contains(matrixName))
436+
{
437+
LinkedAxleIndex = i;
438+
break;
439+
}
440+
}
427441
if (matrixName.StartsWith("WHEELS") && (matrixName.Length == 7 || matrixName.Length == 8 || matrixName.Length == 9))
428442
{
429443
// Standard WHEELS length would be 8 to test for WHEELS11. Came across WHEELS tag that used a period(.) between the last 2 numbers, changing max length to 9.
@@ -441,15 +455,15 @@ void MatchMatrixToPart(MSTSWagon car, int matrix, int bogieMatrix)
441455
if (matrixName.Length == 8 || matrixName.Length == 9)
442456
Int32.TryParse(matrixName.Substring(6, 1), out id);
443457
if (matrixName.Length == 8 || matrixName.Length == 9 || !matrixAnimated)
444-
WheelPartIndexes.Add(matrix);
458+
WheelPartIndexes[LinkedAxleIndex ?? -1].Add(matrix);
445459
else
446-
RunningGear.AddMatrix(matrix);
460+
RunningGears[LinkedAxleIndex ?? (car.LocomotiveAxles.Count > 0 ? 0 : -1)].AddMatrix(matrix);
447461
var pmatrix = TrainCarShape.SharedShape.GetParentMatrix(matrix);
448462
car.AddWheelSet(m.M43, id, pmatrix, matrixName.ToString(), bogie1Axles, bogie2Axles);
449463
}
450464
// Standard wheels are processed above, but wheels used as animated fans that are greater than 3m are processed here.
451465
else
452-
RunningGear.AddMatrix(matrix);
466+
RunningGears[LinkedAxleIndex ?? -1].AddMatrix(matrix);
453467
}
454468
else if (matrixName.StartsWith("BOGIE") && matrixName.Length <= 6) //BOGIE1 is valid, BOGIE11 is not, it is used by some modelers to indicate this is part of bogie1
455469
{
@@ -578,7 +592,7 @@ void MatchMatrixToPart(MSTSWagon car, int matrix, int bogieMatrix)
578592
else
579593
{
580594
if (matrixAnimated && matrix != 0)
581-
RunningGear.AddMatrix(matrix);
595+
RunningGears[LinkedAxleIndex ?? (car.LocomotiveAxles.Count > 0 ? 0 : -1)].AddMatrix(matrix);
582596

583597
for (var i = 0; i < TrainCarShape.Hierarchy.Length; i++)
584598
if (TrainCarShape.Hierarchy[i] == matrix)
@@ -709,68 +723,80 @@ private void UpdateAnimation(RenderFrame frame, ElapsedTime elapsedTime)
709723
{
710724

711725
float distanceTravelledM = 0.0f; // Distance travelled by non-driven wheels
712-
float distanceTravelledDrivenM = 0.0f; // Distance travelled by driven wheels
713726
float AnimationWheelRadiusM = MSTSWagon.WheelRadiusM; // Radius of non driven wheels
714727
float AnimationDriveWheelRadiusM = MSTSWagon.DriverWheelRadiusM; // Radius of driven wheels
715728

716729
if (MSTSWagon.IsDriveable && MSTSWagon.Simulator.UseAdvancedAdhesion && !MSTSWagon.Simulator.Settings.SimpleControlPhysics)
717730
{
731+
var loco = MSTSWagon as MSTSLocomotive;
718732
//TODO: next code line has been modified to flip trainset physics in order to get viewing direction coincident with loco direction when using rear cab.
719733
// To achieve the same result with other means, without flipping trainset physics, the line should be changed as follows:
720734
// distanceTravelledM = MSTSWagon.WheelSpeedMpS * elapsedTime.ClockSeconds;
721-
722-
distanceTravelledM = ((MSTSWagon.Train != null && MSTSWagon.Train.IsPlayerDriven && ((MSTSLocomotive)MSTSWagon).UsingRearCab) ? -1 : 1) * MSTSWagon.WheelSpeedMpS * elapsedTime.ClockSeconds;
723-
if (Car.EngineType == Orts.Simulation.RollingStocks.TrainCar.EngineTypes.Steam)
735+
distanceTravelledM = ((MSTSWagon.Train != null && MSTSWagon.Train.IsPlayerDriven && loco.UsingRearCab) ? -1 : 1) * MSTSWagon.WheelSpeedMpS * elapsedTime.ClockSeconds;
736+
if (Car.BrakeSkid && !loco.DriveWheelOnlyBrakes) distanceTravelledM = 0;
737+
foreach (var kvp in RunningGears)
724738
{
725-
distanceTravelledDrivenM = ((MSTSWagon.Train != null && MSTSWagon.Train.IsPlayerDriven && ((MSTSLocomotive)MSTSWagon).UsingRearCab) ? -1 : 1) * MSTSWagon.WheelSpeedSlipMpS * elapsedTime.ClockSeconds;
739+
if (!kvp.Value.Empty())
740+
{
741+
var axle = kvp.Key >= 0 && kvp.Key < loco.LocomotiveAxles.Count ? loco.LocomotiveAxles[kvp.Key] : null;
742+
if (axle != null)
743+
//TODO: next code line has been modified to flip trainset physics in order to get viewing direction coincident with loco direction when using rear cab.
744+
kvp.Value.UpdateLoop(((MSTSWagon.Train != null && MSTSWagon.Train.IsPlayerDriven && loco.UsingRearCab) ? -1 : 1) * axle.AxleSpeedMpS * elapsedTime.ClockSeconds / MathHelper.TwoPi / axle.WheelRadiusM);
745+
else if (AnimationDriveWheelRadiusM > 0.001)
746+
kvp.Value.UpdateLoop(distanceTravelledM / MathHelper.TwoPi / AnimationDriveWheelRadiusM);
747+
}
748+
726749
}
727-
else // Other driveable rolling stocked.
750+
foreach (var kvp in WheelPartIndexes)
728751
{
729-
distanceTravelledDrivenM = ((MSTSWagon.Train != null && MSTSWagon.Train.IsPlayerDriven && ((MSTSLocomotive)MSTSWagon).UsingRearCab) ? -1 : 1) * MSTSWagon.WheelSpeedMpS * elapsedTime.ClockSeconds;
752+
var axle = kvp.Key < loco.LocomotiveAxles.Count && kvp.Key >= 0 ? loco.LocomotiveAxles[kvp.Key] : (Car.EngineType == TrainCar.EngineTypes.Steam ? null : loco.LocomotiveAxles[0]);
753+
Matrix wheelRotationMatrix;
754+
if (axle != null)
755+
{
756+
//TODO: next code line has been modified to flip trainset physics in order to get viewing direction coincident with loco direction when using rear cab.
757+
wheelRotationMatrix = Matrix.CreateRotationX(((MSTSWagon.Train != null && MSTSWagon.Train.IsPlayerDriven && loco.UsingRearCab) ? -1 : 1) * -axle.AxlePositionRad);
758+
}
759+
else
760+
{
761+
var rotationalDistanceR = distanceTravelledM / AnimationWheelRadiusM; // in radians
762+
WheelRotationR = MathHelper.WrapAngle(WheelRotationR - rotationalDistanceR);
763+
wheelRotationMatrix = Matrix.CreateRotationX(WheelRotationR);
764+
}
765+
foreach (var iMatrix in kvp.Value)
766+
{
767+
TrainCarShape.XNAMatrices[iMatrix] = wheelRotationMatrix * TrainCarShape.SharedShape.Matrices[iMatrix];
768+
}
730769
}
731770
}
732771
else // set values for simple adhesion
733772
{
734773
distanceTravelledM = ((MSTSWagon.IsDriveable && MSTSWagon.Train != null && MSTSWagon.Train.IsPlayerDriven && ((MSTSLocomotive)MSTSWagon).UsingRearCab) ? -1 : 1) * MSTSWagon.SpeedMpS * elapsedTime.ClockSeconds;
735-
distanceTravelledDrivenM = distanceTravelledM;
736-
}
737-
738-
if (Car.BrakeSkid) // if car wheels are skidding because of brakes locking wheels up then stop wheels rotating.
739-
{
740-
// Temporary bug fix (CSantucci)
741-
if (MSTSWagon is MSTSLocomotive loco && loco.DriveWheelOnlyBrakes)
774+
if (Car.BrakeSkid) distanceTravelledM = 0;
775+
foreach (var kvp in RunningGears)
742776
{
743-
distanceTravelledDrivenM = 0.0f;
777+
if (!kvp.Value.Empty() && AnimationDriveWheelRadiusM > 0.001)
778+
kvp.Value.UpdateLoop(distanceTravelledM / MathHelper.TwoPi / AnimationDriveWheelRadiusM);
744779
}
745-
else
780+
// Wheel rotation (animation) - for non-drive wheels in steam locomotives and all wheels in other stock
781+
if (WheelPartIndexes.Count > 0)
746782
{
747-
distanceTravelledM = 0.0f;
748-
distanceTravelledDrivenM = 0.0f;
783+
var rotationalDistanceR = distanceTravelledM / AnimationWheelRadiusM; // in radians
784+
WheelRotationR = MathHelper.WrapAngle(WheelRotationR - rotationalDistanceR);
785+
var wheelRotationMatrix = Matrix.CreateRotationX(WheelRotationR);
786+
foreach (var kvp in WheelPartIndexes)
787+
{
788+
foreach (var iMatrix in kvp.Value)
789+
{
790+
TrainCarShape.XNAMatrices[iMatrix] = wheelRotationMatrix * TrainCarShape.SharedShape.Matrices[iMatrix];
791+
}
792+
}
749793
}
750794
}
751795

752-
// Running gear and drive wheel rotation (animation) in steam locomotives
753-
if (!RunningGear.Empty() && AnimationDriveWheelRadiusM > 0.001)
754-
RunningGear.UpdateLoop(distanceTravelledDrivenM / MathHelper.TwoPi / AnimationDriveWheelRadiusM);
755-
756-
757-
// Wheel rotation (animation) - for non-drive wheels in steam locomotives and all wheels in other stock
758-
if (WheelPartIndexes.Count > 0)
759-
{
760-
var wheelCircumferenceM = MathHelper.TwoPi * AnimationWheelRadiusM;
761-
var rotationalDistanceR = MathHelper.TwoPi * distanceTravelledM / wheelCircumferenceM; // in radians
762-
WheelRotationR = MathHelper.WrapAngle(WheelRotationR - rotationalDistanceR);
763-
var wheelRotationMatrix = Matrix.CreateRotationX(WheelRotationR);
764-
foreach (var iMatrix in WheelPartIndexes)
765-
{
766-
TrainCarShape.XNAMatrices[iMatrix] = wheelRotationMatrix * TrainCarShape.SharedShape.Matrices[iMatrix];
767-
}
768-
}
769-
770796
#if DEBUG_WHEEL_ANIMATION
771797

772798
Trace.TraceInformation("========================== Debug Animation in MSTSWagonViewer.cs ==========================================");
773-
Trace.TraceInformation("Slip speed - Car ID: {0} WheelDistance: {1} SlipWheelDistance: {2}", Car.CarID, distanceTravelledM, distanceTravelledDrivenM);
799+
Trace.TraceInformation("Slip speed - Car ID: {0} WheelDistance: {1}", Car.CarID, distanceTravelledM);
774800
Trace.TraceInformation("Wag Speed - Wheelspeed: {0} Slip: {1} Train: {2}", MSTSWagon.WheelSpeedMpS, MSTSWagon.WheelSpeedSlipMpS, MSTSWagon.SpeedMpS);
775801
Trace.TraceInformation("Wheel Radius - DriveWheel: {0} NonDriveWheel: {1}", AnimationDriveWheelRadiusM, AnimationWheelRadiusM);
776802

0 commit comments

Comments
 (0)