Browse Source

Merge pull request #12403 from AndreaCatania/phymat

Physics material
Juan Linietsky 7 years ago
parent
commit
1ad20dc2f1

+ 14 - 0
modules/bullet/bullet_physics_server.cpp

@@ -647,6 +647,20 @@ float BulletPhysicsServer::body_get_param(RID p_body, BodyParameter p_param) con
 	return body->get_param(p_param);
 	return body->get_param(p_param);
 }
 }
 
 
+void BulletPhysicsServer::body_set_combine_mode(RID p_body, BodyParameter p_param, CombineMode p_mode) {
+	RigidBodyBullet *body = rigid_body_owner.get(p_body);
+	ERR_FAIL_COND(!body);
+
+	body->set_combine_mode(p_param, p_mode);
+}
+
+PhysicsServer::CombineMode BulletPhysicsServer::body_get_combine_mode(RID p_body, BodyParameter p_param) const {
+	RigidBodyBullet *body = rigid_body_owner.get(p_body);
+	ERR_FAIL_COND_V(!body, COMBINE_MODE_INHERIT);
+
+	return body->get_combine_mode(p_param);
+}
+
 void BulletPhysicsServer::body_set_kinematic_safe_margin(RID p_body, real_t p_margin) {
 void BulletPhysicsServer::body_set_kinematic_safe_margin(RID p_body, real_t p_margin) {
 	RigidBodyBullet *body = rigid_body_owner.get(p_body);
 	RigidBodyBullet *body = rigid_body_owner.get(p_body);
 	ERR_FAIL_COND(!body);
 	ERR_FAIL_COND(!body);

+ 3 - 0
modules/bullet/bullet_physics_server.h

@@ -213,6 +213,9 @@ public:
 	virtual void body_set_param(RID p_body, BodyParameter p_param, float p_value);
 	virtual void body_set_param(RID p_body, BodyParameter p_param, float p_value);
 	virtual float body_get_param(RID p_body, BodyParameter p_param) const;
 	virtual float body_get_param(RID p_body, BodyParameter p_param) const;
 
 
+	virtual void body_set_combine_mode(RID p_body, BodyParameter p_param, CombineMode p_mode);
+	virtual CombineMode body_get_combine_mode(RID p_body, BodyParameter p_param) const;
+
 	virtual void body_set_kinematic_safe_margin(RID p_body, real_t p_margin);
 	virtual void body_set_kinematic_safe_margin(RID p_body, real_t p_margin);
 	virtual real_t body_get_kinematic_safe_margin(RID p_body) const;
 	virtual real_t body_get_kinematic_safe_margin(RID p_body) const;
 
 

+ 18 - 0
modules/bullet/rigid_body_bullet.cpp

@@ -257,6 +257,8 @@ RigidBodyBullet::RigidBodyBullet() :
 		angularDamp(0),
 		angularDamp(0),
 		can_sleep(true),
 		can_sleep(true),
 		omit_forces_integration(false),
 		omit_forces_integration(false),
+		restitution_combine_mode(PhysicsServer::COMBINE_MODE_INHERIT),
+		friction_combine_mode(PhysicsServer::COMBINE_MODE_INHERIT),
 		force_integration_callback(NULL),
 		force_integration_callback(NULL),
 		isTransformChanged(false),
 		isTransformChanged(false),
 		previousActiveState(true),
 		previousActiveState(true),
@@ -750,6 +752,22 @@ Vector3 RigidBodyBullet::get_angular_velocity() const {
 	return gVec;
 	return gVec;
 }
 }
 
 
+void RigidBodyBullet::set_combine_mode(const PhysicsServer::BodyParameter p_param, const PhysicsServer::CombineMode p_mode) {
+	if (p_param == PhysicsServer::BODY_PARAM_BOUNCE) {
+		restitution_combine_mode = p_mode;
+	} else {
+		friction_combine_mode = p_mode;
+	}
+}
+
+PhysicsServer::CombineMode RigidBodyBullet::get_combine_mode(PhysicsServer::BodyParameter p_param) const {
+	if (p_param == PhysicsServer::BODY_PARAM_BOUNCE) {
+		return restitution_combine_mode;
+	} else {
+		return friction_combine_mode;
+	}
+}
+
 void RigidBodyBullet::set_transform__bullet(const btTransform &p_global_transform) {
 void RigidBodyBullet::set_transform__bullet(const btTransform &p_global_transform) {
 	if (mode == PhysicsServer::BODY_MODE_KINEMATIC) {
 	if (mode == PhysicsServer::BODY_MODE_KINEMATIC) {
 		// The kinematic use MotionState class
 		// The kinematic use MotionState class

+ 9 - 0
modules/bullet/rigid_body_bullet.h

@@ -200,6 +200,9 @@ private:
 	bool can_sleep;
 	bool can_sleep;
 	bool omit_forces_integration;
 	bool omit_forces_integration;
 
 
+	PhysicsServer::CombineMode restitution_combine_mode;
+	PhysicsServer::CombineMode friction_combine_mode;
+
 	Vector<CollisionData> collisions;
 	Vector<CollisionData> collisions;
 	// these parameters are used to avoid vector resize
 	// these parameters are used to avoid vector resize
 	int maxCollisionsDetection;
 	int maxCollisionsDetection;
@@ -295,6 +298,12 @@ public:
 	void set_angular_velocity(const Vector3 &p_velocity);
 	void set_angular_velocity(const Vector3 &p_velocity);
 	Vector3 get_angular_velocity() const;
 	Vector3 get_angular_velocity() const;
 
 
+	void set_combine_mode(const PhysicsServer::BodyParameter p_param, const PhysicsServer::CombineMode p_mode);
+	PhysicsServer::CombineMode get_combine_mode(PhysicsServer::BodyParameter p_param) const;
+
+	_FORCE_INLINE_ PhysicsServer::CombineMode get_restitution_combine_mode() const { return restitution_combine_mode; }
+	_FORCE_INLINE_ PhysicsServer::CombineMode get_friction_combine_mode() const { return friction_combine_mode; }
+
 	virtual void set_transform__bullet(const btTransform &p_global_transform);
 	virtual void set_transform__bullet(const btTransform &p_global_transform);
 	virtual const btTransform &get_transform__bullet() const;
 	virtual const btTransform &get_transform__bullet() const;
 
 

+ 38 - 1
modules/bullet/space_bullet.cpp

@@ -549,7 +549,43 @@ BulletPhysicsDirectSpaceState *SpaceBullet::get_direct_state() {
 }
 }
 
 
 btScalar calculateGodotCombinedRestitution(const btCollisionObject *body0, const btCollisionObject *body1) {
 btScalar calculateGodotCombinedRestitution(const btCollisionObject *body0, const btCollisionObject *body1) {
-	return MAX(body0->getRestitution(), body1->getRestitution());
+
+	const PhysicsServer::CombineMode cm = static_cast<RigidBodyBullet *>(body0->getUserPointer())->get_restitution_combine_mode();
+
+	switch (cm) {
+		case PhysicsServer::COMBINE_MODE_INHERIT:
+			if (static_cast<RigidBodyBullet *>(body1->getUserPointer())->get_restitution_combine_mode() != PhysicsServer::COMBINE_MODE_INHERIT)
+				return calculateGodotCombinedRestitution(body1, body0);
+			// else use MAX [This is used when the two bodies doesn't use physical material]
+		case PhysicsServer::COMBINE_MODE_MAX:
+			return MAX(body0->getRestitution(), body1->getRestitution());
+		case PhysicsServer::COMBINE_MODE_MIN:
+			return MIN(body0->getRestitution(), body1->getRestitution());
+		case PhysicsServer::COMBINE_MODE_MULTIPLY:
+			return body0->getRestitution() * body1->getRestitution();
+		default: // Is always PhysicsServer::COMBINE_MODE_AVERAGE:
+			return (body0->getRestitution() + body1->getRestitution()) / 2;
+	}
+}
+
+btScalar calculateGodotCombinedFriction(const btCollisionObject *body0, const btCollisionObject *body1) {
+
+	const PhysicsServer::CombineMode cm = static_cast<RigidBodyBullet *>(body0->getUserPointer())->get_friction_combine_mode();
+
+	switch (cm) {
+		case PhysicsServer::COMBINE_MODE_INHERIT:
+			if (static_cast<RigidBodyBullet *>(body1->getUserPointer())->get_friction_combine_mode() != PhysicsServer::COMBINE_MODE_INHERIT)
+				return calculateGodotCombinedFriction(body1, body0);
+			// else use MULTIPLY [This is used when the two bodies doesn't use physical material]
+		case PhysicsServer::COMBINE_MODE_MULTIPLY:
+			return body0->getFriction() * body1->getFriction();
+		case PhysicsServer::COMBINE_MODE_MAX:
+			return MAX(body0->getFriction(), body1->getFriction());
+		case PhysicsServer::COMBINE_MODE_MIN:
+			return MIN(body0->getFriction(), body1->getFriction());
+		default: // Is always PhysicsServer::COMBINE_MODE_AVERAGE:
+			return (body0->getFriction() * body1->getFriction()) / 2;
+	}
 }
 }
 
 
 void SpaceBullet::create_empty_world(bool p_create_soft_world) {
 void SpaceBullet::create_empty_world(bool p_create_soft_world) {
@@ -585,6 +621,7 @@ void SpaceBullet::create_empty_world(bool p_create_soft_world) {
 	ghostPairCallback = bulletnew(btGhostPairCallback);
 	ghostPairCallback = bulletnew(btGhostPairCallback);
 	godotFilterCallback = bulletnew(GodotFilterCallback);
 	godotFilterCallback = bulletnew(GodotFilterCallback);
 	gCalculateCombinedRestitutionCallback = &calculateGodotCombinedRestitution;
 	gCalculateCombinedRestitutionCallback = &calculateGodotCombinedRestitution;
+	gCalculateCombinedFrictionCallback = &calculateGodotCombinedFriction;
 
 
 	dynamicsWorld->setWorldUserInfo(this);
 	dynamicsWorld->setWorldUserInfo(this);
 
 

+ 144 - 16
scene/2d/physics_body_2d.cpp

@@ -30,6 +30,7 @@
 
 
 #include "physics_body_2d.h"
 #include "physics_body_2d.h"
 
 
+#include "core/core_string_names.h"
 #include "core/method_bind_ext.gen.inc"
 #include "core/method_bind_ext.gen.inc"
 #include "engine.h"
 #include "engine.h"
 #include "math_funcs.h"
 #include "math_funcs.h"
@@ -186,28 +187,75 @@ real_t StaticBody2D::get_constant_angular_velocity() const {
 	return constant_angular_velocity;
 	return constant_angular_velocity;
 }
 }
 
 
+#ifndef DISABLE_DEPRECATED
 void StaticBody2D::set_friction(real_t p_friction) {
 void StaticBody2D::set_friction(real_t p_friction) {
 
 
+	ERR_EXPLAIN("The method set_friction has been deprecated and will be removed in the future, use physical material")
+	WARN_DEPRECATED
+
 	ERR_FAIL_COND(p_friction < 0 || p_friction > 1);
 	ERR_FAIL_COND(p_friction < 0 || p_friction > 1);
 
 
-	friction = p_friction;
-	Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, friction);
+	if (physics_material_override.is_null()) {
+		physics_material_override.instance();
+	}
+	physics_material_override->set_friction(p_friction);
+	_reload_physics_characteristics();
 }
 }
+
 real_t StaticBody2D::get_friction() const {
 real_t StaticBody2D::get_friction() const {
 
 
-	return friction;
+	ERR_EXPLAIN("The method get_friction has been deprecated and will be removed in the future, use physical material")
+	WARN_DEPRECATED
+
+	if (physics_material_override.is_null()) {
+		return 1;
+	}
+
+	return physics_material_override->get_friction();
 }
 }
 
 
 void StaticBody2D::set_bounce(real_t p_bounce) {
 void StaticBody2D::set_bounce(real_t p_bounce) {
 
 
+	ERR_EXPLAIN("The method set_bounce has been deprecated and will be removed in the future, use physical material")
+	WARN_DEPRECATED
+
 	ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1);
 	ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1);
 
 
-	bounce = p_bounce;
-	Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, bounce);
+	if (physics_material_override.is_null()) {
+		physics_material_override.instance();
+	}
+	physics_material_override->set_bounce(p_bounce);
+	_reload_physics_characteristics();
 }
 }
+
 real_t StaticBody2D::get_bounce() const {
 real_t StaticBody2D::get_bounce() const {
 
 
-	return bounce;
+	ERR_EXPLAIN("The method get_bounce has been deprecated and will be removed in the future, use physical material")
+	WARN_DEPRECATED
+
+	if (physics_material_override.is_null()) {
+		return 0;
+	}
+
+	return physics_material_override->get_bounce();
+}
+#endif
+
+void StaticBody2D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
+	if (physics_material_override.is_valid()) {
+		physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics");
+	}
+
+	physics_material_override = p_physics_material_override;
+
+	if (physics_material_override.is_valid()) {
+		physics_material_override->connect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics");
+	}
+	_reload_physics_characteristics();
+}
+
+Ref<PhysicsMaterial> StaticBody2D::get_physics_material_override() const {
+	return physics_material_override;
 }
 }
 
 
 void StaticBody2D::_bind_methods() {
 void StaticBody2D::_bind_methods() {
@@ -222,23 +270,41 @@ void StaticBody2D::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_bounce", "bounce"), &StaticBody2D::set_bounce);
 	ClassDB::bind_method(D_METHOD("set_bounce", "bounce"), &StaticBody2D::set_bounce);
 	ClassDB::bind_method(D_METHOD("get_bounce"), &StaticBody2D::get_bounce);
 	ClassDB::bind_method(D_METHOD("get_bounce"), &StaticBody2D::get_bounce);
 
 
+	ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &StaticBody2D::set_physics_material_override);
+	ClassDB::bind_method(D_METHOD("get_physics_material_override"), &StaticBody2D::get_physics_material_override);
+
+	ClassDB::bind_method(D_METHOD("_reload_physics_characteristics"), &StaticBody2D::_reload_physics_characteristics);
+
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "constant_linear_velocity"), "set_constant_linear_velocity", "get_constant_linear_velocity");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "constant_linear_velocity"), "set_constant_linear_velocity", "get_constant_linear_velocity");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "constant_angular_velocity"), "set_constant_angular_velocity", "get_constant_angular_velocity");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "constant_angular_velocity"), "set_constant_angular_velocity", "get_constant_angular_velocity");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_bounce", "get_bounce");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_bounce", "get_bounce");
+	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override");
 }
 }
 
 
 StaticBody2D::StaticBody2D() :
 StaticBody2D::StaticBody2D() :
 		PhysicsBody2D(Physics2DServer::BODY_MODE_STATIC) {
 		PhysicsBody2D(Physics2DServer::BODY_MODE_STATIC) {
 
 
 	constant_angular_velocity = 0;
 	constant_angular_velocity = 0;
-	bounce = 0;
-	friction = 1;
 }
 }
 
 
 StaticBody2D::~StaticBody2D() {
 StaticBody2D::~StaticBody2D() {
 }
 }
 
 
