Skip to content

Commit

Permalink
Merge pull request #844 from cesarBLG/multiple-axles-visuals
Browse files Browse the repository at this point in the history
Animate axles separately
  • Loading branch information
cjakeman committed Jul 25, 2023
2 parents 9c9d99e + 3f42c30 commit ded0036
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,8 @@ public float SlipDerivationPercentpS
/// </summary>
public float SlipWarningTresholdPercent { set; get; }

public List<string> AnimatedParts = new List<string>();

/// <summary>
/// Nonparametric constructor of Axle class instance
/// - sets motor parameter to null
Expand Down Expand Up @@ -653,6 +655,12 @@ public void Parse(STFReader stf)
case "weight":
AxleWeightN = 9.81f * stf.ReadFloatBlock(STFReader.UNITS.Mass, null);
break;
case "animatedparts":
foreach (var part in stf.ReadStringBlock("").ToUpper().Replace(" ", "").Split(','))
{
if (part != "") AnimatedParts.Add(part);
}
break;
case "(":
stf.SkipRestOfBlock();
break;
Expand All @@ -664,6 +672,8 @@ public void Copy(Axle other)
WheelRadiusM = other.WheelRadiusM;
InertiaKgm2 = other.InertiaKgm2;
AxleWeightN = other.AxleWeightN;
AnimatedParts.Clear();
AnimatedParts.AddRange(other.AnimatedParts);
}

/// <summary>
Expand Down
114 changes: 70 additions & 44 deletions Source/RunActivity/Viewer3D/RollingStock/MSTSWagonViewer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,10 @@ public class MSTSWagonViewer : TrainCarViewer

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

// Everything else is animated through the shape file.
AnimatedPart RunningGear;
Dictionary<int,AnimatedPart> RunningGears; // List of animated parts linked to every axle
AnimatedPart Pantograph1;
AnimatedPart Pantograph2;
AnimatedPart Pantograph3;
Expand Down Expand Up @@ -313,7 +313,12 @@ public MSTSWagonViewer(Viewer viewer, MSTSWagon car)
if (car.InteriorShapeFileName != null)
InteriorShape = new AnimatedShape(viewer, wagonFolderSlash + car.InteriorShapeFileName + '\0' + wagonFolderSlash, car.WorldPosition, ShapeFlags.Interior, 30.0f);

