Hello,
I’ve been experimenting with the Bullet Vehicle demo from the Panda tutorials. However, a lot of the settings are a mystery to me, such as chassis connection point and wheel direction. Is there a way to calculate these values? In the below code the vehicle only moves very slowly almost on the spot, so I’m assuming one of the driven wheels is going in the wrong direction or something is amiss. Does anybody have experience of this?
#include "pandaFramework.h"
#include "windowFramework.h"
#include "nodePath.h"
#include "clockObject.h"
#include "asyncTask.h"
#include "genericAsyncTask.h"
#include "bulletWorld.h"
#include "bulletVehicle.h"
#include "bulletBoxShape.h"
#include "bulletPlaneShape.h"
#include "bulletWheel.h"
BulletWorld *get_physics_world() {
// physics_world is supposed to be an global variable,
// but declaring global variables is not cool
// for good programmers lol, instead, should use static keyword.
static BulletWorld *physics_world = new BulletWorld();
return physics_world;
}
AsyncTask::DoneStatus update_scene(GenericAsyncTask* task, void* data) {
// Get dt (from Python example) and apply to do_physics(float, int, int);
ClockObject *co = ClockObject::get_global_clock();
get_physics_world()->do_physics(co->get_dt(), 10, 1.0 / 180.0);
return AsyncTask::DS_cont;
}
int main(int argc, char *argv[]) {
// All variables.
PandaFramework framework;
PT(WindowFramework) window;
NodePath camera;
PT(AsyncTaskManager) task_mgr;
// Init everything :D
framework.open_framework(argc, argv);
framework.set_window_title("Bullet Vehicle");
window = framework.open_window();
window->enable_keyboard();
window->setup_trackball();
camera = window->get_camera_group();
task_mgr = AsyncTaskManager::get_global_ptr();
// Make physics simulation.
// Static world stuff.
get_physics_world()->set_gravity(0, 0, -9.81f);
// Chassis body
BulletBoxShape* shape = new BulletBoxShape(LVecBase3(0.7, 1.5, 0.5));
ConstPointerTo<TransformState> ts = TransformState::make_pos(LVecBase3(0, 0, 0.5));
PT(BulletRigidBodyNode) chassis_rigid_node = new BulletRigidBodyNode("Vehicle");
chassis_rigid_node->add_shape(shape,ts);
NodePath np_chassis = window->get_render().attach_new_node(chassis_rigid_node);
np_chassis.set_pos(0, 0, 1);
chassis_rigid_node->set_mass(800.0);
chassis_rigid_node->set_deactivation_enabled(false);
get_physics_world()->attach_rigid_body(chassis_rigid_node);
//Chassis
PT(BulletDebugNode) visNode = new BulletDebugNode("ChassisVisual");
NodePath visNP = np_chassis.attach_new_node(visNode);
// Vehicle
BulletVehicle* vehicle = new BulletVehicle(get_physics_world(), chassis_rigid_node);
vehicle->set_coordinate_system(BulletUpAxis::Z_up);
get_physics_world()->attach_vehicle(vehicle);
//wheels
NodePath wheel1NP;
wheel1NP.reparent_to(window->get_render());
BulletWheel wheel1 = vehicle->create_wheel();
wheel1.set_node(wheel1NP.node());
wheel1.set_chassis_connection_point_cs(LPoint3(0.8, 1.1, 0.3));
wheel1.set_front_wheel(true);
wheel1.set_wheel_direction_cs(LVector3(0, 0, -1));
wheel1.set_wheel_axle_cs(LVector3(1, 0, 0));
wheel1.set_wheel_radius(0.25);
wheel1.set_max_suspension_travel_cm(40.0);
wheel1.set_suspension_stiffness(40.0);
wheel1.set_wheels_damping_relaxation(2.3);
wheel1.set_wheels_damping_compression(4.4);
wheel1.set_friction_slip(100.0);
wheel1.set_roll_influence(0.1);
//wheel2
BulletWheel wheel2 = vehicle->create_wheel();
NodePath wheel2NP;
wheel2NP.reparent_to(window->get_render());
wheel2.set_node(wheel2NP.node());
wheel2.set_chassis_connection_point_cs(LPoint3(-0.8, 1.1, 0.3));
wheel2.set_front_wheel(true);
wheel2.set_wheel_direction_cs(LVector3(0, 0, -1));
wheel2.set_wheel_axle_cs(LVector3(-1, 0, 0));
wheel2.set_wheel_radius(0.25);
wheel2.set_max_suspension_travel_cm(40.0);
wheel2.set_suspension_stiffness(40.0);
wheel2.set_wheels_damping_relaxation(2.3);
wheel2.set_wheels_damping_compression(4.4);
wheel2.set_friction_slip(100.0);
wheel2.set_roll_influence(0.1);
////wheel3
BulletWheel wheel3 = vehicle->create_wheel();
NodePath wheel3NP;
wheel3NP.reparent_to(window->get_render());
wheel3.set_node(wheel3NP.node());
wheel3.set_chassis_connection_point_cs(LPoint3(0.8, -1.1, 0.3));
wheel3.set_front_wheel(false);
wheel3.set_wheel_direction_cs(LVector3(0, 0, -1));
wheel3.set_wheel_axle_cs(LVector3(1, 0, 0));
wheel3.set_wheel_radius(0.25);
wheel3.set_max_suspension_travel_cm(40.0);
wheel3.set_suspension_stiffness(40.0);
wheel3.set_wheels_damping_relaxation(2.3);
wheel3.set_wheels_damping_compression(4.4);
wheel3.set_friction_slip(100.0);
wheel3.set_roll_influence(0.1);
////wheel4
BulletWheel wheel4 = vehicle->create_wheel();
NodePath wheel4NP;
wheel4NP.reparent_to(window->get_render());
wheel4.set_node(wheel4NP.node());
wheel4.set_chassis_connection_point_cs(LPoint3(-0.8, -1.1, 0.3));
wheel4.set_front_wheel(false);
wheel4.set_wheel_direction_cs(LVector3(0, 0, -1));
wheel4.set_wheel_axle_cs(LVector3(-1, 0, 0));
wheel4.set_wheel_radius(0.25);
wheel4.set_max_suspension_travel_cm(40.0);
wheel4.set_suspension_stiffness(40.0);
wheel4.set_wheels_damping_relaxation(2.3);
wheel4.set_wheels_damping_compression(4.4);
wheel4.set_friction_slip(100.0);
wheel4.set_roll_influence(0.1);
// Steering info
PN_stdfloat steering = 0.0;
PN_stdfloat engineForce = 1000.0;
// Apply steering to front wheels
vehicle->set_steering_value(steering, 0);
vehicle->set_steering_value(steering, 1);
// Apply engine and brake to rear wheels
vehicle->apply_engine_force(engineForce, 0);
vehicle->apply_engine_force(engineForce, 1);
//ground
PT(BulletPlaneShape) floor_shape = new BulletPlaneShape(LVecBase3f(0, 0, 1), 1);
PT(BulletRigidBodyNode) floor_rigid_node = new BulletRigidBodyNode("Ground");
floor_shape->set_margin(100);
floor_rigid_node->add_shape(floor_shape);
NodePath np_ground = window->get_render().attach_new_node(floor_rigid_node);
np_ground.set_pos(0, 0, -2);
get_physics_world()->attach_rigid_body(floor_rigid_node);
visNode->add_child(floor_rigid_node);
visNode->show_bounding_boxes(false);
visNode->show_constraints(true);
visNode->show_normals(true);
visNode->show_wireframe(true);
get_physics_world()->set_debug_node(visNode);
visNP.show();
np_ground.show();
//wheelNP.show();
PT(GenericAsyncTask) task;
task = new GenericAsyncTask("Scene update", &update_scene, (void*) NULL);
task_mgr->add(task);
framework.main_loop();
return (0);
}
Thanks,
Zobbo