Utilities
NWH Common provides utility classes for math, geometry, unit conversion, and control systems.
MathUtility
Mathematical operations commonly needed in physics simulations.
Clamping and Wrapping
using NWH.Common.Utility;
// Clamp value between min and max
float clamped = MathUtility.Clamp(value, min, max);
// Clamp01 (between 0 and 1)
float normalized = MathUtility.Clamp01(value);
// Wrap angle to -180 to 180 range
float angle = MathUtility.WrapAngle(angle);
// Wrap value to any range
float wrapped = MathUtility.Wrap(value, min, max);
Interpolation
// Smooth interpolation (similar to Mathf.SmoothDamp)
float smoothed = MathUtility.SmoothStep(from, to, t);
// Inverse lerp with clamping
float t = MathUtility.InverseLerp(a, b, value);
// Remap value from one range to another
float remapped = MathUtility.Remap(value, fromMin, fromMax, toMin, toMax);
Comparison
// Approximately equal with tolerance
bool isEqual = MathUtility.Approximately(a, b, tolerance);
// Check if value within range
bool inRange = MathUtility.InRange(value, min, max);
// Sign function (-1, 0, or 1)
int sign = MathUtility.Sign(value);
Common Physics Calculations
// Calculate spring force
float springForce = MathUtility.SpringForce(
currentLength,
restLength,
springRate,
damping,
velocity
);
// Calculate damper force
float damperForce = MathUtility.DamperForce(
velocity,
damperRate
);
// Apply exponential smoothing
float smoothed = MathUtility.ExponentialSmooth(
currentValue,
targetValue,
smoothTime,
deltaTime
);
GeomUtility
Geometry calculations for physics and collision detection.
Distance Calculations
using NWH.Common.Utility;
// Distance from point to line segment
float distance = GeomUtility.DistanceToLineSegment(
point,
lineStart,
lineEnd,
out Vector3 closestPoint
);
// Distance from point to plane
float distance = GeomUtility.DistanceToPlane(
point,
planeNormal,
planePoint
);
// Closest point on line segment
Vector3 closest = GeomUtility.ClosestPointOnLineSegment(
point,
lineStart,
lineEnd
);
Intersection Tests
// Line-plane intersection
bool intersects = GeomUtility.LinePlaneIntersection(
lineStart,
lineEnd,
planeNormal,
planePoint,
out Vector3 intersectionPoint
);
// Ray-sphere intersection
bool intersects = GeomUtility.RaySphereIntersection(
rayOrigin,
rayDirection,
sphereCenter,
sphereRadius,
out float distance
);
// AABB (box) intersection
bool intersects = GeomUtility.AABBIntersection(
box1Min,
box1Max,
box2Min,
box2Max
);
Projections
// Project point onto plane
Vector3 projected = GeomUtility.ProjectPointOnPlane(
point,
planeNormal,
planePoint
);
// Project vector onto another vector
Vector3 projected = GeomUtility.ProjectVector(
vector,
ontoVector
);
// Project point onto line
Vector3 projected = GeomUtility.ProjectPointOnLine(
point,
lineStart,
lineDirection
);
Area and Volume
// Triangle area
float area = GeomUtility.TriangleArea(
vertexA,
vertexB,
vertexC
);
// Polygon area (2D)
float area = GeomUtility.PolygonArea(vertices);
// Sphere volume
float volume = GeomUtility.SphereVolume(radius);
// Box volume
float volume = GeomUtility.BoxVolume(size);
UnitConverter
Convert between different unit systems.
Speed Conversions
using NWH.Common.Utility;
// m/s to km/h
float kmh = UnitConverter.MsToKmh(metersPerSecond);
// m/s to mph
float mph = UnitConverter.MsToMph(metersPerSecond);
// km/h to m/s
float ms = UnitConverter.KmhToMs(kilometersPerHour);
// mph to m/s
float ms = UnitConverter.MphToMs(milesPerHour);
Torque and Power
// Nm to lb-ft
float lbft = UnitConverter.NmToLbft(newtonMeters);
// lb-ft to Nm
float nm = UnitConverter.LbftToNm(poundFeet);
// kW to HP
float hp = UnitConverter.KwToHp(kilowatts);
// HP to kW
float kw = UnitConverter.HpToKw(horsepower);
// Calculate power from torque and RPM
float power = UnitConverter.PowerFromTorqueAndRpm(torque, rpm);
Weight and Mass
// kg to lbs
float lbs = UnitConverter.KgToLbs(kilograms);
// lbs to kg
float kg = UnitConverter.LbsToKg(pounds);
Distance
// meters to feet
float feet = UnitConverter.MetersToFeet(meters);
// feet to meters
float meters = UnitConverter.FeetToMeters(feet);
// meters to miles
float miles = UnitConverter.MetersToMiles(meters);
// miles to meters
float meters = UnitConverter.MilesToMeters(miles);
Temperature
// Celsius to Fahrenheit
float f = UnitConverter.CelsiusToFahrenheit(celsius);
// Fahrenheit to Celsius
float c = UnitConverter.FahrenheitToCelsius(fahrenheit);
// Celsius to Kelvin
float k = UnitConverter.CelsiusToKelvin(celsius);
Usage Example
public class Speedometer : MonoBehaviour
{
public Rigidbody vehicle;
public Text speedText;
public bool useImperialUnits = false;
void Update()
{
float speed = vehicle.velocity.magnitude;
if (useImperialUnits)
{
float mph = UnitConverter.MsToMph(speed);
speedText.text = $"{mph:F1} mph";
}
else
{
float kmh = UnitConverter.MsToKmh(speed);
speedText.text = $"{kmh:F1} km/h";
}
}
}
PIDController
Proportional-Integral-Derivative controller for smooth control systems.
Overview
PID controllers are used for:
- Smooth throttle/brake control
- Cruise control systems
- Automatic steering
- Any feedback control system
Setup
using NWH.Common.Utility;
// Create PID controller
PIDController pid = new PIDController();
// Configure gains
pid.Kp = 1.0f; // Proportional gain
pid.Ki = 0.1f; // Integral gain
pid.Kd = 0.05f; // Derivative gain
// Optional: Set output limits
pid.outputMin = -1f;
pid.outputMax = 1f;
Usage
void FixedUpdate()
{
float targetSpeed = 20f; // m/s
float currentSpeed = rigidbody.velocity.magnitude;
// Calculate control output
float throttle = pid.Update(
targetSpeed,
currentSpeed,
Time.fixedDeltaTime
);
// Apply throttle to vehicle
ApplyThrottle(throttle);
}
Tuning PID Gains
Proportional (Kp):
- Affects immediate response
- Higher = more aggressive, may oscillate
- Start with 1.0, increase if too slow
Integral (Ki):
- Eliminates steady-state error
- Higher = faster elimination, may overshoot
- Start with 0, increase if error persists
Derivative (Kd):
- Reduces overshoot and oscillation
- Higher = more damping, may be sluggish
- Start with 0, increase if oscillating
Tuning Process:
- Set all to 0
- Increase Kp until system responds
- Add Kd to reduce oscillation
- Add Ki if steady-state error exists
Reset
Reset integral accumulation when setpoint changes:
pid.Reset();
target = newTarget;
Example: Cruise Control
public class CruiseControl : MonoBehaviour
{
private PIDController speedPID;
public float cruiseSpeed = 25f; // m/s
public bool enabled = false;
void Start()
{
speedPID = new PIDController
{
Kp = 0.5f,
Ki = 0.05f,
Kd = 0.1f,
outputMin = 0f,
outputMax = 1f
};
}
void FixedUpdate()
{
if (!enabled) return;
float currentSpeed = GetComponent<Rigidbody>().velocity.magnitude;
float throttle = speedPID.Update(
cruiseSpeed,
currentSpeed,
Time.fixedDeltaTime
);
ApplyThrottle(throttle);
}
public void SetCruiseSpeed(float speed)
{
cruiseSpeed = speed;
speedPID.Reset();
}
}
Common Usage Patterns
Speed Display with Units
public class SpeedDisplay : MonoBehaviour
{
public enum SpeedUnit { MetersPerSecond, KilometersPerHour, MilesPerHour }
public SpeedUnit displayUnit = SpeedUnit.KilometersPerHour;
public string GetSpeedText(float speedMs)
{
switch (displayUnit)
{
case SpeedUnit.MetersPerSecond:
return $"{speedMs:F1} m/s";
case SpeedUnit.KilometersPerHour:
return $"{UnitConverter.MsToKmh(speedMs):F0} km/h";
case SpeedUnit.MilesPerHour:
return $"{UnitConverter.MsToMph(speedMs):F0} mph";
default:
return $"{speedMs:F1} m/s";
}
}
}
Smooth Camera Follow
public class SmoothFollow : MonoBehaviour
{
public Transform target;
public float smoothTime = 0.3f;
void LateUpdate()
{
Vector3 targetPosition = target.position + offset;
transform.position = MathUtility.ExponentialSmooth(
transform.position,
targetPosition,
smoothTime,
Time.deltaTime
);
}
}
Ground Detection
public class GroundCheck : MonoBehaviour
{
public float rayLength = 1f;
public bool IsGrounded()
{
RaycastHit hit;
bool grounded = Physics.Raycast(
transform.position,
-transform.up,
out hit,
rayLength
);
if (grounded)
{
float distance = GeomUtility.DistanceToPlane(
transform.position,
hit.normal,
hit.point
);
return distance < 0.1f;
}
return false;
}
}
Performance Notes
- MathUtility - All methods are static, no allocations
- GeomUtility - Some methods use
outparameters to avoid allocations - UnitConverter - Simple multiplications, very fast
- PIDController - Lightweight, suitable for many instances
API Reference
For detailed API documentation, refer to the complete API reference in the navigation menu:
- <xref:NWH.Common.Utility.MathUtility>
- GeomUtility
- UnitConverter
- PIDController
See Also
- Input System - For implementing input-based control systems with PIDController
- Camera System - For smooth camera follow techniques using MathUtility
- Variable Center of Mass - Related physics calculations
- Shifting Origin - Large world coordinate systems with distance calculations