+void StaticBody2D::_reload_physics_characteristics() {
+	if (physics_material_override.is_null()) {
+		Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, 0);
+		Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, 1);
+		Physics2DServer::get_singleton()->body_set_combine_mode(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, Physics2DServer::COMBINE_MODE_INHERIT);
+		Physics2DServer::get_singleton()->body_set_combine_mode(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, Physics2DServer::COMBINE_MODE_INHERIT);
+	} else {
+		Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, physics_material_override->get_bounce());
+		Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, physics_material_override->get_friction());
+		Physics2DServer::get_singleton()->body_set_combine_mode(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, (Physics2DServer::CombineMode)physics_material_override->get_bounce_combine_mode());
+		Physics2DServer::get_singleton()->body_set_combine_mode(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, (Physics2DServer::CombineMode)physics_material_override->get_friction_combine_mode());
+	}
+}
+
 void RigidBody2D::_body_enter_tree(ObjectID p_id) {
 void RigidBody2D::_body_enter_tree(ObjectID p_id) {
 
 
 	Object *obj = ObjectDB::get_instance(p_id);
 	Object *obj = ObjectDB::get_instance(p_id);
@@ -545,28 +611,72 @@ real_t RigidBody2D::get_weight() const {
 	return mass * real_t(GLOBAL_DEF("physics/2d/default_gravity", 98)) / 10;
 	return mass * real_t(GLOBAL_DEF("physics/2d/default_gravity", 98)) / 10;
 }
 }
 
 
+#ifndef DISABLE_DEPRECATED
 void RigidBody2D::set_friction(real_t p_friction) {
 void RigidBody2D::set_friction(real_t p_friction) {
 
 
+	ERR_EXPLAIN("The method set_friction has been deprecated and will be removed in the future, use physical material")
+	WARN_DEPRECATED
 	ERR_FAIL_COND(p_friction < 0 || p_friction > 1);
 	ERR_FAIL_COND(p_friction < 0 || p_friction > 1);
 
 
-	friction = p_friction;
-	Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, friction);
+	if (physics_material_override.is_null()) {
+		physics_material_override.instance();
+	}
+	physics_material_override->set_friction(p_friction);
+	_reload_physics_characteristics();
 }
 }
 real_t RigidBody2D::get_friction() const {
 real_t RigidBody2D::get_friction() const {
 
 
-	return friction;
+	ERR_EXPLAIN("The method get_friction has been deprecated and will be removed in the future, use physical material")
+	WARN_DEPRECATED
+
+	if (physics_material_override.is_null()) {
+		return 1;
+	}
+
+	return physics_material_override->get_friction();
 }
 }
 
 
 void RigidBody2D::set_bounce(real_t p_bounce) {
 void RigidBody2D::set_bounce(real_t p_bounce) {
 
 
+	ERR_EXPLAIN("The method set_bounce has been deprecated and will be removed in the future, use physical material")
+	WARN_DEPRECATED
+
 	ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1);
 	ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1);
 
 
