Using Hinge Joints for Wheels
This example uses Newton custom hinge joints. It is based on our Box2D Smart Pascal chassis that you can view in motion here. We leave you to experiment with ramps. For success with the steps below, you need to have installed GLScene and GLSceneLCL_NGD.
It is handy to give the ground a height of 1 and Position.Y of -1. This brings the top of the ground to Y = -0.5, and means that a cube with default side length 1 or a cylinder of default radius 0.5 (added at the origin by default) will be resting on the ground.
- Start a new form-based application in Lazarus. Save all, saving the project as Wheels and the unit as uWheels.
- Copy newton.dll and dJointLibrary.dll from GLSceneLCL\external to the project folder.
- Select menu item Project > Project Inspector... and add GLSceneLCL_NGD as a new requirement.
- Add to the form from the GLScene tab a GLScene, GLSceneViewer, GLCadencer and GLNGDManager.
- Drag the bottom right corner of the form and GLSceneViewer to give the scene a reasonable size.
- Double click on the GLScene1 icon to obtain the GLScene Editor. Click on Scene objects then on the top right icon to add a camera. Add also to Scene objects two cubes, four cylinders and a light source.
- Use the Object Inspector to change the names of the cubes to Ground and Chassis. Change the names of the cylinders to RearLeft, RearRight, FrontLeft and FrontRight.
- Use the Object Inspector to change the properties of Ground. Change its CubeDepth and CubeWidth to 20 and its Position.Y to -1. Click on the Behaviours ellipsis, then on the + icon of the pop-up and add a NGD Static behaviour. Select the created behaviour and select GLNGDManager1 as its manager.
- Use the Object Inspector to change the properties of Chassis. Change its CubeDepth 1.5, CubeHeight to 0.4 and CubeWidth to 2.5. Change its Position.X to 0.7. Click on the Behaviours ellipsis, click on the + icon of the pop-up and add a NGD Dynamic behaviour. Select the created behaviour and select GLNGDManager1 as its manager.
- Use the Object Inspector to change the properties of the cylinders. For each, change its Height property to 0.2 and its PitchAngle to 90. Click on the Behaviours ellipsis, click on the + icon of the pop-up and add a NGD Dynamic behaviour. Select the created behaviour and select GLNGDManager1 as its manager and Torque.Z to -0.5 (for a four-wheel drive). Change Position.X for the front wheels to 1.4, Position.Z for the left wheels to -1 and for the front wheels to 1.
- Use the Object Inspector to add four joints. Select nj_CustomHinge for the JointType of each and set the MaxAngle for CustomHingeOptions to 720. Select Chassis for the ParentObject of each and a different cylinder for the ChildObject of each. Set the CustomHingeOption PinDirection.Z of each to 1. Set the CustomHingeOption PivotPoints of each joint to be the same as the Position of the ChildObject cylinder, so that, for example, for the joint to the left rear wheel PivotPoint.X and PivotPoint.Y are 0 and PivotPoint.Z is -1.
- Use the Object Inspector to change Y and Z coordinates of the camera's position to 3 and 15, respectively. Change the X, Y, and Z coordinates of the light source position to -10, 5 and 2, respectively.
-
Set the Camera property of the GLSceneViewer1 to GLCamera1 and the Scene property of GLCadencer1 to GLScene1.
Our text view of the form is now as follows
object Form1: TForm1 Left = 607 Height = 521 Top = 182 Width = 721 Caption = 'Form1' ClientHeight = 521 ClientWidth = 721 OnCreate = FormCreate LCLVersion = '1.6.0.4' object GLSceneViewer1: TGLSceneViewer Left = 32 Height = 402 Top = 112 Width = 644 Camera = GLCamera1 FieldOfView = 152.06169128418 TabOrder = 0 end object GLScene1: TGLScene left = 40 top = 23 object GLCamera1: TGLCamera TagFloat = 0 DepthOfView = 100 FocalLength = 50 TargetObject = Ground Position.Coordinates = { 0000000000004040000070410000803F } end object Ground: TGLCube TagFloat = 0 PitchAngle = 0 Position.Coordinates = { 00000000000080BF000000000000803F } RollAngle = 0 TurnAngle = 0 BehavioursData = { 0458434F4C02010201060C54474C4E47445374617469630200060A4E47442053 746174696302000201060D474C4E47444D616E61676572310800090500000000 000AD7A3F83F0600 } CubeSize = { 0000A0410000803F0000A041 } end object GLLightSource1: TGLLightSource TagFloat = 0 ConstAttenuation = 1 LinearAttenuation = 0 QuadraticAttenuation = 0 Position.Coordinates = { 000020C10000A040000000400000803F } SpotCutOff = 180 SpotExponent = 0 end object RearLeft: TGLCylinder TagFloat = 0 Direction.Coordinates = { 000000000000803F0000000000000000 } PitchAngle = 90 Position.Coordinates = { 0000000000000000000080BF0000803F } RollAngle = 0 TurnAngle = 0 Up.Coordinates = { 0000000000000000FFFF7FBF00000000 } BottomRadius = 0.5 Height = 0.200000002980232 TopRadius = 0.5 BehavioursData = { 0458434F4C02010201060D54474C4E474444796E616D69630200060B4E474420 44796E616D696302000201060D474C4E47444D616E6167657231080009050000 0000000AD7A3F83F0600020109050000000000CDCCCCFB3F0500000000000000 80FF3F0905000000000000000000000200080200090000000000000000000000 BF000000000200090000000000000000000000000000803F020008 } end object Chassis: TGLCube TagFloat = 0 PitchAngle = 0 Position.Coordinates = { 3333333F00000000000000000000803F } RollAngle = 0 TurnAngle = 0 BehavioursData = { 0458434F4C02010201060D54474C4E474444796E616D69630200060B4E474420 44796E616D696302000201060D474C4E47444D616E6167657231080009050000 0000000AD7A3F83F0600020109050000000000CDCCCCFB3F0500000000000000 80FF3F0905000000000000000000000200080200080200090000000000000000 000000000000803F020008 } CubeSize = { 00002040CDCCCC3E0000C03F } end object RearRight: TGLCylinder TagFloat = 0 Direction.Coordinates = { 000000000000803F0000000000000000 } PitchAngle = 90 Position.Coordinates = { 00000000000000000000803F0000803F } RollAngle = 0 TurnAngle = 0 Up.Coordinates = { 0000000000000000000080BF00000000 } BottomRadius = 0.5 Height = 0.200000002980232 TopRadius = 0.5 BehavioursData = { 0458434F4C02010201060D54474C4E474444796E616D69630200060B4E474420 44796E616D696302000201060D474C4E47444D616E6167657231080009050000 0000000AD7A3F83F0600020109050000000000CDCCCCFB3F0500000000000000 80FF3F0905000000000000000000000200080200090000000000000000000000 BF000000000200090000000000000000000000000000803F020008 } end object FrontLeft: TGLCylinder TagFloat = 0 Direction.Coordinates = { 000000000000803F0000000000000000 } PitchAngle = 90 Position.Coordinates = { 3333B33F00000000000080BF0000803F } RollAngle = 0 TurnAngle = 0 Up.Coordinates = { 0000000000000000000080BF00000000 } BottomRadius = 0.5 Height = 0.200000002980232 TopRadius = 0.5 BehavioursData = { 0458434F4C02010201060D54474C4E474444796E616D69630200060B4E474444 796E616D69633302000201060D474C4E47444D616E6167657231080009050000 0000000AD7A3F83F0600020109050000000000CDCCCCFB3F0500000000000000 80FF3F0905000000000000000000000200080200090000000000000000000000 BF000000000200090000000000000000000000000000803F020008 } end object FrontRight: TGLCylinder TagFloat = 0 Direction.Coordinates = { 000000000000803F0000000000000000 } PitchAngle = 90 Position.Coordinates = { 3333B33F000000000000803F0000803F } RollAngle = 0 TurnAngle = 0 Up.Coordinates = { 0000000000000000000080BF00000000 } BottomRadius = 0.5 Height = 0.200000002980232 TopRadius = 0.5 BehavioursData = { 0458434F4C02010201060D54474C4E474444796E616D69630200060B4E474444 796E616D69633402000201060D474C4E47444D616E6167657231080009050000 0000000AD7A3F83F0600020109050000000000CDCCCCFB3F0500000000000000 80FF3F0905000000000000000000000200080200090000000000000000000000 BF000000000200090000000000000000000000000000803F020008 } end end object GLCadencer1: TGLCadencer Scene = GLScene1 MaxDeltaTime = 0 MinDeltaTime = 0 FixedDeltaTime = 0 OnProgress = GLCadencer1Progress left = 96 top = 23 end object GLNGDManager1: TGLNGDManager NewtonSurfaceItem = <> NewtonSurfacePair = <> NewtonJoint = < item CustomHingeOptions.PivotPoint.Coordinates = { 0000000000000000000080BF0000803F } CustomHingeOptions.PinDirection.Coordinates = { 00000000000000000000803F00000000 } CustomHingeOptions.MinAngle = 0 CustomHingeOptions.MaxAngle = 720 JointType = nj_CustomHinge ParentObject = Chassis ChildObject = RearLeft end item CustomHingeOptions.PivotPoint.Coordinates = { 00000000000000000000803F0000803F } CustomHingeOptions.PinDirection.Coordinates = { 00000000000000000000803F00000000 } CustomHingeOptions.MinAngle = 0 CustomHingeOptions.MaxAngle = 720 JointType = nj_CustomHinge ParentObject = Chassis ChildObject = RearRight end item CustomHingeOptions.PivotPoint.Coordinates = { 3333B33F00000000000080BF0000803F } CustomHingeOptions.PinDirection.Coordinates = { 00000000000000000000803F00000000 } CustomHingeOptions.MinAngle = 0 CustomHingeOptions.MaxAngle = 720 JointType = nj_CustomHinge ParentObject = Chassis ChildObject = FrontLeft end item CustomHingeOptions.PivotPoint.Coordinates = { 3333B33F000000000000803F0000803F } CustomHingeOptions.PinDirection.Coordinates = { 00000000000000000000803F00000000 } CustomHingeOptions.MinAngle = 0 CustomHingeOptions.MaxAngle = 720 JointType = nj_CustomHinge ParentObject = Chassis ChildObject = FrontRight end> left = 152 top = 23 end end
- Remove the redundant GLBaseClasses from the uses clause.
-
Double click in the OnProgress event of GLCadencer1 and paste into the created procedure this line:
GLNGDManager1.Step(deltaTime);
-
Execute the application.
When executing the application, you may receive an error message that WGL_ARB_pbuffer support is required. Check the box with caption Ignore this exception type and press the button to continue. If a wheel buckles, check that its Direction.Y is 1 and Direction.X and Direction.Z are 0. Up.Z should be -1 and Up.X and Up.Y should be 0. The joint type must be nj_CustomHinge and you must have set the properties for CustomHingeOptions (and not, for example HingeOptions).The chassis should move to the right for two revolutions of each wheel.
You can provide a climbable ramp with a cube that has a NGD static behaviour, CubeDepth = 4, CubeHeight = 0.1, CubeWidth = 2, RollAngle = 8, Position.X = 4, Position.Y = -0.5 and Position.Z = 8.
You can make the chassis turn left by applying a force to the right wheel. This can be done in the Object Inspector or in code with a line such as TGLNGDDynamic(FrontRight.Behaviours[0]).Force.X := 5;