Saturday, 26 February 2011

UDK Motorsport: Torque curves and engine sound

I have my gear plot. I need to find some way to combine that with the engine's torque curve in order to get the kind of curve Unreal requires. The obvious solution is to use the output of the gear plot as the input of the torque curve.

This is a basic mathematical tool called function composition. The problem is that while the gear plot is a set of linear functions, the torque curve isn't a function at all. So we need to find a function that has roughly the shape of the torque curve we are interested in.

After hours of Googling, I stumbled upon that post which gave me the beginning of the solution: the idea is to use the engine's power curve, which has (partly) the shape of a cubic function.

In order to get a curve resembling our power curve, we will need to do something called curve fitting. I won't extend on how to do the fitting, it's quite trivial with gnuplot. However, keep in mind that you need a few sample points for the fitting to work. Just grab half a dozen points' coordinates along the curve, especially on the upward and downward slopes and at the extremum. Also, if you're using gnuplot to do the fitting, just remember to set the correct range before doing the fitting, or you'll end up with an incorrect curve.

Using some random data inaccurately measured from the 2004 Boxster curve I had on the first post about gears,  I get the following fitted curve (I've made some scaling to get readable power values):

Looks about right. Now, it's easy to retrieve the torque, as the power equals the revs (in rad/s) times the torque. So we just have to divide the power by the revs and we'll get the torque curve:
Let's compare with the original curves:
We're a bit off, but it does look okay (note that the ranges are slightly different on the two graphs). You can also see that the torque curve is getting funky near 0, which is normal, since we're dividing by a value that tends to 0. The post I mentioned earlier does state that this method is unreliable for rotational speeds under 1000 RPM, but in the case of cars, the engine spends very little time under that threshold, so it should be okay.

Now that I have my torque curve as a function I can put stuff into, it becomes easy to get the torque based on the linear speed for each gear:
Note that since the speed is in UU/s, the torque is in NUU rather than in Nm.
And there we finally are! Implementing those curves in Unreal is quite easy. We'll just take 4 points:

  • The origin.
  • The maximum torque.
  • The speed at which the torque reaches 0.
  • The speed at which the torque reaches -100. (No, you can't see that point on the graph above.)
The origin seems to be the same for all gears. For the other points, the OutValue is obviously the same for all gears as well, only the speed changes.  With the curve above, I get the following points:

Gears(1)=(TorqueCurve=(Points=((InVal=0.0,OutVal=7.0,InterpMode=CIM_CurveAuto),(InVal=360.0,OutVal=13.0,InterpMode=CIM_CurveAuto),(InVal=870.0,OutVal=0.0,InterpMode=CIM_CurveAuto),(InVal=961.0,OutVal=-100.0,InterpMode=CIM_CurveAuto))))
Gears(2)=(TorqueCurve=(Points=((InVal=0.0,OutVal=7.0,InterpMode=CIM_CurveAuto),(InVal=580.0,OutVal=13.0,InterpMode=CIM_CurveAuto),(InVal=1400.0,OutVal=0.0,InterpMode=CIM_CurveAuto),(InVal=1538.0,OutVal=-100.0,InterpMode=CIM_CurveAuto))))
Gears(3)=(TorqueCurve=(Points=((InVal=0.0,OutVal=7.0,InterpMode=CIM_CurveAuto),(InVal=835.0,OutVal=13.0,InterpMode=CIM_CurveAuto),(InVal=2000.0,OutVal=0.0,InterpMode=CIM_CurveAuto),(InVal=2200.0,OutVal=-100.0,InterpMode=CIM_CurveAuto))))
Gears(4)=(TorqueCurve=(Points=((InVal=0.0,OutVal=7.0,InterpMode=CIM_CurveAuto),(InVal=1278.0,OutVal=13.0,InterpMode=CIM_CurveAuto),(InVal=3040.0,OutVal=0.0,InterpMode=CIM_CurveAuto),(InVal=3347.0,OutVal=-100.0,InterpMode=CIM_CurveAuto))))
Gears(5)=(TorqueCurve=(Points=((InVal=0.0,OutVal=7.0,InterpMode=CIM_CurveAuto),(InVal=1810.0,OutVal=13.0,InterpMode=CIM_CurveAuto),(InVal=4370.0,OutVal=0.0,InterpMode=CIM_CurveAuto),(InVal=4812.0,OutVal=-100.0,InterpMode=CIM_CurveAuto))))

Note that I've scaled the outvals down as it seemed to provide too much torque as it were. But that is a matter of tweaking I didn't take the time to completely figure out.

This yields the following results:


"Hey, the engine makes some noise!"

Yep, let's quickly talk about that. SVehicle has an AudioComponent property called EngineSound. It's set as follows:

begin object class=AudioComponent Name=CarEngineSound
 SoundCue=SoundCue'A_Vehicle_Scorpion.SoundCues.A_Vehicle_Scorpion_EngineLoop'
end object
EngineSound=CarEngineSound
Components.Add(CarEngineSound);

Then, UDKVehicleSimCar uses its EngineRPMCurve property to change the pitch of the car's engine according to the simulated RPM. As for the torque curve, I'm using one curve per gear (on the video, it's the small graph).
It's very easy to implement since we already have those curves in the gear plot. Being linear, only two points are needed for the curve: one for the origin, one for the max RPM. Note that at the origin, I set OutVal to 1000 rather than 0 as even when the car is stopped, the egine should make some noise.