-	bounce = p_bounce;
-	Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, bounce);
+	if (physics_material_override.is_null()) {
+		physics_material_override.instance();
+	}
+	physics_material_override->set_bounce(p_bounce);
+	_reload_physics_characteristics();
 }
 }
 real_t RigidBody2D::get_bounce() const {
 real_t RigidBody2D::get_bounce() const {
 
 
-	return bounce;
+	ERR_EXPLAIN("The method get_bounce has been deprecated and will be removed in the future, use physical material")
+	WARN_DEPRECATED
+
+	if (physics_material_override.is_null()) {
+		return 0;
+	}
+
+	return physics_material_override->get_bounce();
+}
+#endif
+
+void RigidBody2D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
+	if (physics_material_override.is_valid()) {
+		physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics");
+	}
+
+	physics_material_override = p_physics_material_override;
+
+	if (physics_material_override.is_valid()) {
+		physics_material_override->connect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics");
+	}
+	_reload_physics_characteristics();
+}
+
+Ref<PhysicsMaterial> RigidBody2D::get_physics_material_override() const {
+	return physics_material_override;
 }
 }
 
 
 void RigidBody2D::set_gravity_scale(real_t p_gravity_scale) {
 void RigidBody2D::set_gravity_scale(real_t p_gravity_scale) {
@@ -843,6 +953,11 @@ void RigidBody2D::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_bounce", "bounce"), &RigidBody2D::set_bounce);
 	ClassDB::bind_method(D_METHOD("set_bounce", "bounce"), &RigidBody2D::set_bounce);
 	ClassDB::bind_method(D_METHOD("get_bounce"), &RigidBody2D::get_bounce);
 	ClassDB::bind_method(D_METHOD("get_bounce"), &RigidBody2D::get_bounce);
 
 
+	ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &RigidBody2D::set_physics_material_override);
+	ClassDB::bind_method(D_METHOD("get_physics_material_override"), &RigidBody2D::get_physics_material_override);
+
+	ClassDB::bind_method(D_METHOD("_reload_physics_characteristics"), &RigidBody2D::_reload_physics_characteristics);
+
 	ClassDB::bind_method(D_METHOD("set_gravity_scale", "gravity_scale"), &RigidBody2D::set_gravity_scale);
 	ClassDB::bind_method(D_METHOD("set_gravity_scale", "gravity_scale"), &RigidBody2D::set_gravity_scale);
 	ClassDB::bind_method(D_METHOD("get_gravity_scale"), &RigidBody2D::get_gravity_scale);
 	ClassDB::bind_method(D_METHOD("get_gravity_scale"), &RigidBody2D::get_gravity_scale);
 
 
@@ -903,6 +1018,7 @@ void RigidBody2D::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "weight", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01", PROPERTY_USAGE_EDITOR), "set_weight", "get_weight");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "weight", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01", PROPERTY_USAGE_EDITOR), "set_weight", "get_weight");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_bounce", "get_bounce");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_bounce", "get_bounce");
+	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity_scale", PROPERTY_HINT_RANGE, "-128,128,0.01"), "set_gravity_scale", "get_gravity_scale");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity_scale", PROPERTY_HINT_RANGE, "-128,128,0.01"), "set_gravity_scale", "get_gravity_scale");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_integrator"), "set_use_custom_integrator", "is_using_custom_integrator");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_integrator"), "set_use_custom_integrator", "is_using_custom_integrator");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "continuous_cd", PROPERTY_HINT_ENUM, "Disabled,Cast Ray,Cast Shape"), "set_continuous_collision_detection_mode", "get_continuous_collision_detection_mode");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "continuous_cd", PROPERTY_HINT_ENUM, "Disabled,Cast Ray,Cast Shape"), "set_continuous_collision_detection_mode", "get_continuous_collision_detection_mode");
@@ -941,9 +1057,7 @@ RigidBody2D::RigidBody2D() :
 
 
 	mode = MODE_RIGID;
 	mode = MODE_RIGID;
 
 
-	bounce = 0;
 	mass = 1;
 	mass = 1;
-	friction = 1;
 
 
 	gravity_scale = 1;
 	gravity_scale = 1;
 	linear_damp = -1;
 	linear_damp = -1;
@@ -969,6 +1083,20 @@ RigidBody2D::~RigidBody2D() {
 		memdelete(contact_monitor);
 		memdelete(contact_monitor);
 }
 }
 
 
+void RigidBody2D::_reload_physics_characteristics() {
+	if (physics_material_override.is_null()) {
+		Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, 0);
+		Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, 1);
+		Physics2DServer::get_singleton()->body_set_combine_mode(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, Physics2DServer::COMBINE_MODE_INHERIT);
+		Physics2DServer::get_singleton()->body_set_combine_mode(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, Physics2DServer::COMBINE_MODE_INHERIT);
+	} else {
+		Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, physics_material_override->get_bounce());
+		Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, physics_material_override->get_friction());
+		Physics2DServer::get_singleton()->body_set_combine_mode(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, (Physics2DServer::CombineMode)physics_material_override->get_bounce_combine_mode());
+		Physics2DServer::get_singleton()->body_set_combine_mode(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, (Physics2DServer::CombineMode)physics_material_override->get_friction_combine_mode());
+	}
+}
+
 //////////////////////////
 //////////////////////////
 
 
 Ref<KinematicCollision2D> KinematicBody2D::_move(const Vector2 &p_motion, bool p_infinite_inertia, bool p_exclude_raycast_shapes, bool p_test_only) {
 Ref<KinematicCollision2D> KinematicBody2D::_move(const Vector2 &p_motion, bool p_infinite_inertia, bool p_exclude_raycast_shapes, bool p_test_only) {

+ 18 - 4
scene/2d/physics_body_2d.h

@@ -32,6 +32,7 @@
 #define PHYSICS_BODY_2D_H
 #define PHYSICS_BODY_2D_H
 
 
 #include "scene/2d/collision_object_2d.h"
 #include "scene/2d/collision_object_2d.h"
+#include "scene/resources/physics_material.h"
 #include "servers/physics_2d_server.h"
 #include "servers/physics_2d_server.h"
 #include "vset.h"
 #include "vset.h"
 
 
@@ -79,18 +80,21 @@ class StaticBody2D : public PhysicsBody2D {
 	Vector2 constant_linear_velocity;
 	Vector2 constant_linear_velocity;
 	real_t constant_angular_velocity;
 	real_t constant_angular_velocity;
 
 
-	real_t bounce;
-	real_t friction;
+	Ref<PhysicsMaterial> physics_material_override;
 
 
 protected:
 protected:
 	static void _bind_methods();
 	static void _bind_methods();
 
 
 public:
 public:
+#ifndef DISABLE_DEPRECATED
 	void set_friction(real_t p_friction);
 	void set_friction(real_t p_friction);
 	real_t get_friction() const;
 	real_t get_friction() const;
 
 
 	void set_bounce(real_t p_bounce);
 	void set_bounce(real_t p_bounce);
 	real_t get_bounce() const;
 	real_t get_bounce() const;
+#endif
+	void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override);
+	Ref<PhysicsMaterial> get_physics_material_override() const;
 
 
 	void set_constant_linear_velocity(const Vector2 &p_vel);
 	void set_constant_linear_velocity(const Vector2 &p_vel);
 	void set_constant_angular_velocity(real_t p_vel);
 	void set_constant_angular_velocity(real_t p_vel);
@@ -100,6 +104,9 @@ public:
 
 
 	StaticBody2D();
 	StaticBody2D();
 	~StaticBody2D();
 	~StaticBody2D();
+
+private:
+	void _reload_physics_characteristics();
 };
 };
 
 
 class RigidBody2D : public PhysicsBody2D {
 class RigidBody2D : public PhysicsBody2D {
@@ -125,9 +132,8 @@ private:
 	Physics2DDirectBodyState *state;
 	Physics2DDirectBodyState *state;
 	Mode mode;
 	Mode mode;
 
 
-	real_t bounce;
 	real_t mass;
 	real_t mass;
-	real_t friction;
+	Ref<PhysicsMaterial> physics_material_override;
 	real_t gravity_scale;
 	real_t gravity_scale;
 	real_t linear_damp;
 	real_t linear_damp;
 	real_t angular_damp;
 	real_t angular_damp;
@@ -204,11 +210,16 @@ public:
 	void set_weight(real_t p_weight);
 	void set_weight(real_t p_weight);
 	real_t get_weight() const;
 	real_t get_weight() const;
 
 
+#ifndef DISABLE_DEPRECATED
 	void set_friction(real_t p_friction);
 	void set_friction(real_t p_friction);
 	real_t get_friction() const;
 	real_t get_friction() const;
 
 
 	void set_bounce(real_t p_bounce);
 	void set_bounce(real_t p_bounce);
 	real_t get_bounce() const;
 	real_t get_bounce() const;
+#endif
+
+	void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override);
+	Ref<PhysicsMaterial> get_physics_material_override() const;
 
 
 	void set_gravity_scale(real_t p_gravity_scale);
 	void set_gravity_scale(real_t p_gravity_scale);
 	real_t get_gravity_scale() const;
 	real_t get_gravity_scale() const;
@@ -261,6 +272,9 @@ public:
 
 
 	RigidBody2D();
 	RigidBody2D();
 	~RigidBody2D();
 	~RigidBody2D();
+
+private:
+	void _reload_physics_characteristics();
 };
 };
 
 
 VARIANT_ENUM_CAST(RigidBody2D::Mode);
 VARIANT_ENUM_CAST(RigidBody2D::Mode);