RunningGear = new AnimatedPart(TrainCarShape);
RunningGears = new Dictionary<int,AnimatedPart>();
for (int i=-1; i<car.LocomotiveAxles.Count; i++)
{
RunningGears[i] = new AnimatedPart(TrainCarShape);
WheelPartIndexes[i] = new List<int>();
}
Pantograph1 = new AnimatedPart(TrainCarShape);
Pantograph2 = new AnimatedPart(TrainCarShape);
Pantograph3 = new AnimatedPart(TrainCarShape);
Expand Down Expand Up @@ -424,6 +429,15 @@ void MatchMatrixToPart(MSTSWagon car, int matrix, int bogieMatrix)
var matrixName = TrainCarShape.SharedShape.MatrixNames[matrix].ToUpper();
// Gate all RunningGearPartIndexes on this!
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;
int? LinkedAxleIndex = null;
for (int i=0; i<car.LocomotiveAxles.Count; i++)
{
if (car.LocomotiveAxles[i].AnimatedParts.Contains(matrixName))
{
LinkedAxleIndex = i;
break;
}
}
if (matrixName.StartsWith("WHEELS") && (matrixName.Length == 7 || matrixName.Length == 8 || matrixName.Length == 9))
{
// 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.
Expand All @@ -441,15 +455,15 @@ void MatchMatrixToPart(MSTSWagon car, int matrix, int bogieMatrix)
if (matrixName.Length == 8 || matrixName.Length == 9)
Int32.TryParse(matrixName.Substring(6, 1), out id);
if (matrixName.Length == 8 || matrixName.Length == 9 || !matrixAnimated)
WheelPartIndexes.Add(matrix);
WheelPartIndexes[LinkedAxleIndex ?? -1].Add(matrix);
else
RunningGear.AddMatrix(matrix);
RunningGears[LinkedAxleIndex ?? (car.LocomotiveAxles.Count > 0 ? 0 : -1)].AddMatrix(matrix);
var pmatrix = TrainCarShape.SharedShape.GetParentMatrix(matrix);
car.AddWheelSet(m.M43, id, pmatrix, matrixName.ToString(), bogie1Axles, bogie2Axles);
}
// Standard wheels are processed above, but wheels used as animated fans that are greater than 3m are processed here.
else
RunningGear.AddMatrix(matrix);
RunningGears[LinkedAxleIndex ?? -1].AddMatrix(matrix);
}
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
{
Expand Down Expand Up @@ -578,7 +592,7 @@ void MatchMatrixToPart(MSTSWagon car, int matrix, int bogieMatrix)
else
{
if (matrixAnimated && matrix != 0)
RunningGear.AddMatrix(matrix);
RunningGears[LinkedAxleIndex ?? (car.LocomotiveAxles.Count > 0 ? 0 : -1)].AddMatrix(matrix);

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

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

if (MSTSWagon.IsDriveable && MSTSWagon.Simulator.UseAdvancedAdhesion && !MSTSWagon.Simulator.Settings.SimpleControlPhysics)
{
var loco = MSTSWagon as MSTSLocomotive;
//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.
// To achieve the same result with other means, without flipping trainset physics, the line should be changed as follows:
// distanceTravelledM = MSTSWagon.WheelSpeedMpS * elapsedTime.ClockSeconds;

distanceTravelledM = ((MSTSWagon.Train != null && MSTSWagon.Train.IsPlayerDriven && ((MSTSLocomotive)MSTSWagon).UsingRearCab) ? -1 : 1) * MSTSWagon.WheelSpeedMpS * elapsedTime.ClockSeconds;
if (Car.EngineType == Orts.Simulation.RollingStocks.TrainCar.EngineTypes.Steam)
distanceTravelledM = ((MSTSWagon.Train != null && MSTSWagon.Train.IsPlayerDriven && loco.UsingRearCab) ? -1 : 1) * MSTSWagon.WheelSpeedMpS * elapsedTime.ClockSeconds;
if (Car.BrakeSkid && !loco.DriveWheelOnlyBrakes) distanceTravelledM = 0;
foreach (var kvp in RunningGears)
{
distanceTravelledDrivenM = ((MSTSWagon.Train != null && MSTSWagon.Train.IsPlayerDriven && ((MSTSLocomotive)MSTSWagon).UsingRearCab) ? -1 : 1) * MSTSWagon.WheelSpeedSlipMpS * elapsedTime.ClockSeconds;
if (!kvp.Value.Empty())
{
var axle = kvp.Key >= 0 && kvp.Key < loco.LocomotiveAxles.Count ? loco.LocomotiveAxles[kvp.Key] : null;
if (axle != null)
//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.
kvp.Value.UpdateLoop(((MSTSWagon.Train != null && MSTSWagon.Train.IsPlayerDriven && loco.UsingRearCab) ? -1 : 1) * axle.AxleSpeedMpS * elapsedTime.ClockSeconds / MathHelper.TwoPi / axle.WheelRadiusM);
else if (AnimationDriveWheelRadiusM > 0.001)
kvp.Value.UpdateLoop(distanceTravelledM / MathHelper.TwoPi / AnimationDriveWheelRadiusM);
}

}
else // Other driveable rolling stocked.
foreach (var kvp in WheelPartIndexes)
{
distanceTravelledDrivenM = ((MSTSWagon.Train != null && MSTSWagon.Train.IsPlayerDriven && ((MSTSLocomotive)MSTSWagon).UsingRearCab) ? -1 : 1) * MSTSWagon.WheelSpeedMpS * elapsedTime.ClockSeconds;
var axle = kvp.Key < loco.LocomotiveAxles.Count && kvp.Key >= 0 ? loco.LocomotiveAxles[kvp.Key] : (Car.EngineType == TrainCar.EngineTypes.Steam ? null : loco.LocomotiveAxles[0]);
Matrix wheelRotationMatrix;
if (axle != null)
{
//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.
wheelRotationMatrix = Matrix.CreateRotationX(((MSTSWagon.Train != null && MSTSWagon.Train.IsPlayerDriven && loco.UsingRearCab) ? -1 : 1) * -axle.AxlePositionRad);
}
else
{
var rotationalDistanceR = distanceTravelledM / AnimationWheelRadiusM; // in radians
WheelRotationR = MathHelper.WrapAngle(WheelRotationR - rotationalDistanceR);
wheelRotationMatrix = Matrix.CreateRotationX(WheelRotationR);
}
foreach (var iMatrix in kvp.Value)
{
TrainCarShape.XNAMatrices[iMatrix] = wheelRotationMatrix * TrainCarShape.SharedShape.Matrices[iMatrix];
}
}
}
else // set values for simple adhesion
{
distanceTravelledM = ((MSTSWagon.IsDriveable && MSTSWagon.Train != null && MSTSWagon.Train.IsPlayerDriven && ((MSTSLocomotive)MSTSWagon).UsingRearCab) ? -1 : 1) * MSTSWagon.SpeedMpS * elapsedTime.ClockSeconds;
distanceTravelledDrivenM = distanceTravelledM;
}

if (Car.BrakeSkid) // if car wheels are skidding because of brakes locking wheels up then stop wheels rotating.
{
// Temporary bug fix (CSantucci)
if (MSTSWagon is MSTSLocomotive loco && loco.DriveWheelOnlyBrakes)
if (Car.BrakeSkid) distanceTravelledM = 0;
foreach (var kvp in RunningGears)
{
distanceTravelledDrivenM = 0.0f;
if (!kvp.Value.Empty() && AnimationDriveWheelRadiusM > 0.001)
kvp.Value.UpdateLoop(distanceTravelledM / MathHelper.TwoPi / AnimationDriveWheelRadiusM);
}
else
// Wheel rotation (animation) - for non-drive wheels in steam locomotives and all wheels in other stock
if (WheelPartIndexes.Count > 0)
{
distanceTravelledM = 0.0f;
distanceTravelledDrivenM = 0.0f;
var rotationalDistanceR = distanceTravelledM / AnimationWheelRadiusM; // in radians
WheelRotationR = MathHelper.WrapAngle(WheelRotationR - rotationalDistanceR);
var wheelRotationMatrix = Matrix.CreateRotationX(WheelRotationR);
foreach (var kvp in WheelPartIndexes)
{
foreach (var iMatrix in kvp.Value)
{
TrainCarShape.XNAMatrices[iMatrix] = wheelRotationMatrix * TrainCarShape.SharedShape.Matrices[iMatrix];
}
}
}
}

// Running gear and drive wheel rotation (animation) in steam locomotives
if (!RunningGear.Empty() && AnimationDriveWheelRadiusM > 0.001)
RunningGear.UpdateLoop(distanceTravelledDrivenM / MathHelper.TwoPi / AnimationDriveWheelRadiusM);


// Wheel rotation (animation) - for non-drive wheels in steam locomotives and all wheels in other stock
if (WheelPartIndexes.Count > 0)
{
var wheelCircumferenceM = MathHelper.TwoPi * AnimationWheelRadiusM;
var rotationalDistanceR = MathHelper.TwoPi * distanceTravelledM / wheelCircumferenceM; // in radians
WheelRotationR = MathHelper.WrapAngle(WheelRotationR - rotationalDistanceR);
var wheelRotationMatrix = Matrix.CreateRotationX(WheelRotationR);
foreach (var iMatrix in WheelPartIndexes)
{
TrainCarShape.XNAMatrices[iMatrix] = wheelRotationMatrix * TrainCarShape.SharedShape.Matrices[iMatrix];
}
}

#if DEBUG_WHEEL_ANIMATION

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

Expand Down

0 comments on commit ded0036

Please sign in to comment.