summaryrefslogtreecommitdiff
path: root/scene/3d
diff options
context:
space:
mode:
Diffstat (limited to 'scene/3d')
-rw-r--r--scene/3d/light.cpp10
-rw-r--r--scene/3d/light.h1
-rw-r--r--scene/3d/navigation.cpp138
-rw-r--r--scene/3d/navigation.h9
-rw-r--r--scene/3d/physics_body.cpp14
-rw-r--r--scene/3d/physics_body.h6
-rw-r--r--scene/3d/skeleton.cpp10
-rw-r--r--scene/3d/skeleton.h1
-rw-r--r--scene/3d/spatial.cpp93
-rw-r--r--scene/3d/spatial.h14
-rw-r--r--scene/3d/vehicle_body.cpp846
-rw-r--r--scene/3d/vehicle_body.h142
-rw-r--r--scene/3d/visual_instance.cpp21
-rw-r--r--scene/3d/visual_instance.h1
14 files changed, 1283 insertions, 23 deletions
diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp
index 25f3b3d3a5..1efc74e672 100644
--- a/scene/3d/light.cpp
+++ b/scene/3d/light.cpp
@@ -460,7 +460,7 @@ void Light::_bind_methods() {
ADD_PROPERTY( PropertyInfo( Variant::BOOL, "params/enabled"), _SCS("set_enabled"), _SCS("is_enabled"));
- ADD_PROPERTY( PropertyInfo( Variant::INT, "params/bake_mode",PROPERTY_HINT_ENUM,"Disabled,Indirect,Full"), _SCS("set_bake_mode"), _SCS("get_bake_mode"));
+ ADD_PROPERTY( PropertyInfo( Variant::INT, "params/bake_mode",PROPERTY_HINT_ENUM,"Disabled,Indirect,Indirect+Shadows,Full"), _SCS("set_bake_mode"), _SCS("get_bake_mode"));
ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/energy", PROPERTY_HINT_EXP_RANGE, "0,64,0.01"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_ENERGY );
/*
if (type == VisualServer::LIGHT_OMNI || type == VisualServer::LIGHT_SPOT) {
@@ -477,7 +477,7 @@ void Light::_bind_methods() {
ADD_PROPERTYI( PropertyInfo( Variant::COLOR, "colors/diffuse"), _SCS("set_color"), _SCS("get_color"),COLOR_DIFFUSE);
ADD_PROPERTYI( PropertyInfo( Variant::COLOR, "colors/specular"), _SCS("set_color"), _SCS("get_color"),COLOR_SPECULAR);
ADD_PROPERTY( PropertyInfo( Variant::BOOL, "shadow/shadow"), _SCS("set_project_shadows"), _SCS("has_project_shadows"));
- ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/darkening", PROPERTY_HINT_RANGE, "0,64,0.01"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SHADOW_DARKENING );
+ ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/darkening", PROPERTY_HINT_RANGE, "0,1,0.01"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SHADOW_DARKENING );
ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/z_offset", PROPERTY_HINT_RANGE, "0,128,0.001"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SHADOW_Z_OFFSET);
ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/z_slope_scale", PROPERTY_HINT_RANGE, "0,128,0.001"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SHADOW_Z_SLOPE_SCALE);
ADD_PROPERTYI( PropertyInfo( Variant::REAL, "shadow/esm_multiplier", PROPERTY_HINT_RANGE, "1.0,512.0,0.1"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SHADOW_ESM_MULTIPLIER);
@@ -498,6 +498,12 @@ void Light::_bind_methods() {
BIND_CONSTANT( COLOR_DIFFUSE );
BIND_CONSTANT( COLOR_SPECULAR );
+ BIND_CONSTANT( BAKE_MODE_DISABLED );
+ BIND_CONSTANT( BAKE_MODE_INDIRECT );
+ BIND_CONSTANT( BAKE_MODE_INDIRECT_AND_SHADOWS );
+ BIND_CONSTANT( BAKE_MODE_FULL );
+
+
}
diff --git a/scene/3d/light.h b/scene/3d/light.h
index 6b1ea2d455..9fdd7295dc 100644
--- a/scene/3d/light.h
+++ b/scene/3d/light.h
@@ -69,6 +69,7 @@ public:
BAKE_MODE_DISABLED,
BAKE_MODE_INDIRECT,
+ BAKE_MODE_INDIRECT_AND_SHADOWS,
BAKE_MODE_FULL
};
diff --git a/scene/3d/navigation.cpp b/scene/3d/navigation.cpp
index 4b0d233fbe..d2abdad079 100644
--- a/scene/3d/navigation.cpp
+++ b/scene/3d/navigation.cpp
@@ -180,7 +180,7 @@ void Navigation::navmesh_remove(int p_id){
}
-Vector<Vector3> Navigation::get_simple_path(const Vector3& p_start, const Vector3& p_end) {
+Vector<Vector3> Navigation::get_simple_path(const Vector3& p_start, const Vector3& p_end, bool p_optimize) {
Polygon *begin_poly=NULL;
@@ -332,24 +332,112 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3& p_start, const Vector
if (found_route) {
- //use midpoints for now
- Polygon *p=end_poly;
Vector<Vector3> path;
- path.push_back(end_point);
- while(true) {
- int prev = p->prev_edge;
- int prev_n = (p->prev_edge+1)%p->edges.size();
- Vector3 point = (_get_vertex(p->edges[prev].point) + _get_vertex(p->edges[prev_n].point))*0.5;
- path.push_back(point);
- p = p->edges[prev].C;
- if (p==begin_poly)
- break;
- }
- path.push_back(begin_point);
+ if (p_optimize) {
+ //string pulling
+
+ Polygon *apex_poly=end_poly;
+ Vector3 apex_point=end_point;
+ Vector3 portal_left=apex_point;
+ Vector3 portal_right=apex_point;
+ Polygon *left_poly=end_poly;
+ Polygon *right_poly=end_poly;
+ Polygon *p=end_poly;
+ path.push_back(end_point);
+
+ while(p) {
+
+ Vector3 left;
+ Vector3 right;
+
+#define CLOCK_TANGENT(m_a,m_b,m_c) ( ((m_a)-(m_c)).cross((m_a)-(m_b)) )
+
+ if (p==begin_poly) {
+ left=begin_point;
+ right=begin_point;
+ } else {
+ int prev = p->prev_edge;
+ int prev_n = (p->prev_edge+1)%p->edges.size();
+ left = _get_vertex(p->edges[prev].point);
+ right = _get_vertex(p->edges[prev_n].point);
+
+ if (CLOCK_TANGENT(apex_point,left,(left+right)*0.5).dot(up) < 0){
+ SWAP(left,right);
+ }
+ }
+
+ bool skip=false;
+
+
+ if (CLOCK_TANGENT(apex_point,portal_left,left).dot(up) >= 0){
+ //process
+ if (portal_left==apex_point || CLOCK_TANGENT(apex_point,left,portal_right).dot(up) > 0) {
+ left_poly=p;
+ portal_left=left;
+ } else {
+
+ apex_point=portal_right;
+ p=right_poly;
+ left_poly=p;
+ portal_left=apex_point;
+ portal_right=apex_point;
+ path.push_back(apex_point);
+ skip=true;
+ }
+ }
+
+ if (!skip && CLOCK_TANGENT(apex_point,portal_right,right).dot(up) <= 0){
+ //process
+ if (portal_right==apex_point || CLOCK_TANGENT(apex_point,right,portal_left).dot(up) < 0) {
+ right_poly=p;
+ portal_right=right;
+ } else {
+
+ apex_point=portal_left;
+ p=left_poly;
+ right_poly=p;
+ portal_right=apex_point;
+ portal_left=apex_point;
+ path.push_back(apex_point);
+ }
+ }
+
+ if (p!=begin_poly)
+ p=p->edges[p->prev_edge].C;
+ else
+ p=NULL;
+
+ }
+ if (path[path.size()-1]!=begin_point)
+ path.push_back(begin_point);
- path.invert();;
+ path.invert();
+
+
+
+
+ } else {
+ //midpoints
+ Polygon *p=end_poly;
+
+ path.push_back(end_point);
+ while(true) {
+ int prev = p->prev_edge;
+ int prev_n = (p->prev_edge+1)%p->edges.size();
+ Vector3 point = (_get_vertex(p->edges[prev].point) + _get_vertex(p->edges[prev_n].point))*0.5;
+ path.push_back(point);
+ p = p->edges[prev].C;
+ if (p==begin_poly)
+ break;
+ }
+
+ path.push_back(begin_point);
+
+
+ path.invert();;
+ }
return path;
}
@@ -475,17 +563,33 @@ Vector3 Navigation::get_closest_point_normal(const Vector3& p_point){
}
+void Navigation::set_up_vector(const Vector3& p_up) {
+
+
+ up=p_up;
+}
+
+Vector3 Navigation::get_up_vector() const{
+
+ return up;
+}
+
+
void Navigation::_bind_methods() {
ObjectTypeDB::bind_method(_MD("navmesh_create","mesh:NavigationMesh","xform"),&Navigation::navmesh_create);
ObjectTypeDB::bind_method(_MD("navmesh_set_transform","id","xform"),&Navigation::navmesh_set_transform);
ObjectTypeDB::bind_method(_MD("navmesh_remove","id"),&Navigation::navmesh_remove);
- ObjectTypeDB::bind_method(_MD("get_simple_path","start","end"),&Navigation::get_simple_path);
+ ObjectTypeDB::bind_method(_MD("get_simple_path","start","end","optimize"),&Navigation::get_simple_path,DEFVAL(true));
ObjectTypeDB::bind_method(_MD("get_closest_point_to_segment","start","end"),&Navigation::get_closest_point_to_segment);
ObjectTypeDB::bind_method(_MD("get_closest_point","to_point"),&Navigation::get_closest_point);
ObjectTypeDB::bind_method(_MD("get_closest_point_normal","to_point"),&Navigation::get_closest_point_normal);
+ ObjectTypeDB::bind_method(_MD("set_up_vector","up"),&Navigation::set_up_vector);
+ ObjectTypeDB::bind_method(_MD("get_up_vector"),&Navigation::get_up_vector);
+
+ ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"up_vector"),_SCS("set_up_vector"),_SCS("get_up_vector"));
}
Navigation::Navigation() {
@@ -493,5 +597,7 @@ Navigation::Navigation() {
ERR_FAIL_COND( sizeof(Point)!=8 );
cell_size=0.01; //one centimeter
last_id=1;
+ up=Vector3(0,1,0);
}
+
diff --git a/scene/3d/navigation.h b/scene/3d/navigation.h
index 40f474858c..e8a97a6591 100644
--- a/scene/3d/navigation.h
+++ b/scene/3d/navigation.h
@@ -103,6 +103,8 @@ class Navigation : public Spatial {
return Vector3(p_point.x,p_point.y,p_point.z)*cell_size;
}
+
+
void _navmesh_link(int p_id);
void _navmesh_unlink(int p_id);
@@ -110,18 +112,23 @@ class Navigation : public Spatial {
Map<int,NavMesh> navmesh_map;
int last_id;
+ Vector3 up;
+
protected:
static void _bind_methods();
public:
+ void set_up_vector(const Vector3& p_up);
+ Vector3 get_up_vector() const;
+
//API should be as dynamic as possible
int navmesh_create(const Ref<NavigationMesh>& p_mesh,const Transform& p_xform);
void navmesh_set_transform(int p_id, const Transform& p_xform);
void navmesh_remove(int p_id);
- Vector<Vector3> get_simple_path(const Vector3& p_start, const Vector3& p_end);
+ Vector<Vector3> get_simple_path(const Vector3& p_start, const Vector3& p_end,bool p_optimize=true);
Vector3 get_closest_point_to_segment(const Vector3& p_from,const Vector3& p_to);
Vector3 get_closest_point(const Vector3& p_point);
Vector3 get_closest_point_normal(const Vector3& p_point);
diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp
index 2a1a5972a9..721fd368e1 100644
--- a/scene/3d/physics_body.cpp
+++ b/scene/3d/physics_body.cpp
@@ -43,6 +43,20 @@ void PhysicsBody::_notification(int p_what) {
*/
}
+Vector3 PhysicsBody::get_linear_velocity() const {
+
+ return Vector3();
+}
+Vector3 PhysicsBody::get_angular_velocity() const {
+
+ return Vector3();
+}
+
+float PhysicsBody::get_inverse_mass() const {
+
+ return 0;
+}
+
PhysicsBody::PhysicsBody(PhysicsServer::BodyMode p_mode) : CollisionObject( PhysicsServer::get_singleton()->body_create(p_mode), false) {
diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h
index 6695ee719a..616288e1f6 100644
--- a/scene/3d/physics_body.h
+++ b/scene/3d/physics_body.h
@@ -44,6 +44,10 @@ protected:
PhysicsBody(PhysicsServer::BodyMode p_mode);
public:
+ virtual Vector3 get_linear_velocity() const;
+ virtual Vector3 get_angular_velocity() const;
+ virtual float get_inverse_mass() const;
+
PhysicsBody();
};
@@ -183,6 +187,8 @@ public:
void set_mass(real_t p_mass);
real_t get_mass() const;
+ virtual float get_inverse_mass() const { return 1.0/mass; }
+
void set_weight(real_t p_weight);
real_t get_weight() const;
diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp
index 323bfa4dc4..858ee4e4ad 100644
--- a/scene/3d/skeleton.cpp
+++ b/scene/3d/skeleton.cpp
@@ -237,6 +237,14 @@ Transform Skeleton::get_bone_transform(int p_bone) const {
return bones[p_bone].pose_global * bones[p_bone].rest_global_inverse;
}
+Transform Skeleton::get_bone_global_pose(int p_bone) const {
+
+ ERR_FAIL_INDEX_V(p_bone,bones.size(),Transform());
+ if (dirty)
+ const_cast<Skeleton*>(this)->notification(NOTIFICATION_UPDATE_SKELETON);
+ return bones[p_bone].pose_global;
+}
+
RID Skeleton::get_skeleton() const {
return skeleton;
@@ -511,6 +519,8 @@ void Skeleton::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_bone_pose","bone_idx"),&Skeleton::get_bone_pose);
ObjectTypeDB::bind_method(_MD("set_bone_pose","bone_idx","pose"),&Skeleton::set_bone_pose);
+ ObjectTypeDB::bind_method(_MD("get_bone_global_pose","bone_idx"),&Skeleton::get_bone_global_pose);
+
ObjectTypeDB::bind_method(_MD("get_bone_custom_pose","bone_idx"),&Skeleton::get_bone_custom_pose);
ObjectTypeDB::bind_method(_MD("set_bone_custom_pose","bone_idx","custom_pose"),&Skeleton::set_bone_custom_pose);
diff --git a/scene/3d/skeleton.h b/scene/3d/skeleton.h
index c95734fbf1..3e0ab0afd7 100644
--- a/scene/3d/skeleton.h
+++ b/scene/3d/skeleton.h
@@ -116,6 +116,7 @@ public:
void set_bone_rest(int p_bone, const Transform& p_rest);
Transform get_bone_rest(int p_bone) const;
Transform get_bone_transform(int p_bone) const;
+ Transform get_bone_global_pose(int p_bone) const;
void set_bone_enabled(int p_bone, bool p_enabled);
bool is_bone_enabled(int p_bone) const;
diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp
index c52503870f..13094300d0 100644
--- a/scene/3d/spatial.cpp
+++ b/scene/3d/spatial.cpp
@@ -506,6 +506,86 @@ Transform Spatial::get_import_transform() const {
#endif
+void Spatial::_propagate_visibility_changed() {
+
+ notification(NOTIFICATION_VISIBILITY_CHANGED);
+ emit_signal(SceneStringNames::get_singleton()->visibility_changed);
+ _change_notify("visibility/visible");
+
+ for (List<Spatial*>::Element*E=data.children.front();E;E=E->next()) {
+
+ Spatial *c=E->get();
+ if (!c || !c->data.visible)
+ continue;
+ c->_propagate_visibility_changed();
+ }
+}
+
+
+void Spatial::show() {
+
+ if (data.visible)
+ return;
+
+ data.visible=true;
+
+ if (!is_inside_scene())
+ return;
+
+ if (!data.parent || is_visible()) {
+
+ _propagate_visibility_changed();
+ }
+}
+
+void Spatial::hide(){
+
+ if (!data.visible)
+ return;
+
+ bool was_visible = is_visible();
+ data.visible=false;
+
+ if (!data.parent || was_visible) {
+
+ _propagate_visibility_changed();
+ }
+
+}
+bool Spatial::is_visible() const{
+
+ const Spatial *s=this;
+
+ while(s) {
+ if (!s->data.visible) {
+ return false;
+ }
+ s=s->data.parent;
+ }
+
+ return true;
+}
+
+
+bool Spatial::is_hidden() const{
+
+ return !data.visible;
+}
+
+void Spatial::_set_visible_(bool p_visible) {
+
+ if (p_visible)
+ show();
+ else
+ hide();
+}
+
+bool Spatial::_is_visible_() const {
+
+ return !is_hidden();
+}
+
+
void Spatial::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_transform","local"), &Spatial::set_transform);
@@ -537,9 +617,18 @@ void Spatial::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_gizmo","gizmo:SpatialGizmo"), &Spatial::set_gizmo);
ObjectTypeDB::bind_method(_MD("get_gizmo:SpatialGizmo"), &Spatial::get_gizmo);
+ ObjectTypeDB::bind_method(_MD("show"), &Spatial::show);
+ ObjectTypeDB::bind_method(_MD("hide"), &Spatial::hide);
+ ObjectTypeDB::bind_method(_MD("is_visible"), &Spatial::is_visible);
+ ObjectTypeDB::bind_method(_MD("is_hidden"), &Spatial::is_hidden);
+
+ ObjectTypeDB::bind_method(_MD("_set_visible_"), &Spatial::_set_visible_);
+ ObjectTypeDB::bind_method(_MD("_is_visible_"), &Spatial::_is_visible_);
+
BIND_CONSTANT( NOTIFICATION_TRANSFORM_CHANGED );
BIND_CONSTANT( NOTIFICATION_ENTER_WORLD );
BIND_CONSTANT( NOTIFICATION_EXIT_WORLD );
+ BIND_CONSTANT( NOTIFICATION_VISIBILITY_CHANGED );
//ADD_PROPERTY( PropertyInfo(Variant::TRANSFORM,"transform/global",PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR ), _SCS("set_global_transform"), _SCS("get_global_transform") );
ADD_PROPERTYNZ( PropertyInfo(Variant::TRANSFORM,"transform/local",PROPERTY_HINT_NONE,""), _SCS("set_transform"), _SCS("get_transform") );
@@ -547,8 +636,11 @@ void Spatial::_bind_methods() {
ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"transform/rotation",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_EDITOR), _SCS("_set_rotation_deg"), _SCS("_get_rotation_deg") );
ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"transform/rotation_rad",PROPERTY_HINT_NONE,"",0), _SCS("set_rotation"), _SCS("get_rotation") );
ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"transform/scale",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_EDITOR), _SCS("set_scale"), _SCS("get_scale") );
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL,"visibility/visible"), _SCS("_set_visible_"), _SCS("_is_visible_") );
//ADD_PROPERTY( PropertyInfo(Variant::TRANSFORM,"transform/local"), _SCS("set_transform"), _SCS("get_transform") );
+ ADD_SIGNAL( MethodInfo("visibility_changed" ) );
+
}
@@ -564,6 +656,7 @@ Spatial::Spatial() : xform_change(this)
data.scale=Vector3(1,1,1);
data.viewport=NULL;
data.inside_world=false;
+ data.visible=true;
#ifdef TOOLS_ENABLED
data.gizmo_disabled=false;
data.gizmo_dirty=false;
diff --git a/scene/3d/spatial.h b/scene/3d/spatial.h
index e1119be515..f2ec26eb58 100644
--- a/scene/3d/spatial.h
+++ b/scene/3d/spatial.h
@@ -91,6 +91,8 @@ class Spatial : public Node {
bool ignore_notification;
+ bool visible;
+
#ifdef TOOLS_ENABLED
Ref<SpatialGizmo> gizmo;
bool gizmo_disabled;
@@ -109,6 +111,8 @@ class Spatial : public Node {
void _set_rotation_deg(const Vector3& p_deg);
Vector3 _get_rotation_deg() const;
+ void _propagate_visibility_changed();
+
protected:
@@ -118,7 +122,9 @@ protected:
void _notification(int p_what);
static void _bind_methods();
-
+
+ void _set_visible_(bool p_visible);
+ bool _is_visible_() const;
public:
enum {
@@ -126,6 +132,7 @@ public:
NOTIFICATION_TRANSFORM_CHANGED=SceneMainLoop::NOTIFICATION_TRANSFORM_CHANGED,
NOTIFICATION_ENTER_WORLD=41,
NOTIFICATION_EXIT_WORLD=42,
+ NOTIFICATION_VISIBILITY_CHANGED=43,
};
Spatial *get_parent_spatial() const;
@@ -159,6 +166,11 @@ public:
Transform get_relative_transform(const Node *p_parent) const;
+ void show();
+ void hide();
+ bool is_visible() const;
+ bool is_hidden() const;
+
#ifdef TOOLS_ENABLED
void set_import_transform(const Transform& p_transform) ;
Transform get_import_transform() const;
diff --git a/scene/3d/vehicle_body.cpp b/scene/3d/vehicle_body.cpp
new file mode 100644
index 0000000000..7680c1d56c
--- /dev/null
+++ b/scene/3d/vehicle_body.cpp
@@ -0,0 +1,846 @@
+#include "vehicle_body.h"
+
+#define ROLLING_INFLUENCE_FIX
+
+class btVehicleJacobianEntry
+{
+public:
+
+ Vector3 m_linearJointAxis;
+ Vector3 m_aJ;
+ Vector3 m_bJ;
+ Vector3 m_0MinvJt;
+ Vector3 m_1MinvJt;
+ //Optimization: can be stored in the w/last component of one of the vectors
+ real_t m_Adiag;
+
+ real_t getDiagonal() const { return m_Adiag; }
+
+ btVehicleJacobianEntry() {};
+ //constraint between two different rigidbodies
+ btVehicleJacobianEntry(
+ const Matrix3& world2A,
+ const Matrix3& world2B,
+ const Vector3& rel_pos1,
+ const Vector3& rel_pos2,
+ const Vector3& jointAxis,
+ const Vector3& inertiaInvA,
+ const real_t massInvA,
+ const Vector3& inertiaInvB,
+ const real_t massInvB)
+ :m_linearJointAxis(jointAxis)
+ {
+ m_aJ = world2A.xform(rel_pos1.cross(m_linearJointAxis));
+ m_bJ = world2B.xform(rel_pos2.cross(-m_linearJointAxis));
+ m_0MinvJt = inertiaInvA * m_aJ;
+ m_1MinvJt = inertiaInvB * m_bJ;
+ m_Adiag = massInvA + m_0MinvJt.dot(m_aJ) + massInvB + m_1MinvJt.dot(m_bJ);
+
+ //btAssert(m_Adiag > real_t(0.0));
+ }
+
+ real_t getRelativeVelocity(const Vector3& linvelA,const Vector3& angvelA,const Vector3& linvelB,const Vector3& angvelB)
+ {
+ Vector3 linrel = linvelA - linvelB;
+ Vector3 angvela = angvelA * m_aJ;
+ Vector3 angvelb = angvelB * m_bJ;
+ linrel *= m_linearJointAxis;
+ angvela += angvelb;
+ angvela += linrel;
+ real_t rel_vel2 = angvela[0]+angvela[1]+angvela[2];
+ return rel_vel2 + CMP_EPSILON;
+ }
+
+
+};
+
+void VehicleWheel::_notification(int p_what) {
+
+
+ if (p_what==NOTIFICATION_ENTER_SCENE) {
+
+ if (!get_parent())
+ return;
+ VehicleBody *cb = get_parent()->cast_to<VehicleBody>();
+ if (!cb)
+ return;
+ body=cb;
+ local_xform=get_transform();
+ cb->wheels.push_back(this);
+
+ m_chassisConnectionPointCS = get_transform().origin;
+ m_wheelDirectionCS = -get_transform().basis.get_axis(Vector3::AXIS_Y).normalized();
+ m_wheelAxleCS = get_transform().basis.get_axis(Vector3::AXIS_X).normalized();
+
+ }
+ if (p_what==NOTIFICATION_EXIT_SCENE) {
+
+ if (!get_parent())
+ return;
+ VehicleBody *cb = get_parent()->cast_to<VehicleBody>();
+ if (!cb)
+ return;
+ cb->wheels.erase(this);
+ body=NULL;
+ }
+
+}
+
+
+void VehicleWheel::_update(PhysicsDirectBodyState *s) {
+
+
+
+ if (m_raycastInfo.m_isInContact)
+
+ {
+ real_t project= m_raycastInfo.m_contactNormalWS.dot( m_raycastInfo.m_wheelDirectionWS );
+ Vector3 chassis_velocity_at_contactPoint;
+ Vector3 relpos = m_raycastInfo.m_contactPointWS - s->get_transform().origin;
+
+ chassis_velocity_at_contactPoint = s->get_linear_velocity() +
+ (s->get_angular_velocity()).cross(relpos);// * mPos);
+
+ real_t projVel = m_raycastInfo.m_contactNormalWS.dot( chassis_velocity_at_contactPoint );
+ if ( project >= real_t(-0.1))
+ {
+ m_suspensionRelativeVelocity = real_t(0.0);
+ m_clippedInvContactDotSuspension = real_t(1.0) / real_t(0.1);
+ }
+ else
+ {
+ real_t inv = real_t(-1.) / project;
+ m_suspensionRelativeVelocity = projVel * inv;
+ m_clippedInvContactDotSuspension = inv;
+ }
+
+ }
+
+ else // Not in contact : position wheel in a nice (rest length) position
+ {
+ m_raycastInfo.m_suspensionLength = m_suspensionRestLength;
+ m_suspensionRelativeVelocity = real_t(0.0);
+ m_raycastInfo.m_contactNormalWS = -m_raycastInfo.m_wheelDirectionWS;
+ m_clippedInvContactDotSuspension = real_t(1.0);
+ }
+}
+
+void VehicleWheel::_bind_methods() {
+
+
+
+}
+
+
+VehicleWheel::VehicleWheel() {
+
+
+
+ m_steering = real_t(0.);
+ m_engineForce = real_t(0.);
+ m_rotation = real_t(0.);
+ m_deltaRotation = real_t(0.);
+ m_brake = real_t(0.);
+ m_rollInfluence = real_t(0.1);
+
+ m_suspensionRestLength = 0.15;
+ m_wheelRadius = 0.5;//0.28;
+ m_suspensionStiffness = 5.88;
+ m_wheelsDampingCompression = 0.83;
+ m_wheelsDampingRelaxation = 0.88;
+ m_frictionSlip = 10.5;
+ m_bIsFrontWheel = false;
+ m_maxSuspensionTravelCm = 500;
+ m_maxSuspensionForce = 6000;
+
+ m_suspensionRelativeVelocity=0;
+ m_clippedInvContactDotSuspension=1.0;
+ m_raycastInfo.m_isInContact=false;
+
+ body=NULL;
+}
+
+
+void VehicleBody::_update_wheel_transform(VehicleWheel& wheel ,PhysicsDirectBodyState *s) {
+
+ wheel.m_raycastInfo.m_isInContact = false;
+
+ Transform chassisTrans = s->get_transform();
+ //if (interpolatedTransform && (getRigidBody()->getMotionState()))
+ //{
+ // getRigidBody()->getMotionState()->getWorldTransform(chassisTrans);
+ //}
+
+ wheel.m_raycastInfo.m_hardPointWS = chassisTrans.xform( wheel.m_chassisConnectionPointCS );
+ wheel.m_raycastInfo.m_wheelDirectionWS = chassisTrans.get_basis().xform( wheel.m_wheelDirectionCS).normalized();
+ wheel.m_raycastInfo.m_wheelAxleWS = chassisTrans.get_basis().xform( wheel.m_wheelAxleCS ).normalized();
+}
+
+void VehicleBody::_update_wheel(int p_idx,PhysicsDirectBodyState *s) {
+
+ VehicleWheel& wheel = *wheels[p_idx];
+ _update_wheel_transform(wheel,s);
+
+ Vector3 up = -wheel.m_raycastInfo.m_wheelDirectionWS;
+ const Vector3& right = wheel.m_raycastInfo.m_wheelAxleWS;
+ Vector3 fwd = up.cross(right);
+ fwd = fwd.normalized();
+// up = right.cross(fwd);
+// up.normalize();
+
+ //rotate around steering over de wheelAxleWS
+ real_t steering = wheel.m_steering;
+
+ Matrix3 steeringMat(up,steering);
+
+ Matrix3 rotatingMat(right,-wheel.m_rotation);
+
+ Matrix3 basis2(
+ right[0],up[0],fwd[0],
+ right[1],up[1],fwd[1],
+ right[2],up[2],fwd[2]
+ );
+
+ wheel.m_worldTransform.set_basis(steeringMat * rotatingMat * basis2);
+ wheel.m_worldTransform.set_origin(
+ wheel.m_raycastInfo.m_hardPointWS + wheel.m_raycastInfo.m_wheelDirectionWS * wheel.m_raycastInfo.m_suspensionLength
+ );
+}
+
+
+real_t VehicleBody::_ray_cast(int p_idx,PhysicsDirectBodyState *s) {
+
+
+ VehicleWheel& wheel = *wheels[p_idx];
+
+ _update_wheel_transform(wheel,s);
+
+
+ real_t depth = -1;
+
+ real_t raylen = wheel.m_suspensionRestLength+wheel.m_wheelRadius;
+
+ Vector3 rayvector = wheel.m_raycastInfo.m_wheelDirectionWS * (raylen);
+ const Vector3& source = wheel.m_raycastInfo.m_hardPointWS;
+ wheel.m_raycastInfo.m_contactPointWS = source + rayvector;
+ const Vector3& target = wheel.m_raycastInfo.m_contactPointWS;
+
+ real_t param = real_t(0.);
+
+
+ PhysicsDirectSpaceState::RayResult rr;
+
+
+ PhysicsDirectSpaceState *ss=s->get_space_state();
+
+ bool col = ss->intersect_ray(source,target,rr,exclude);
+
+
+ wheel.m_raycastInfo.m_groundObject = 0;
+
+ if (col)
+ {
+ //print_line("WHEEL "+itos(p_idx)+" FROM "+source+" TO: "+target);
+ //print_line("WHEEL "+itos(p_idx)+" COLLIDE? "+itos(col));
+ param = source.distance_to(rr.position)/source.distance_to(target);
+ depth = raylen * param;
+ wheel.m_raycastInfo.m_contactNormalWS = rr.normal;
+
+ wheel.m_raycastInfo.m_isInContact = true;
+ if (rr.collider)
+ wheel.m_raycastInfo.m_groundObject=rr.collider->cast_to<PhysicsBody>();
+
+
+ real_t hitDistance = param*raylen;
+ wheel.m_raycastInfo.m_suspensionLength = hitDistance - wheel.m_wheelRadius;
+ //clamp on max suspension travel
+
+ real_t minSuspensionLength = wheel.m_suspensionRestLength - wheel.m_maxSuspensionTravelCm*real_t(0.01);
+ real_t maxSuspensionLength = wheel.m_suspensionRestLength+ wheel.m_maxSuspensionTravelCm*real_t(0.01);
+ if (wheel.m_raycastInfo.m_suspensionLength < minSuspensionLength)
+ {
+ wheel.m_raycastInfo.m_suspensionLength = minSuspensionLength;
+ }
+ if (wheel.m_raycastInfo.m_suspensionLength > maxSuspensionLength)
+ {
+ wheel.m_raycastInfo.m_suspensionLength = maxSuspensionLength;
+ }
+
+ wheel.m_raycastInfo.m_contactPointWS = rr.position;
+
+ real_t denominator= wheel.m_raycastInfo.m_contactNormalWS.dot( wheel.m_raycastInfo.m_wheelDirectionWS );
+
+ Vector3 chassis_velocity_at_contactPoint;
+ //Vector3 relpos = wheel.m_raycastInfo.m_contactPointWS-getRigidBody()->getCenterOfMassPosition();
+
+ //chassis_velocity_at_contactPoint = getRigidBody()->getVelocityInLocalPoint(relpos);
+
+ chassis_velocity_at_contactPoint = s->get_linear_velocity() +
+ (s->get_angular_velocity()).cross(wheel.m_raycastInfo.m_contactPointWS-s->get_transform().origin);// * mPos);
+
+
+ real_t projVel = wheel.m_raycastInfo.m_contactNormalWS.dot( chassis_velocity_at_contactPoint );
+
+ if ( denominator >= real_t(-0.1))
+ {
+ wheel.m_suspensionRelativeVelocity = real_t(0.0);
+ wheel.m_clippedInvContactDotSuspension = real_t(1.0) / real_t(0.1);
+ }
+ else
+ {
+ real_t inv = real_t(-1.) / denominator;
+ wheel.m_suspensionRelativeVelocity = projVel * inv;
+ wheel.m_clippedInvContactDotSuspension = inv;
+ }
+
+ } else
+ {
+ wheel.m_raycastInfo.m_isInContact = false;
+ //put wheel info as in rest position
+ wheel.m_raycastInfo.m_suspensionLength = wheel.m_suspensionRestLength;
+ wheel.m_suspensionRelativeVelocity = real_t(0.0);
+ wheel.m_raycastInfo.m_contactNormalWS = - wheel.m_raycastInfo.m_wheelDirectionWS;
+ wheel.m_clippedInvContactDotSuspension = real_t(1.0);
+ }
+
+ return depth;
+}
+
+
+void VehicleBody::_update_suspension(PhysicsDirectBodyState *s)
+{
+
+ real_t deltaTime = s->get_step();
+ real_t chassisMass = mass;
+
+ for (int w_it=0; w_it<wheels.size(); w_it++)
+ {
+ VehicleWheel& wheel_info = *wheels[w_it];
+
+
+ if ( wheel_info.m_raycastInfo.m_isInContact )
+ {
+ real_t force;
+ // Spring
+ {
+ real_t susp_length = wheel_info.m_suspensionRestLength;
+ real_t current_length = wheel_info.m_raycastInfo.m_suspensionLength;
+
+ real_t length_diff = (susp_length - current_length);
+
+ force = wheel_info.m_suspensionStiffness
+ * length_diff * wheel_info.m_clippedInvContactDotSuspension;
+ }
+
+ // Damper
+ {
+ real_t projected_rel_vel = wheel_info.m_suspensionRelativeVelocity;
+ {
+ real_t susp_damping;
+ if ( projected_rel_vel < real_t(0.0) )
+ {
+ susp_damping = wheel_info.m_wheelsDampingCompression;
+ }
+ else
+ {
+ susp_damping = wheel_info.m_wheelsDampingRelaxation;
+ }
+ force -= susp_damping * projected_rel_vel;
+ }
+ }
+
+ // RESULT
+ wheel_info.m_wheelsSuspensionForce = force * chassisMass;
+ if (wheel_info.m_wheelsSuspensionForce < real_t(0.))
+ {
+ wheel_info.m_wheelsSuspensionForce = real_t(0.);
+ }
+ }
+ else
+ {
+ wheel_info.m_wheelsSuspensionForce = real_t(0.0);
+ }
+ }
+
+}
+
+
+//bilateral constraint between two dynamic objects
+void VehicleBody::_resolve_single_bilateral(PhysicsDirectBodyState *s, const Vector3& pos1,
+ PhysicsBody* body2, const Vector3& pos2, const Vector3& normal,real_t& impulse)
+{
+
+ real_t normalLenSqr = normal.length_squared();
+ //ERR_FAIL_COND( normalLenSqr < real_t(1.1));
+
+ if (normalLenSqr > real_t(1.1))
+ {
+ impulse = real_t(0.);
+ return;
+ }
+
+ Vector3 rel_pos1 = pos1 - s->get_transform().origin;
+ Vector3 rel_pos2;
+ if (body2)
+ rel_pos2 = pos2 - body2->get_global_transform().origin;
+ //this jacobian entry could be re-used for all iterations
+
+ Vector3 vel1 = s->get_linear_velocity() + (s->get_angular_velocity()).cross(rel_pos1);// * mPos);
+ Vector3 vel2;
+
+ if (body2)
+ vel2=body2->get_linear_velocity() + body2->get_angular_velocity().cross(rel_pos2);
+
+ Vector3 vel = vel1 - vel2;
+
+ Matrix3 b2trans;
+ float b2invmass=0;
+ Vector3 b2lv;
+ Vector3 b2av;
+ Vector3 b2invinertia; //todo
+
+ if (body2) {
+ b2trans = body2->get_global_transform().basis.transposed();
+ b2invmass = body2->get_inverse_mass();
+ b2lv = body2->get_linear_velocity();
+ b2av = body2->get_angular_velocity();
+ }
+
+
+
+ btVehicleJacobianEntry jac(s->get_transform().basis.transposed(),
+ b2trans,
+ rel_pos1,
+ rel_pos2,
+ normal,
+ s->get_inverse_inertia(),
+ 1.0/mass,
+ b2invinertia,
+ b2invmass);
+
+ real_t jacDiagAB = jac.getDiagonal();
+ real_t jacDiagABInv = real_t(1.) / jacDiagAB;
+
+ real_t rel_vel = jac.getRelativeVelocity(
+ s->get_linear_velocity(),
+ s->get_transform().basis.transposed().xform(s->get_angular_velocity()),
+ b2lv,
+ b2trans.xform(b2av));
+ real_t a;
+ a=jacDiagABInv;
+
+
+ rel_vel = normal.dot(vel);
+
+ //todo: move this into proper structure
+ real_t contactDamping = real_t(0.4);
+#define ONLY_USE_LINEAR_MASS
+#ifdef ONLY_USE_LINEAR_MASS
+ real_t massTerm = real_t(1.) / ((1.0/mass) + b2invmass);
+ impulse = - contactDamping * rel_vel * massTerm;
+#else
+ real_t velocityImpulse = -contactDamping * rel_vel * jacDiagABInv;
+ impulse = velocityImpulse;
+#endif
+
+}
+
+
+
+VehicleBody::btVehicleWheelContactPoint::btVehicleWheelContactPoint(PhysicsDirectBodyState *s,PhysicsBody* body1,const Vector3& frictionPosWorld,const Vector3& frictionDirectionWorld, real_t maxImpulse)
+ :m_s(s),
+ m_body1(body1),
+ m_frictionPositionWorld(frictionPosWorld),
+ m_frictionDirectionWorld(frictionDirectionWorld),
+ m_maxImpulse(maxImpulse)
+{
+ float denom0=0;
+ float denom1=0;
+
+ {
+ Vector3 r0 = frictionPosWorld - s->get_transform().origin;
+ Vector3 c0 = (r0).cross(frictionDirectionWorld);
+ Vector3 vec = s->get_inverse_inertia_tensor().xform_inv(c0).cross(r0);
+ denom0= s->get_inverse_mass() + frictionDirectionWorld.dot(vec);
+ }
+
+ if (body1) {
+
+ Vector3 r0 = frictionPosWorld - body1->get_global_transform().origin;
+ Vector3 c0 = (r0).cross(frictionDirectionWorld);
+ Vector3 vec = s->get_inverse_inertia_tensor().xform_inv(c0).cross(r0);
+ //denom1= body1->get_inverse_mass() + frictionDirectionWorld.dot(vec);
+ denom1=0;
+
+ }
+
+
+ real_t relaxation = 1.f;
+ m_jacDiagABInv = relaxation/(denom0+denom1);
+}
+
+
+real_t VehicleBody::_calc_rolling_friction(btVehicleWheelContactPoint& contactPoint) {
+
+ real_t j1=0.f;
+
+ const Vector3& contactPosWorld = contactPoint.m_frictionPositionWorld;
+
+ Vector3 rel_pos1 = contactPosWorld - contactPoint.m_s->get_transform().origin;
+ Vector3 rel_pos2;
+ if (contactPoint.m_body1)
+ rel_pos2 = contactPosWorld - contactPoint.m_body1->get_global_transform().origin;
+
+ real_t maxImpulse = contactPoint.m_maxImpulse;
+
+ Vector3 vel1 = contactPoint.m_s->get_linear_velocity() + (contactPoint.m_s->get_angular_velocity()).cross(rel_pos1);// * mPos);
+
+ Vector3 vel2;
+ if (contactPoint.m_body1) {
+ vel2=contactPoint.m_body1->get_linear_velocity() + contactPoint.m_body1->get_angular_velocity().cross(rel_pos2);
+
+ }
+
+ Vector3 vel = vel1 - vel2;
+
+ real_t vrel = contactPoint.m_frictionDirectionWorld.dot(vel);
+
+ // calculate j that moves us to zero relative velocity
+ j1 = -vrel * contactPoint.m_jacDiagABInv;
+
+ return CLAMP(j1,-maxImpulse,maxImpulse);
+}
+
+
+static const real_t sideFrictionStiffness2 = real_t(1.0);
+void VehicleBody::_update_friction(PhysicsDirectBodyState *s) {
+
+ //calculate the impulse, so that the wheels don't move sidewards
+ int numWheel = wheels.size();
+ if (!numWheel)
+ return;
+
+ m_forwardWS.resize(numWheel);
+ m_axle.resize(numWheel);
+ m_forwardImpulse.resize(numWheel);
+ m_sideImpulse.resize(numWheel);
+
+ int numWheelsOnGround = 0;
+
+
+ //collapse all those loops into one!
+ for (int i=0;i<wheels.size();i++)
+ {
+ VehicleWheel& wheelInfo = *wheels[i];
+ if (wheelInfo.m_raycastInfo.m_isInContact)
+ numWheelsOnGround++;
+ m_sideImpulse[i] = real_t(0.);
+ m_forwardImpulse[i] = real_t(0.);
+
+ }
+
+ {
+
+ for (int i=0;i<wheels.size();i++)
+ {
+
+ VehicleWheel& wheelInfo = *wheels[i];
+
+
+ if (wheelInfo.m_raycastInfo.m_isInContact)
+ {
+
+ //const btTransform& wheelTrans = getWheelTransformWS( i );
+
+ Matrix3 wheelBasis0 = wheelInfo.get_global_transform().basis;
+ m_axle[i] = wheelBasis0.get_axis(Vector3::AXIS_X);
+ m_axle[i] = wheelInfo.m_raycastInfo.m_wheelAxleWS;
+
+ const Vector3& surfNormalWS = wheelInfo.m_raycastInfo.m_contactNormalWS;
+ real_t proj = m_axle[i].dot(surfNormalWS);
+ m_axle[i] -= surfNormalWS * proj;
+ m_axle[i] = m_axle[i].normalized();
+
+ m_forwardWS[i] = surfNormalWS.cross(m_axle[i]);
+ m_forwardWS[i].normalize();
+
+
+ _resolve_single_bilateral(s, wheelInfo.m_raycastInfo.m_contactPointWS,
+ wheelInfo.m_raycastInfo.m_groundObject, wheelInfo.m_raycastInfo.m_contactPointWS,
+ m_axle[i],m_sideImpulse[i]);
+
+ m_sideImpulse[i] *= sideFrictionStiffness2;
+
+
+ }
+ }
+ }
+
+ real_t sideFactor = real_t(1.);
+ real_t fwdFactor = 0.5;
+
+ bool sliding = false;
+ {
+ for (int wheel =0;wheel <wheels.size();wheel++)
+ {
+ VehicleWheel& wheelInfo = *wheels[wheel];
+
+
+ //class btRigidBody* groundObject = (class btRigidBody*) wheelInfo.m_raycastInfo.m_groundObject;
+
+ real_t rollingFriction = 0.f;
+
+ if (wheelInfo.m_raycastInfo.m_isInContact)
+ {
+ if (wheelInfo.m_engineForce != 0.f)
+ {
+ rollingFriction = wheelInfo.m_engineForce* s->get_step();
+ } else
+ {
+ real_t defaultRollingFrictionImpulse = 0.f;
+ real_t maxImpulse = wheelInfo.m_brake ? wheelInfo.m_brake : defaultRollingFrictionImpulse;
+ btVehicleWheelContactPoint contactPt(s,wheelInfo.m_raycastInfo.m_groundObject,wheelInfo.m_raycastInfo.m_contactPointWS,m_forwardWS[wheel],maxImpulse);
+ rollingFriction = _calc_rolling_friction(contactPt);
+ }
+ }
+
+ //switch between active rolling (throttle), braking and non-active rolling friction (no throttle/break)
+
+
+
+
+ m_forwardImpulse[wheel] = real_t(0.);
+ wheelInfo.m_skidInfo= real_t(1.);
+
+ if (wheelInfo.m_raycastInfo.m_isInContact)
+ {
+ wheelInfo.m_skidInfo= real_t(1.);
+
+ real_t maximp = wheelInfo.m_wheelsSuspensionForce * s->get_step() * wheelInfo.m_frictionSlip;
+ real_t maximpSide = maximp;
+
+ real_t maximpSquared = maximp * maximpSide;
+
+
+ m_forwardImpulse[wheel] = rollingFriction;//wheelInfo.m_engineForce* timeStep;
+
+ real_t x = (m_forwardImpulse[wheel] ) * fwdFactor;
+ real_t y = (m_sideImpulse[wheel] ) * sideFactor;
+
+ real_t impulseSquared = (x*x + y*y);
+
+ if (impulseSquared > maximpSquared)
+ {
+ sliding = true;
+
+ real_t factor = maximp / Math::sqrt(impulseSquared);
+
+ wheelInfo.m_skidInfo *= factor;
+ }
+ }
+
+ }
+ }
+
+
+
+
+ if (sliding)
+ {
+ for (int wheel = 0;wheel < wheels.size(); wheel++)
+ {
+ if (m_sideImpulse[wheel] != real_t(0.))
+ {
+ if (wheels[wheel]->m_skidInfo< real_t(1.))
+ {
+ m_forwardImpulse[wheel] *= wheels[wheel]->m_skidInfo;
+ m_sideImpulse[wheel] *= wheels[wheel]->m_skidInfo;
+ }
+ }
+ }
+ }
+
+ // apply the impulses
+ {
+ for (int wheel = 0;wheel<wheels.size(); wheel++)
+ {
+ VehicleWheel& wheelInfo = *wheels[wheel];
+
+ Vector3 rel_pos = wheelInfo.m_raycastInfo.m_contactPointWS -
+ s->get_transform().origin;
+
+ if (m_forwardImpulse[wheel] != real_t(0.))
+ {
+ s->apply_impulse(rel_pos,m_forwardWS[wheel]*(m_forwardImpulse[wheel]));
+ }
+ if (m_sideImpulse[wheel] != real_t(0.))
+ {
+ PhysicsBody* groundObject = wheelInfo.m_raycastInfo.m_groundObject;
+
+ Vector3 rel_pos2;
+ if (groundObject) {
+ rel_pos2=wheelInfo.m_raycastInfo.m_contactPointWS - groundObject->get_global_transform().origin;
+ }
+
+
+ Vector3 sideImp = m_axle[wheel] * m_sideImpulse[wheel];
+
+#if defined ROLLING_INFLUENCE_FIX // fix. It only worked if car's up was along Y - VT.
+ Vector3 vChassisWorldUp = s->get_transform().basis.transposed()[1];//getRigidBody()->getCenterOfMassTransform().getBasis().getColumn(m_indexUpAxis);
+ rel_pos -= vChassisWorldUp * (vChassisWorldUp.dot(rel_pos) * (1.f-wheelInfo.m_rollInfluence));
+#else
+ rel_pos[1] *= wheelInfo.m_rollInfluence; //?
+#endif
+ s->apply_impulse(rel_pos,sideImp);
+
+ //apply friction impulse on the ground
+ //todo
+ //groundObject->applyImpulse(-sideImp,rel_pos2);
+ }
+ }
+ }
+
+
+}
+
+
+void VehicleBody::_direct_state_changed(Object *p_state) {
+
+
+ PhysicsDirectBodyState *s = p_state->cast_to<PhysicsDirectBodyState>();
+
+ set_ignore_transform_notification(true);
+ set_global_transform(s->get_transform());
+ set_ignore_transform_notification(false);
+
+
+ float step = s->get_step();
+
+ for(int i=0;i<wheels.size();i++) {
+
+ _update_wheel(i,s);
+ }
+
+ for(int i=0;i<wheels.size();i++) {
+
+ _ray_cast(i,s);
+ }
+
+ _update_suspension(s);
+
+ for(int i=0;i<wheels.size();i++) {
+
+ //apply suspension force
+ VehicleWheel& wheel = *wheels[i];
+
+ real_t suspensionForce = wheel.m_wheelsSuspensionForce;
+
+ if (suspensionForce > wheel.m_maxSuspensionForce)
+ {
+ suspensionForce = wheel.m_maxSuspensionForce;
+ }
+ Vector3 impulse = wheel.m_raycastInfo.m_contactNormalWS * suspensionForce * step;
+ Vector3 relpos = wheel.m_raycastInfo.m_contactPointWS - s->get_transform().origin;
+
+ s->apply_impulse(relpos,impulse);
+ //getRigidBody()->applyImpulse(impulse, relpos);
+
+ }
+
+
+ _update_friction(s);
+
+
+ for (int i=0;i<wheels.size();i++)
+ {
+ VehicleWheel& wheel = *wheels[i];
+ Vector3 relpos = wheel.m_raycastInfo.m_hardPointWS - s->get_transform().origin;
+ Vector3 vel = s->get_linear_velocity() + (s->get_angular_velocity()).cross(relpos);// * mPos);
+
+ if (wheel.m_raycastInfo.m_isInContact)
+ {
+ const Transform& chassisWorldTransform = s->get_transform();
+
+ Vector3 fwd (
+ chassisWorldTransform.basis[0][Vector3::AXIS_Z],
+ chassisWorldTransform.basis[1][Vector3::AXIS_Z],
+ chassisWorldTransform.basis[2][Vector3::AXIS_Z]);
+
+ real_t proj = fwd.dot(wheel.m_raycastInfo.m_contactNormalWS);
+ fwd -= wheel.m_raycastInfo.m_contactNormalWS * proj;
+
+ real_t proj2 = fwd.dot(vel);
+
+ wheel.m_deltaRotation = (proj2 * step) / (wheel.m_wheelRadius);
+ wheel.m_rotation += wheel.m_deltaRotation;
+
+ } else
+ {
+ wheel.m_rotation += wheel.m_deltaRotation;
+ }
+
+ wheel.m_deltaRotation *= real_t(0.99);//damping of rotation when not in contact
+
+ }
+
+}
+
+void VehicleBody::set_mass(real_t p_mass) {
+
+ mass=p_mass;
+ PhysicsServer::get_singleton()->body_set_param(get_rid(),PhysicsServer::BODY_PARAM_MASS,mass);
+}
+
+real_t VehicleBody::get_mass() const{
+
+ return mass;
+}
+
+
+void VehicleBody::set_friction(real_t p_friction) {
+
+ friction=p_friction;
+ PhysicsServer::get_singleton()->body_set_param(get_rid(),PhysicsServer::BODY_PARAM_FRICTION,friction);
+}
+
+real_t VehicleBody::get_friction() const{
+
+ return friction;
+}
+
+void VehicleBody::_bind_methods(){
+
+ ObjectTypeDB::bind_method(_MD("set_mass","mass"),&VehicleBody::set_mass);
+ ObjectTypeDB::bind_method(_MD("get_mass"),&VehicleBody::get_mass);
+
+ ObjectTypeDB::bind_method(_MD("set_friction","friction"),&VehicleBody::set_friction);
+ ObjectTypeDB::bind_method(_MD("get_friction"),&VehicleBody::get_friction);
+
+ ObjectTypeDB::bind_method(_MD("_direct_state_changed"),&VehicleBody::_direct_state_changed);
+
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"body/mass",PROPERTY_HINT_RANGE,"0.01,65536,0.01"),_SCS("set_mass"),_SCS("get_mass"));
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"body/friction",PROPERTY_HINT_RANGE,"0.01,1,0.01"),_SCS("set_friction"),_SCS("get_friction"));
+
+
+}
+
+
+
+VehicleBody::VehicleBody() : PhysicsBody(PhysicsServer::BODY_MODE_RIGID) {
+
+
+ m_pitchControl=0;
+ m_currentVehicleSpeedKmHour = real_t(0.);
+ m_steeringValue = real_t(0.);
+
+
+ mass=1;
+ friction=1;
+
+ ccd=false;
+
+ exclude.insert(get_rid());
+ PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(),this,"_direct_state_changed");
+
+}
+
diff --git a/scene/3d/vehicle_body.h b/scene/3d/vehicle_body.h
new file mode 100644
index 0000000000..97137da699
--- /dev/null
+++ b/scene/3d/vehicle_body.h
@@ -0,0 +1,142 @@
+#ifndef VEHICLE_BODY_H
+#define VEHICLE_BODY_H
+
+#include "scene/3d/physics_body.h"
+
+class VehicleBody;
+
+class VehicleWheel : public Spatial {
+
+ OBJ_TYPE(VehicleWheel,Spatial);
+
+friend class VehicleBody;
+
+
+ Transform m_worldTransform;
+ Transform local_xform;
+
+
+ Vector3 m_chassisConnectionPointCS; //const
+ Vector3 m_wheelDirectionCS;//const
+ Vector3 m_wheelAxleCS; // const or modified by steering
+
+ real_t m_suspensionRestLength;
+ real_t m_maxSuspensionTravelCm;
+ real_t m_wheelRadius;
+
+ real_t m_suspensionStiffness;
+ real_t m_wheelsDampingCompression;
+ real_t m_wheelsDampingRelaxation;
+ real_t m_frictionSlip;
+ real_t m_maxSuspensionForce;
+ bool m_bIsFrontWheel;
+
+ VehicleBody *body;
+
+// btVector3 m_wheelAxleCS; // const or modified by steering ?
+
+ real_t m_steering;
+ real_t m_rotation;
+ real_t m_deltaRotation;
+ real_t m_rollInfluence;
+ real_t m_engineForce;
+ real_t m_brake;
+
+ real_t m_clippedInvContactDotSuspension;
+ real_t m_suspensionRelativeVelocity;
+ //calculated by suspension
+ real_t m_wheelsSuspensionForce;
+ real_t m_skidInfo;
+
+
+ struct RaycastInfo {
+ //set by raycaster
+ Vector3 m_contactNormalWS;//contactnormal
+ Vector3 m_contactPointWS;//raycast hitpoint
+ real_t m_suspensionLength;
+ Vector3 m_hardPointWS;//raycast starting point
+ Vector3 m_wheelDirectionWS; //direction in worldspace
+ Vector3 m_wheelAxleWS; // axle in worldspace
+ bool m_isInContact;
+ PhysicsBody* m_groundObject; //could be general void* ptr
+ } m_raycastInfo;
+
+ void _update(PhysicsDirectBodyState *s);
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+
+
+ VehicleWheel();
+
+};
+
+
+class VehicleBody : public PhysicsBody {
+
+ OBJ_TYPE(VehicleBody,PhysicsBody);
+
+ real_t mass;
+ real_t friction;
+
+ Vector3 linear_velocity;
+ Vector3 angular_velocity;
+ bool ccd;
+
+ real_t m_pitchControl;
+ real_t m_steeringValue;
+ real_t m_currentVehicleSpeedKmHour;
+
+ Set<RID> exclude;
+
+ Vector<Vector3> m_forwardWS;
+ Vector<Vector3> m_axle;
+ Vector<real_t> m_forwardImpulse;
+ Vector<real_t> m_sideImpulse;
+
+ struct btVehicleWheelContactPoint {
+ PhysicsDirectBodyState *m_s;
+ PhysicsBody* m_body1;
+ Vector3 m_frictionPositionWorld;
+ Vector3 m_frictionDirectionWorld;
+ real_t m_jacDiagABInv;
+ real_t m_maxImpulse;
+
+
+ btVehicleWheelContactPoint(PhysicsDirectBodyState *s,PhysicsBody* body1,const Vector3& frictionPosWorld,const Vector3& frictionDirectionWorld, real_t maxImpulse);
+ };
+
+ void _resolve_single_bilateral(PhysicsDirectBodyState *s, const Vector3& pos1, PhysicsBody* body2, const Vector3& pos2, const Vector3& normal, real_t& impulse);
+ real_t _calc_rolling_friction(btVehicleWheelContactPoint& contactPoint);
+
+ void _update_friction(PhysicsDirectBodyState *s);
+ void _update_suspension(PhysicsDirectBodyState *s);
+ real_t _ray_cast(int p_idx,PhysicsDirectBodyState *s);
+ void _update_wheel_transform(VehicleWheel& wheel ,PhysicsDirectBodyState *s);
+ void _update_wheel(int p_idx,PhysicsDirectBodyState *s);
+
+
+
+friend class VehicleWheel;
+ Vector<VehicleWheel*> wheels;
+
+ static void _bind_methods();
+
+ void _direct_state_changed(Object *p_state);
+public:
+
+
+ void set_mass(real_t p_mass);
+ real_t get_mass() const;
+
+ void set_friction(real_t p_friction);
+ real_t get_friction() const;
+
+
+ VehicleBody();
+};
+
+#endif // VEHICLE_BODY_H
diff --git a/scene/3d/visual_instance.cpp b/scene/3d/visual_instance.cpp
index d6c46f9bf6..af535e139f 100644
--- a/scene/3d/visual_instance.cpp
+++ b/scene/3d/visual_instance.cpp
@@ -195,6 +195,7 @@ void GeometryInstance::_notification(int p_what) {
_find_baked_light();
}
+ _update_visibility();
} else if (p_what==NOTIFICATION_EXIT_WORLD) {
@@ -207,8 +208,13 @@ void GeometryInstance::_notification(int p_what) {
_baked_light_changed();
}
+
+ } if (p_what==NOTIFICATION_VISIBILITY_CHANGED) {
+
+ _update_visibility();
}
+
}
void GeometryInstance::_baked_light_changed() {
@@ -241,6 +247,15 @@ void GeometryInstance::_find_baked_light() {
_baked_light_changed();
}
+void GeometryInstance::_update_visibility() {
+
+ if (!is_inside_scene())
+ return;
+
+ _change_notify("geometry/visible");
+ VS::get_singleton()->instance_geometry_set_flag(get_instance(),VS::INSTANCE_FLAG_VISIBLE,is_visible() && flags[FLAG_VISIBLE]);
+}
+
void GeometryInstance::set_flag(Flags p_flag,bool p_value) {
ERR_FAIL_INDEX(p_flag,FLAG_MAX);
@@ -250,8 +265,7 @@ void GeometryInstance::set_flag(Flags p_flag,bool p_value) {
flags[p_flag]=p_value;
VS::get_singleton()->instance_geometry_set_flag(get_instance(),(VS::InstanceFlags)p_flag,p_value);
if (p_flag==FLAG_VISIBLE) {
- _change_notify("geometry/visible");
- emit_signal(SceneStringNames::get_singleton()->visibility_changed);
+ _update_visibility();
}
if (p_flag==FLAG_USE_BAKED_LIGHT) {
@@ -321,7 +335,7 @@ void GeometryInstance::_bind_methods() {
ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/use_baked_light"), _SCS("set_flag"), _SCS("get_flag"),FLAG_USE_BAKED_LIGHT);
ADD_PROPERTY( PropertyInfo( Variant::INT, "geometry/baked_light_tex_id"), _SCS("set_baked_light_texture_id"), _SCS("get_baked_light_texture_id"));
- ADD_SIGNAL( MethodInfo("visibility_changed"));
+// ADD_SIGNAL( MethodInfo("visibility_changed"));
BIND_CONSTANT(FLAG_VISIBLE );
BIND_CONSTANT(FLAG_CAST_SHADOW );
@@ -346,6 +360,7 @@ GeometryInstance::GeometryInstance() {
flags[FLAG_VISIBLE_IN_ALL_ROOMS]=false;
baked_light_instance=NULL;
baked_light_texture_id=0;
+ VS::get_singleton()->instance_geometry_set_baked_light_texture_index(get_instance(),0);
}
diff --git a/scene/3d/visual_instance.h b/scene/3d/visual_instance.h
index 4b4e1e391b..bbb49a2e78 100644
--- a/scene/3d/visual_instance.h
+++ b/scene/3d/visual_instance.h
@@ -109,6 +109,7 @@ private:
int baked_light_texture_id;
void _baked_light_changed();
+ void _update_visibility();
protected:
void _notification(int p_what);