+ 142 - 20
scene/3d/physics_body.cpp

@@ -30,6 +30,7 @@
 
 
 #include "physics_body.h"
 #include "physics_body.h"
 
 
+#include "core/core_string_names.h"
 #include "engine.h"
 #include "engine.h"
 #include "method_bind_ext.gen.inc"
 #include "method_bind_ext.gen.inc"
 #include "scene/scene_string_names.h"
 #include "scene/scene_string_names.h"
@@ -178,28 +179,75 @@ PhysicsBody::PhysicsBody(PhysicsServer::BodyMode p_mode) :
 	collision_mask = 1;
 	collision_mask = 1;
 }
 }
 
 
+#ifndef DISABLE_DEPRECATED
 void StaticBody::set_friction(real_t p_friction) {
 void StaticBody::set_friction(real_t p_friction) {
 
 
+	ERR_EXPLAIN("The method set_friction has been deprecated and will be removed in the future, use physical material")
+	WARN_DEPRECATED
+
 	ERR_FAIL_COND(p_friction < 0 || p_friction > 1);
 	ERR_FAIL_COND(p_friction < 0 || p_friction > 1);
 
 
-	friction = p_friction;
-	PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, friction);
+	if (physics_material_override.is_null()) {
+		physics_material_override.instance();
+	}
+	physics_material_override->set_friction(p_friction);
+	_reload_physics_characteristics();
 }
 }
+
 real_t StaticBody::get_friction() const {
 real_t StaticBody::get_friction() const {
 
 
-	return friction;
+	ERR_EXPLAIN("The method get_friction has been deprecated and will be removed in the future, use physical material")
+	WARN_DEPRECATED
+
+	if (physics_material_override.is_null()) {
+		return 1;
+	}
+
+	return physics_material_override->get_friction();
 }
 }
 
 
 void StaticBody::set_bounce(real_t p_bounce) {
 void StaticBody::set_bounce(real_t p_bounce) {
 
 
+	ERR_EXPLAIN("The method set_bounce has been deprecated and will be removed in the future, use physical material")
+	WARN_DEPRECATED
+
 	ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1);
 	ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1);
 
 
-	bounce = p_bounce;
-	PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, bounce);
+	if (physics_material_override.is_null()) {
+		physics_material_override.instance();
+	}
+	physics_material_override->set_bounce(p_bounce);
+	_reload_physics_characteristics();
 }
 }
+
 real_t StaticBody::get_bounce() const {
 real_t StaticBody::get_bounce() const {
 
 
-	return bounce;
+	ERR_EXPLAIN("The method get_bounce has been deprecated and will be removed in the future, use physical material")
+	WARN_DEPRECATED
+
+	if (physics_material_override.is_null()) {
+		return 0;
+	}
+
+	return physics_material_override->get_bounce();
+}
+#endif
+
+void StaticBody::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
+	if (physics_material_override.is_valid()) {
+		physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics");
+	}
+
+	physics_material_override = p_physics_material_override;
+
+	if (physics_material_override.is_valid()) {
+		physics_material_override->connect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics");
+	}
+	_reload_physics_characteristics();
+}
+
+Ref<PhysicsMaterial> StaticBody::get_physics_material_override() const {
+	return physics_material_override;
 }
 }
 
 
 void StaticBody::set_constant_linear_velocity(const Vector3 &p_vel) {
 void StaticBody::set_constant_linear_velocity(const Vector3 &p_vel) {
@@ -236,24 +284,39 @@ void StaticBody::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_bounce", "bounce"), &StaticBody::set_bounce);
 	ClassDB::bind_method(D_METHOD("set_bounce", "bounce"), &StaticBody::set_bounce);
 	ClassDB::bind_method(D_METHOD("get_bounce"), &StaticBody::get_bounce);
 	ClassDB::bind_method(D_METHOD("get_bounce"), &StaticBody::get_bounce);
 
 
+	ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &StaticBody::set_physics_material_override);
+	ClassDB::bind_method(D_METHOD("get_physics_material_override"), &StaticBody::get_physics_material_override);
+
+	ClassDB::bind_method(D_METHOD("_reload_physics_characteristics"), &StaticBody::_reload_physics_characteristics);
+
 	ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody::add_collision_exception_with);
 	ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody::add_collision_exception_with);
 	ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &PhysicsBody::remove_collision_exception_with);
 	ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &PhysicsBody::remove_collision_exception_with);
 
 
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_bounce", "get_bounce");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_bounce", "get_bounce");
-
+	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_linear_velocity"), "set_constant_linear_velocity", "get_constant_linear_velocity");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_linear_velocity"), "set_constant_linear_velocity", "get_constant_linear_velocity");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_angular_velocity"), "set_constant_angular_velocity", "get_constant_angular_velocity");
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_angular_velocity"), "set_constant_angular_velocity", "get_constant_angular_velocity");
 }
 }
 
 
 StaticBody::StaticBody() :
 StaticBody::StaticBody() :
 		PhysicsBody(PhysicsServer::BODY_MODE_STATIC) {
 		PhysicsBody(PhysicsServer::BODY_MODE_STATIC) {
-
-	bounce = 0;
-	friction = 1;
 }
 }
 
 
-StaticBody::~StaticBody() {
+StaticBody::~StaticBody() {}
+
+void StaticBody::_reload_physics_characteristics() {
+	if (physics_material_override.is_null()) {
+		PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, 0);
+		PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, 1);
+		PhysicsServer::get_singleton()->body_set_combine_mode(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, PhysicsServer::COMBINE_MODE_INHERIT);
+		PhysicsServer::get_singleton()->body_set_combine_mode(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, PhysicsServer::COMBINE_MODE_INHERIT);
+	} else {
+		PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, physics_material_override->get_bounce());
+		PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, physics_material_override->get_friction());
+		PhysicsServer::get_singleton()->body_set_combine_mode(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, physics_material_override->get_bounce_combine_mode());
+		PhysicsServer::get_singleton()->body_set_combine_mode(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, physics_material_override->get_friction_combine_mode());
+	}
 }
 }
 
 
 void RigidBody::_body_enter_tree(ObjectID p_id) {
 void RigidBody::_body_enter_tree(ObjectID p_id) {
@@ -550,28 +613,67 @@ real_t RigidBody::get_weight() const {
 	return mass * real_t(GLOBAL_DEF("physics/3d/default_gravity", 9.8));
 	return mass * real_t(GLOBAL_DEF("physics/3d/default_gravity", 9.8));
 }
 }
 
 
+#ifndef DISABLE_DEPRECATED
 void RigidBody::set_friction(real_t p_friction) {
 void RigidBody::set_friction(real_t p_friction) {
 
 
+	ERR_EXPLAIN("The method set_friction has been deprecated and will be removed in the future, use physical material")
+	WARN_DEPRECATED
 	ERR_FAIL_COND(p_friction < 0 || p_friction > 1);
 	ERR_FAIL_COND(p_friction < 0 || p_friction > 1);
 
 
-	friction = p_friction;
-	PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, friction);
+	if (physics_material_override.is_null()) {
+		physics_material_override.instance();
+	}
+	physics_material_override->set_friction(p_friction);
+	_reload_physics_characteristics();
 }
 }
 real_t RigidBody::get_friction() const {
 real_t RigidBody::get_friction() const {
 
 
-	return friction;
+	ERR_EXPLAIN("The method get_friction has been deprecated and will be removed in the future, use physical material")
+	WARN_DEPRECATED
+	if (physics_material_override.is_null()) {
+		return 1;
+	}
+
+	return physics_material_override->get_friction();
 }
 }
 
 
 void RigidBody::set_bounce(real_t p_bounce) {
 void RigidBody::set_bounce(real_t p_bounce) {
-
+	ERR_EXPLAIN("The method set_bounce has been deprecated and will be removed in the future, use physical material")
+	WARN_DEPRECATED
 	ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1);
 	ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1);
 
 
-	bounce = p_bounce;
-	PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, bounce);
+	if (physics_material_override.is_null()) {
+		physics_material_override.instance();
+	}
+	physics_material_override->set_bounce(p_bounce);
+	_reload_physics_characteristics();
 }
 }
 real_t RigidBody::get_bounce() const {
 real_t RigidBody::get_bounce() const {
+	ERR_EXPLAIN("The method get_bounce has been deprecated and will be removed in the future, use physical material")
+	WARN_DEPRECATED
+	if (physics_material_override.is_null()) {
+		return 0;
+	}
 
 
-	return bounce;
+	return physics_material_override->get_bounce();
+}
+#endif
+
+void RigidBody::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
+	if (physics_material_override.is_valid()) {
+		physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics");
+	}
+
+	physics_material_override = p_physics_material_override;
+
+	if (physics_material_override.is_valid()) {
+		physics_material_override->connect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics");
+	}
+	_reload_physics_characteristics();
+}
+
+Ref<PhysicsMaterial> RigidBody::get_physics_material_override() const {
+	return physics_material_override;
 }
 }
 
 
 void RigidBody::set_gravity_scale(real_t p_gravity_scale) {
 void RigidBody::set_gravity_scale(real_t p_gravity_scale) {
@@ -812,6 +914,11 @@ void RigidBody::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_bounce", "bounce"), &RigidBody::set_bounce);
 	ClassDB::bind_method(D_METHOD("set_bounce", "bounce"), &RigidBody::set_bounce);
 	ClassDB::bind_method(D_METHOD("get_bounce"), &RigidBody::get_bounce);
 	ClassDB::bind_method(D_METHOD("get_bounce"), &RigidBody::get_bounce);
 
 
+	ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &RigidBody::set_physics_material_override);
+	ClassDB::bind_method(D_METHOD("get_physics_material_override"), &RigidBody::get_physics_material_override);
+
+	ClassDB::bind_method(D_METHOD("_reload_physics_characteristics"), &RigidBody::_reload_physics_characteristics);
+
 	ClassDB::bind_method(D_METHOD("set_linear_velocity", "linear_velocity"), &RigidBody::set_linear_velocity);
 	ClassDB::bind_method(D_METHOD("set_linear_velocity", "linear_velocity"), &RigidBody::set_linear_velocity);
 	ClassDB::bind_method(D_METHOD("get_linear_velocity"), &RigidBody::get_linear_velocity);
 	ClassDB::bind_method(D_METHOD("get_linear_velocity"), &RigidBody::get_linear_velocity);
 
 
@@ -865,6 +972,7 @@ void RigidBody::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "weight", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01", PROPERTY_USAGE_EDITOR), "set_weight", "get_weight");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "weight", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01", PROPERTY_USAGE_EDITOR), "set_weight", "get_weight");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_bounce", "get_bounce");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_bounce", "get_bounce");
+	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity_scale", PROPERTY_HINT_RANGE, "-128,128,0.01"), "set_gravity_scale", "get_gravity_scale");
 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity_scale", PROPERTY_HINT_RANGE, "-128,128,0.01"), "set_gravity_scale", "get_gravity_scale");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_integrator"), "set_use_custom_integrator", "is_using_custom_integrator");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_integrator"), "set_use_custom_integrator", "is_using_custom_integrator");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "continuous_cd"), "set_use_continuous_collision_detection", "is_using_continuous_collision_detection");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "continuous_cd"), "set_use_continuous_collision_detection", "is_using_continuous_collision_detection");
@@ -903,9 +1011,7 @@ RigidBody::RigidBody() :
 
 
 	mode = MODE_RIGID;
 	mode = MODE_RIGID;
 
 
-	bounce = 0;
 	mass = 1;
 	mass = 1;
-	friction = 1;
 	max_contacts_reported = 0;
 	max_contacts_reported = 0;
 	state = NULL;
 	state = NULL;
 
 
@@ -929,6 +1035,21 @@ RigidBody::~RigidBody() {
 	if (contact_monitor)
 	if (contact_monitor)
 		memdelete(contact_monitor);
 		memdelete(contact_monitor);
 }
 }
+
+void RigidBody::_reload_physics_characteristics() {
+	if (physics_material_override.is_null()) {
+		PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, 0);
+		PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, 1);
+		PhysicsServer::get_singleton()->body_set_combine_mode(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, PhysicsServer::COMBINE_MODE_INHERIT);
+		PhysicsServer::get_singleton()->body_set_combine_mode(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, PhysicsServer::COMBINE_MODE_INHERIT);
+	} else {
+		PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, physics_material_override->get_bounce());
+		PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, physics_material_override->get_friction());
+		PhysicsServer::get_singleton()->body_set_combine_mode(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, physics_material_override->get_bounce_combine_mode());
+		PhysicsServer::get_singleton()->body_set_combine_mode(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, physics_material_override->get_friction_combine_mode());
+	}
+}
+
 //////////////////////////////////////////////////////
 //////////////////////////////////////////////////////
 //////////////////////////
 //////////////////////////
 
 
@@ -2228,6 +2349,7 @@ void PhysicalBone::set_bounce(real_t p_bounce) {
 	bounce = p_bounce;
 	bounce = p_bounce;
 	PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, bounce);
 	PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, bounce);
 }
 }
+
 real_t PhysicalBone::get_bounce() const {
 real_t PhysicalBone::get_bounce() const {
 
 
 	return bounce;
 	return bounce;

+ 19 - 4
scene/3d/physics_body.h

@@ -32,6 +32,7 @@
 #define PHYSICS_BODY__H
 #define PHYSICS_BODY__H
 
 
 #include "scene/3d/collision_object.h"
 #include "scene/3d/collision_object.h"
+#include "scene/resources/physics_material.h"
 #include "servers/physics_server.h"
 #include "servers/physics_server.h"
 #include "skeleton.h"
 #include "skeleton.h"
 #include "vset.h"
 #include "vset.h"
@@ -81,18 +82,22 @@ class StaticBody : public PhysicsBody {
 	Vector3 constant_linear_velocity;
 	Vector3 constant_linear_velocity;
 	Vector3 constant_angular_velocity;
 	Vector3 constant_angular_velocity;
 
 
-	real_t bounce;
-	real_t friction;
+	Ref<PhysicsMaterial> physics_material_override;
 
 
 protected:
 protected:
 	static void _bind_methods();
 	static void _bind_methods();
 
 
 public:
 public:
+#ifndef DISABLE_DEPRECATED
 	void set_friction(real_t p_friction);
 	void set_friction(real_t p_friction);
 	real_t get_friction() const;
 	real_t get_friction() const;
 
 
 	void set_bounce(real_t p_bounce);
 	void set_bounce(real_t p_bounce);
 	real_t get_bounce() const;
 	real_t get_bounce() const;
+#endif
+
+	void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override);
+	Ref<PhysicsMaterial> get_physics_material_override() const;
 
 
 	void set_constant_linear_velocity(const Vector3 &p_vel);
 	void set_constant_linear_velocity(const Vector3 &p_vel);
 	void set_constant_angular_velocity(const Vector3 &p_vel);
 	void set_constant_angular_velocity(const Vector3 &p_vel);
@@ -102,6 +107,9 @@ public:
 
 
 	StaticBody();
 	StaticBody();
 	~StaticBody();
 	~StaticBody();
+
+private:
+	void _reload_physics_characteristics();
 };
 };
 
 
 class RigidBody : public PhysicsBody {
 class RigidBody : public PhysicsBody {
@@ -121,9 +129,8 @@ protected:
 	PhysicsDirectBodyState *state;
 	PhysicsDirectBodyState *state;
 	Mode mode;
 	Mode mode;
 
 
-	real_t bounce;
 	real_t mass;
 	real_t mass;
-	real_t friction;
+	Ref<PhysicsMaterial> physics_material_override;
 
 
 	Vector3 linear_velocity;
 	Vector3 linear_velocity;
 	Vector3 angular_velocity;
 	Vector3 angular_velocity;
@@ -196,11 +203,16 @@ public:
 	void set_weight(real_t p_weight);
 	void set_weight(real_t p_weight);
 	real_t get_weight() const;
 	real_t get_weight() const;
 
 
+#ifndef DISABLE_DEPRECATED
 	void set_friction(real_t p_friction);
 	void set_friction(real_t p_friction);
 	real_t get_friction() const;
 	real_t get_friction() const;
 
 
 	void set_bounce(real_t p_bounce);
 	void set_bounce(real_t p_bounce);
 	real_t get_bounce() const;
 	real_t get_bounce() const;
+#endif
+
+	void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override);
+	Ref<PhysicsMaterial> get_physics_material_override() const;
 
 
 	void set_linear_velocity(const Vector3 &p_velocity);
 	void set_linear_velocity(const Vector3 &p_velocity);
 	Vector3 get_linear_velocity() const;
 	Vector3 get_linear_velocity() const;
@@ -249,6 +261,9 @@ public:
 
 
 	RigidBody();
 	RigidBody();
 	~RigidBody();
 	~RigidBody();
+
+private:
+	void _reload_physics_characteristics();
 };
 };
 
 
 VARIANT_ENUM_CAST(RigidBody::Mode);
 VARIANT_ENUM_CAST(RigidBody::Mode);

+ 0 - 2
scene/3d/vehicle_body.cpp

@@ -942,8 +942,6 @@ VehicleBody::VehicleBody() :
 	engine_force = 0;
 	engine_force = 0;
 	brake = 0;
 	brake = 0;
 
 
-	friction = 1;
-
 	state = NULL;
 	state = NULL;
 	ccd = false;
 	ccd = false;
 
 

+ 3 - 0
scene/register_scene_types.cpp

@@ -203,6 +203,7 @@
 #include "scene/3d/vehicle_body.h"
 #include "scene/3d/vehicle_body.h"
 #include "scene/3d/visibility_notifier.h"
 #include "scene/3d/visibility_notifier.h"
 #include "scene/resources/environment.h"
 #include "scene/resources/environment.h"
+#include "scene/resources/physics_material.h"
 #endif
 #endif
 
 
 static ResourceFormatLoaderTheme *resource_loader_theme = NULL;
 static ResourceFormatLoaderTheme *resource_loader_theme = NULL;
@@ -590,6 +591,8 @@ void register_scene_types() {
 	OS::get_singleton()->yield(); //may take time to init
 	OS::get_singleton()->yield(); //may take time to init
 
 
 	ClassDB::register_class<SpatialVelocityTracker>();
 	ClassDB::register_class<SpatialVelocityTracker>();
+
+	ClassDB::register_class<PhysicsMaterial>();
 #endif
 #endif
 	ClassDB::register_class<World>();
 	ClassDB::register_class<World>();
 	ClassDB::register_class<Environment>();
 	ClassDB::register_class<Environment>();

+ 94 - 0
scene/resources/physics_material.cpp

@@ -0,0 +1,94 @@
+/*************************************************************************/
+/*  physics_material.cpp                                                 */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md)    */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+#include "physics_material.h"
+
+bool PhysicsMaterial::_set(const StringName &p_name, const Variant &p_value) {
+	if (p_name == "bounce") {
+		set_bounce(p_value);
+	} else if (p_name == "bounce_combine_mode") {
+		set_bounce_combine_mode(static_cast<PhysicsServer::CombineMode>(int(p_value)));
+	} else if (p_name == "friction") {
+		set_friction(p_value);
+	} else if (p_name == "friction_combine_mode") {
+		set_friction_combine_mode(static_cast<PhysicsServer::CombineMode>(int(p_value)));
+	} else {
+		return false;
+	}
+
+	emit_changed();
+	return true;
+}
+
+bool PhysicsMaterial::_get(const StringName &p_name, Variant &r_ret) const {
+	if (p_name == "bounce") {
+		r_ret = bounce;
+	} else if (p_name == "bounce_combine_mode") {
+		r_ret = int(bounce_combine_mode);
+	} else if (p_name == "friction") {
+		r_ret = friction;
+	} else if (p_name == "friction_combine_mode") {
+		r_ret = int(friction_combine_mode);
+	} else {
+		return false;
+	}
+
+	return true;
+}
+
+void PhysicsMaterial::_get_property_list(List<PropertyInfo> *p_list) const {
+	p_list->push_back(PropertyInfo(Variant::REAL, "bounce"));
+	p_list->push_back(PropertyInfo(Variant::INT, "bounce_combine_mode", PROPERTY_HINT_ENUM, "Max,Min,Multiply,Average"));
+	p_list->push_back(PropertyInfo(Variant::REAL, "friction"));
+	p_list->push_back(PropertyInfo(Variant::INT, "friction_combine_mode", PROPERTY_HINT_ENUM, "Max,Min,Multiply,Average"));
+}
+
+void PhysicsMaterial::_bind_methods() {}
+
+void PhysicsMaterial::set_bounce(real_t p_val) {
+	bounce = p_val;
+}
+
+void PhysicsMaterial::set_bounce_combine_mode(PhysicsServer::CombineMode p_val) {
+	bounce_combine_mode = p_val;
+}
+
+void PhysicsMaterial::set_friction(real_t p_val) {
+	friction = p_val;
+}
+
+void PhysicsMaterial::set_friction_combine_mode(PhysicsServer::CombineMode p_val) {
+	friction_combine_mode = p_val;
+}
+
+PhysicsMaterial::PhysicsMaterial() :
+		bounce(0),
+		bounce_combine_mode(PhysicsServer::COMBINE_MODE_MAX),
+		friction(0),
+		friction_combine_mode(PhysicsServer::COMBINE_MODE_MULTIPLY) {}

+ 70 - 0
scene/resources/physics_material.h

@@ -0,0 +1,70 @@
+/*************************************************************************/
+/*  physics_material.h                                                   */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md)    */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+#ifndef physics_material_override_H
+#define physics_material_override_H
+
+#include "resource.h"
+#include "servers/physics_server.h"
+
+class PhysicsMaterial : public Resource {
+
+	GDCLASS(PhysicsMaterial, Resource);
+	OBJ_SAVE_TYPE(PhysicsMaterial);
+	RES_BASE_EXTENSION("PhyMat");
+
+	real_t bounce;
+	PhysicsServer::CombineMode bounce_combine_mode;
+	real_t friction;
+	PhysicsServer::CombineMode friction_combine_mode;
+
+protected:
+	bool _set(const StringName &p_name, const Variant &p_value);
+	bool _get(const StringName &p_name, Variant &r_ret) const;
+	void _get_property_list(List<PropertyInfo> *p_list) const;
+
+	static void _bind_methods();
+
+public:
+	void set_bounce(real_t p_val);
+	_FORCE_INLINE_ real_t get_bounce() const { return bounce; }
+
+	void set_bounce_combine_mode(PhysicsServer::CombineMode p_val);
+	_FORCE_INLINE_ PhysicsServer::CombineMode get_bounce_combine_mode() const { return bounce_combine_mode; }
+
+	void set_friction(real_t p_val);
+	_FORCE_INLINE_ real_t get_friction() const { return friction; }
+
+	void set_friction_combine_mode(PhysicsServer::CombineMode p_val);
+	_FORCE_INLINE_ PhysicsServer::CombineMode get_friction_combine_mode() const { return friction_combine_mode; }
+
+	PhysicsMaterial();
+};
+
+#endif // physics_material_override_H

+ 40 - 2
servers/physics/body_pair_sw.cpp

@@ -211,6 +211,44 @@ bool BodyPairSW::_test_ccd(real_t p_step, BodySW *p_A, int p_shape_A, const Tran
 	return true;
 	return true;
 }
 }
 
 
+real_t combine_bounce(BodySW *A, BodySW *B) {
+	const PhysicsServer::CombineMode cm = A->get_bounce_combine_mode();
+
+	switch (cm) {
+		case PhysicsServer::COMBINE_MODE_INHERIT:
+			if (B->get_bounce_combine_mode() != PhysicsServer::COMBINE_MODE_INHERIT)
+				return combine_bounce(B, A);
+			// else use MAX [This is used when the two bodies doesn't use physical material]
+		case PhysicsServer::COMBINE_MODE_MAX:
+			return MAX(A->get_bounce(), B->get_bounce());
+		case PhysicsServer::COMBINE_MODE_MIN:
+			return MIN(A->get_bounce(), B->get_bounce());
+		case PhysicsServer::COMBINE_MODE_MULTIPLY:
+			return A->get_bounce() * B->get_bounce();
+		default: // Is always PhysicsServer::COMBINE_MODE_AVERAGE:
+			return (A->get_bounce() + B->get_bounce()) / 2;
+	}
+}
+
+real_t combine_friction(BodySW *A, BodySW *B) {
+	const PhysicsServer::CombineMode cm = A->get_friction_combine_mode();
+
+	switch (cm) {
+		case PhysicsServer::COMBINE_MODE_INHERIT:
+			if (B->get_friction_combine_mode() != PhysicsServer::COMBINE_MODE_INHERIT)
+				return combine_friction(B, A);
+			// else use Multiply [This is used when the two bodies doesn't use physical material]
+		case PhysicsServer::COMBINE_MODE_MULTIPLY:
+			return A->get_friction() * B->get_friction();
+		case PhysicsServer::COMBINE_MODE_MAX:
+			return MAX(A->get_friction(), B->get_friction());
+		case PhysicsServer::COMBINE_MODE_MIN:
+			return MIN(A->get_friction(), B->get_friction());
+		default: // Is always PhysicsServer::COMBINE_MODE_AVERAGE:
+			return (A->get_friction() + B->get_friction()) / 2;
+	}
+}
+
 bool BodyPairSW::setup(real_t p_step) {
 bool BodyPairSW::setup(real_t p_step) {
 
 
 	//cannot collide
 	//cannot collide
@@ -331,7 +369,7 @@ bool BodyPairSW::setup(real_t p_step) {
 		c.acc_bias_impulse = 0;
 		c.acc_bias_impulse = 0;
 		c.acc_bias_impulse_center_of_mass = 0;
 		c.acc_bias_impulse_center_of_mass = 0;
 
 
-		c.bounce = MAX(A->get_bounce(), B->get_bounce());
+		c.bounce = combine_bounce(A, B);
 		if (c.bounce) {
 		if (c.bounce) {
 
 
 			Vector3 crA = A->get_angular_velocity().cross(c.rA);
 			Vector3 crA = A->get_angular_velocity().cross(c.rA);
@@ -421,7 +459,7 @@ void BodyPairSW::solve(real_t p_step) {
 
 
 		//friction impulse
 		//friction impulse
 
 
-		real_t friction = A->get_friction() * B->get_friction();
+		real_t friction = combine_friction(A, B);
 
 
 		Vector3 lvA = A->get_linear_velocity() + A->get_angular_velocity().cross(c.rA);
 		Vector3 lvA = A->get_linear_velocity() + A->get_angular_velocity().cross(c.rA);
 		Vector3 lvB = B->get_linear_velocity() + B->get_angular_velocity().cross(c.rB);
 		Vector3 lvB = B->get_linear_velocity() + B->get_angular_velocity().cross(c.rB);

+ 16 - 0
servers/physics/body_sw.cpp

@@ -423,6 +423,22 @@ void BodySW::_compute_area_gravity_and_dampenings(const AreaSW *p_area) {
 	area_angular_damp += p_area->get_angular_damp();
 	area_angular_damp += p_area->get_angular_damp();
 }
 }
 
 
+void BodySW::set_combine_mode(PhysicsServer::BodyParameter p_param, PhysicsServer::CombineMode p_mode) {
+	if (p_param == PhysicsServer::BODY_PARAM_BOUNCE) {
+		bounce_combine_mode = p_mode;
+	} else {
+		friction_combine_mode = p_mode;
+	}
+}
+
+PhysicsServer::CombineMode BodySW::get_combine_mode(PhysicsServer::BodyParameter p_param) const {
+	if (p_param == PhysicsServer::BODY_PARAM_BOUNCE) {
+		return bounce_combine_mode;
+	} else {
+		return friction_combine_mode;
+	}
+}
+
 void BodySW::set_axis_lock(PhysicsServer::BodyAxis p_axis, bool lock) {
 void BodySW::set_axis_lock(PhysicsServer::BodyAxis p_axis, bool lock) {
 	if (lock) {
 	if (lock) {
 		locked_axis |= p_axis;
 		locked_axis |= p_axis;

+ 8 - 0
servers/physics/body_sw.h

@@ -49,6 +49,8 @@ class BodySW : public CollisionObjectSW {
 	real_t mass;
 	real_t mass;
 	real_t bounce;
 	real_t bounce;
 	real_t friction;
 	real_t friction;
+	PhysicsServer::CombineMode bounce_combine_mode;
+	PhysicsServer::CombineMode friction_combine_mode;
 
 
 	real_t linear_damp;
 	real_t linear_damp;
 	real_t angular_damp;
 	real_t angular_damp;
@@ -298,6 +300,12 @@ public:
 	_FORCE_INLINE_ Vector3 get_gravity() const { return gravity; }
 	_FORCE_INLINE_ Vector3 get_gravity() const { return gravity; }
 	_FORCE_INLINE_ real_t get_bounce() const { return bounce; }
 	_FORCE_INLINE_ real_t get_bounce() const { return bounce; }
 
 
+	void set_combine_mode(PhysicsServer::BodyParameter p_param, PhysicsServer::CombineMode p_mode);
+	PhysicsServer::CombineMode get_combine_mode(PhysicsServer::BodyParameter p_param) const;
+
+	_FORCE_INLINE_ PhysicsServer::CombineMode get_bounce_combine_mode() const { return bounce_combine_mode; }
+	_FORCE_INLINE_ PhysicsServer::CombineMode get_friction_combine_mode() const { return friction_combine_mode; }
+
 	void set_axis_lock(PhysicsServer::BodyAxis p_axis, bool lock);
 	void set_axis_lock(PhysicsServer::BodyAxis p_axis, bool lock);
 	bool is_axis_locked(PhysicsServer::BodyAxis p_axis) const;
 	bool is_axis_locked(PhysicsServer::BodyAxis p_axis) const;
 
 

+ 14 - 0
servers/physics/physics_server_sw.cpp

@@ -701,6 +701,20 @@ real_t PhysicsServerSW::body_get_param(RID p_body, BodyParameter p_param) const
 	return body->get_param(p_param);
 	return body->get_param(p_param);
 };
 };
 
 
+void PhysicsServerSW::body_set_combine_mode(RID p_body, BodyParameter p_param, CombineMode p_mode) {
+	BodySW *body = body_owner.get(p_body);
+	ERR_FAIL_COND(!body);
+
+	body->set_combine_mode(p_param, p_mode);
+}
+
+PhysicsServer::CombineMode PhysicsServerSW::body_get_combine_mode(RID p_body, BodyParameter p_param) const {
+	BodySW *body = body_owner.get(p_body);
+	ERR_FAIL_COND_V(!body, COMBINE_MODE_INHERIT);
+
+	return body->get_combine_mode(p_param);
+}
+
 void PhysicsServerSW::body_set_kinematic_safe_margin(RID p_body, real_t p_margin) {
 void PhysicsServerSW::body_set_kinematic_safe_margin(RID p_body, real_t p_margin) {
 	BodySW *body = body_owner.get(p_body);
 	BodySW *body = body_owner.get(p_body);
 	ERR_FAIL_COND(!body);
 	ERR_FAIL_COND(!body);

+ 4 - 0
servers/physics/physics_server_sw.h

@@ -188,6 +188,10 @@ public:
 	virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value);
 	virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value);
 	virtual real_t body_get_param(RID p_body, BodyParameter p_param) const;
 	virtual real_t body_get_param(RID p_body, BodyParameter p_param) const;
 
 
+	/// p_param accept only Bounce and Friction
+	virtual void body_set_combine_mode(RID p_body, BodyParameter p_param, CombineMode p_mode);
+	virtual CombineMode body_get_combine_mode(RID p_body, BodyParameter p_param) const;
+
 	virtual void body_set_kinematic_safe_margin(RID p_body, real_t p_margin);
 	virtual void body_set_kinematic_safe_margin(RID p_body, real_t p_margin);
 	virtual real_t body_get_kinematic_safe_margin(RID p_body) const;
 	virtual real_t body_get_kinematic_safe_margin(RID p_body) const;
 
 

+ 16 - 0
servers/physics_2d/body_2d_sw.cpp

@@ -405,6 +405,22 @@ void Body2DSW::_compute_area_gravity_and_dampenings(const Area2DSW *p_area) {
 	area_angular_damp += p_area->get_angular_damp();
 	area_angular_damp += p_area->get_angular_damp();
 }
 }
 
 
+void Body2DSW::set_combine_mode(Physics2DServer::BodyParameter p_param, Physics2DServer::CombineMode p_mode) {
+	if (p_param == Physics2DServer::BODY_PARAM_BOUNCE) {
+		bounce_combine_mode = p_mode;
+	} else {
+		friction_combine_mode = p_mode;
+	}
+}
+
+Physics2DServer::CombineMode Body2DSW::get_combine_mode(Physics2DServer::BodyParameter p_param) const {
+	if (p_param == Physics2DServer::BODY_PARAM_BOUNCE) {
+		return bounce_combine_mode;
+	} else {
+		return friction_combine_mode;
+	}
+}
+
 void Body2DSW::integrate_forces(real_t p_step) {
 void Body2DSW::integrate_forces(real_t p_step) {
 
 
 	if (mode == Physics2DServer::BODY_MODE_STATIC)
 	if (mode == Physics2DServer::BODY_MODE_STATIC)

+ 8 - 0
servers/physics_2d/body_2d_sw.h

@@ -54,6 +54,8 @@ class Body2DSW : public CollisionObject2DSW {
 	real_t mass;
 	real_t mass;
 	real_t bounce;
 	real_t bounce;
 	real_t friction;
 	real_t friction;
+	Physics2DServer::CombineMode bounce_combine_mode;
+	Physics2DServer::CombineMode friction_combine_mode;
 
 
 	real_t _inv_mass;
 	real_t _inv_mass;
 	real_t _inv_inertia;
 	real_t _inv_inertia;
@@ -256,6 +258,12 @@ public:
 	_FORCE_INLINE_ real_t get_linear_damp() const { return linear_damp; }
 	_FORCE_INLINE_ real_t get_linear_damp() const { return linear_damp; }
 	_FORCE_INLINE_ real_t get_angular_damp() const { return angular_damp; }
 	_FORCE_INLINE_ real_t get_angular_damp() const { return angular_damp; }
 
 
+	void set_combine_mode(Physics2DServer::BodyParameter p_param, Physics2DServer::CombineMode p_mode);
+	Physics2DServer::CombineMode get_combine_mode(Physics2DServer::BodyParameter p_param) const;
+
+	_FORCE_INLINE_ Physics2DServer::CombineMode get_bounce_combine_mode() const { return bounce_combine_mode; }
+	_FORCE_INLINE_ Physics2DServer::CombineMode get_friction_combine_mode() const { return friction_combine_mode; }
+
 	void integrate_forces(real_t p_step);
 	void integrate_forces(real_t p_step);
 	void integrate_velocities(real_t p_step);
 	void integrate_velocities(real_t p_step);
 
 

+ 40 - 2
servers/physics_2d/body_pair_2d_sw.cpp

@@ -219,6 +219,44 @@ bool BodyPair2DSW::_test_ccd(real_t p_step, Body2DSW *p_A, int p_shape_A, const
 	return true;
 	return true;
 }
 }
 
 
+real_t combine_bounce(Body2DSW *A, Body2DSW *B) {
+	const Physics2DServer::CombineMode cm = A->get_bounce_combine_mode();
+
+	switch (cm) {
+		case Physics2DServer::COMBINE_MODE_INHERIT:
+			if (B->get_bounce_combine_mode() != Physics2DServer::COMBINE_MODE_INHERIT)
+				return combine_bounce(B, A);
+			// else use MAX [This is used when the two bodies doesn't use physical material]
+		case Physics2DServer::COMBINE_MODE_MAX:
+			return MAX(A->get_bounce(), B->get_bounce());
+		case Physics2DServer::COMBINE_MODE_MIN:
+			return MIN(A->get_bounce(), B->get_bounce());
+		case Physics2DServer::COMBINE_MODE_MULTIPLY:
+			return A->get_bounce() * B->get_bounce();
+		default: // Is always Physics2DServer::COMBINE_MODE_AVERAGE:
+			return (A->get_bounce() + B->get_bounce()) / 2;
+	}
+}
+
+real_t combine_friction(Body2DSW *A, Body2DSW *B) {
+	const Physics2DServer::CombineMode cm = A->get_friction_combine_mode();
+
+	switch (cm) {
+		case Physics2DServer::COMBINE_MODE_INHERIT:
+			if (B->get_friction_combine_mode() != Physics2DServer::COMBINE_MODE_INHERIT)
+				return combine_friction(B, A);
+			// else use Multiply [This is used when the two bodies doesn't use physical material]
+		case Physics2DServer::COMBINE_MODE_MULTIPLY:
+			return A->get_friction() * B->get_friction();
+		case Physics2DServer::COMBINE_MODE_MAX:
+			return MAX(A->get_friction(), B->get_friction());
+		case Physics2DServer::COMBINE_MODE_MIN:
+			return MIN(A->get_friction(), B->get_friction());
+		default: // Is always Physics2DServer::COMBINE_MODE_AVERAGE:
+			return (A->get_friction() + B->get_friction()) / 2;
+	}
+}
+
 bool BodyPair2DSW::setup(real_t p_step) {
 bool BodyPair2DSW::setup(real_t p_step) {
 
 
 	//cannot collide
 	//cannot collide
@@ -432,7 +470,7 @@ bool BodyPair2DSW::setup(real_t p_step) {
 
 
 #endif
 #endif
 
 
-		c.bounce = MAX(A->get_bounce(), B->get_bounce());
+		c.bounce = combine_bounce(A, B);
 		if (c.bounce) {
 		if (c.bounce) {
 
 
 			Vector2 crA(-A->get_angular_velocity() * c.rA.y, A->get_angular_velocity() * c.rA.x);
 			Vector2 crA(-A->get_angular_velocity() * c.rA.y, A->get_angular_velocity() * c.rA.x);
@@ -488,7 +526,7 @@ void BodyPair2DSW::solve(real_t p_step) {
 		real_t jnOld = c.acc_normal_impulse;
 		real_t jnOld = c.acc_normal_impulse;
 		c.acc_normal_impulse = MAX(jnOld + jn, 0.0f);
 		c.acc_normal_impulse = MAX(jnOld + jn, 0.0f);
 
 
-		real_t friction = A->get_friction() * B->get_friction();
+		real_t friction = combine_friction(A, B);
 
 
 		real_t jtMax = friction * c.acc_normal_impulse;
 		real_t jtMax = friction * c.acc_normal_impulse;
 		real_t jt = -vt * c.mass_tangent;
 		real_t jt = -vt * c.mass_tangent;

+ 16 - 0
servers/physics_2d/physics_2d_server_sw.cpp

@@ -789,6 +789,22 @@ real_t Physics2DServerSW::body_get_param(RID p_body, BodyParameter p_param) cons
 	return body->get_param(p_param);
 	return body->get_param(p_param);
 };
 };
 
 
+void Physics2DServerSW::body_set_combine_mode(RID p_body, BodyParameter p_param, CombineMode p_mode) {
+
+	Body2DSW *body = body_owner.get(p_body);
+	ERR_FAIL_COND(!body);
+
+	body->set_combine_mode(p_param, p_mode);
+}
+
+Physics2DServer::CombineMode Physics2DServerSW::body_get_combine_mode(RID p_body, BodyParameter p_param) const {
+
+	Body2DSW *body = body_owner.get(p_body);
+	ERR_FAIL_COND_V(!body, COMBINE_MODE_INHERIT);
+
+	return body->get_combine_mode(p_param);
+}
+
 void Physics2DServerSW::body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) {
 void Physics2DServerSW::body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) {
 
 
 	Body2DSW *body = body_owner.get(p_body);
 	Body2DSW *body = body_owner.get(p_body);

+ 4 - 0
servers/physics_2d/physics_2d_server_sw.h

@@ -200,6 +200,10 @@ public:
 	virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value);
 	virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value);
 	virtual real_t body_get_param(RID p_body, BodyParameter p_param) const;
 	virtual real_t body_get_param(RID p_body, BodyParameter p_param) const;
 
 
+	/// p_param accept only Bounce and Friction
+	virtual void body_set_combine_mode(RID p_body, BodyParameter p_param, CombineMode p_mode);
+	virtual CombineMode body_get_combine_mode(RID p_body, BodyParameter p_param) const;
+
 	virtual void body_set_state(RID p_body, BodyState p_state, const Variant &p_variant);
 	virtual void body_set_state(RID p_body, BodyState p_state, const Variant &p_variant);
 	virtual Variant body_get_state(RID p_body, BodyState p_state) const;
 	virtual Variant body_get_state(RID p_body, BodyState p_state) const;
 
 

+ 3 - 0
servers/physics_2d/physics_2d_server_wrap_mt.h

@@ -211,6 +211,9 @@ public:
 	FUNC3(body_set_param, RID, BodyParameter, real_t);
 	FUNC3(body_set_param, RID, BodyParameter, real_t);
 	FUNC2RC(real_t, body_get_param, RID, BodyParameter);
 	FUNC2RC(real_t, body_get_param, RID, BodyParameter);
 
 
+	FUNC3(body_set_combine_mode, RID, BodyParameter, CombineMode);
+	FUNC2RC(CombineMode, body_get_combine_mode, RID, BodyParameter);
+
 	FUNC3(body_set_state, RID, BodyState, const Variant &);
 	FUNC3(body_set_state, RID, BodyState, const Variant &);
 	FUNC2RC(Variant, body_get_state, RID, BodyState);
 	FUNC2RC(Variant, body_get_state, RID, BodyState);
 
 

+ 13 - 0
servers/physics_2d_server.h

@@ -416,6 +416,19 @@ public:
 	virtual void body_set_param(RID p_body, BodyParameter p_param, float p_value) = 0;
 	virtual void body_set_param(RID p_body, BodyParameter p_param, float p_value) = 0;
 	virtual float body_get_param(RID p_body, BodyParameter p_param) const = 0;
 	virtual float body_get_param(RID p_body, BodyParameter p_param) const = 0;
 
 
+	enum CombineMode {
+		COMBINE_MODE_MAX,
+		COMBINE_MODE_MIN,
+		COMBINE_MODE_MULTIPLY,
+		COMBINE_MODE_AVERAGE,
+
+		COMBINE_MODE_INHERIT /// Inherit from other body or use COMBINE_MODE_MAX (Restitution) COMBINE_MODE_MULTIPLY (Friction)
+	};
+
+	/// p_param accept only Bounce and Friction
+	virtual void body_set_combine_mode(RID p_body, BodyParameter p_param, CombineMode p_mode) = 0;
+	virtual CombineMode body_get_combine_mode(RID p_body, BodyParameter p_param) const = 0;
+
 	//state
 	//state
 	enum BodyState {
 	enum BodyState {
 		BODY_STATE_TRANSFORM,
 		BODY_STATE_TRANSFORM,

+ 13 - 0
servers/physics_server.h

@@ -399,6 +399,19 @@ public:
 	virtual void body_set_param(RID p_body, BodyParameter p_param, float p_value) = 0;
 	virtual void body_set_param(RID p_body, BodyParameter p_param, float p_value) = 0;
 	virtual float body_get_param(RID p_body, BodyParameter p_param) const = 0;
 	virtual float body_get_param(RID p_body, BodyParameter p_param) const = 0;
 
 
+	enum CombineMode {
+		COMBINE_MODE_MAX,
+		COMBINE_MODE_MIN,
+		COMBINE_MODE_MULTIPLY,
+		COMBINE_MODE_AVERAGE,
+
+		COMBINE_MODE_INHERIT /// Inherit from other body or use COMBINE_MODE_MAX (Restitution) COMBINE_MODE_MULTIPLY (Friction)
+	};
+
+	/// p_param accept only Bounce and Friction
+	virtual void body_set_combine_mode(RID p_body, BodyParameter p_param, CombineMode p_mode) = 0;
+	virtual CombineMode body_get_combine_mode(RID p_body, BodyParameter p_param) const = 0;
+
 	virtual void body_set_kinematic_safe_margin(RID p_body, real_t p_margin) = 0;
 	virtual void body_set_kinematic_safe_margin(RID p_body, real_t p_margin) = 0;
 	virtual real_t body_get_kinematic_safe_margin(RID p_body) const = 0;
 	virtual real_t body_get_kinematic_safe_margin(RID p_body) const = 0;