Browse Source

Merge pull request #47139 from nekomatata/concave-backface-collision

Disable backface collision with ConcavePolygonShape by default
Rémi Verschelde 4 years ago
parent
commit
793000c6a9

+ 5 - 0
doc/classes/ConcavePolygonShape3D.xml

@@ -28,6 +28,11 @@
 			</description>
 		</method>
 	</methods>
+	<members>
+		<member name="backface_collision" type="bool" setter="set_backface_collision_enabled" getter="is_backface_collision_enabled" default="false">
+			If set to [code]true[/code], collisions occur on both sides of the concave shape faces. Otherwise they occur only along the face normals.
+		</member>
+	</members>
 	<constants>
 	</constants>
 </class>

+ 8 - 2
modules/bullet/shape_bullet.cpp

@@ -375,11 +375,17 @@ ConcavePolygonShapeBullet::~ConcavePolygonShapeBullet() {
 }
 
 void ConcavePolygonShapeBullet::set_data(const Variant &p_data) {
-	setup(p_data);
+	Dictionary d = p_data;
+	ERR_FAIL_COND(!d.has("faces"));
+
+	setup(d["faces"]);
 }
 
 Variant ConcavePolygonShapeBullet::get_data() const {
-	return faces;
+	Dictionary d;
+	d["faces"] = faces;
+
+	return d;
 }
 
 PhysicsServer3D::ShapeType ConcavePolygonShapeBullet::get_type() const {

+ 30 - 7
scene/resources/concave_polygon_shape_3d.cpp

@@ -35,13 +35,12 @@
 Vector<Vector3> ConcavePolygonShape3D::get_debug_mesh_lines() const {
 	Set<DrawEdge> edges;
 
-	Vector<Vector3> data = get_faces();
-	int datalen = data.size();
-	ERR_FAIL_COND_V((datalen % 3) != 0, Vector<Vector3>());
+	int index_count = faces.size();
+	ERR_FAIL_COND_V((index_count % 3) != 0, Vector<Vector3>());
 
-	const Vector3 *r = data.ptr();
+	const Vector3 *r = faces.ptr();
 
-	for (int i = 0; i < datalen; i += 3) {
+	for (int i = 0; i < index_count; i += 3) {
 		for (int j = 0; j < 3; j++) {
 			DrawEdge de(r[i + j], r[i + ((j + 1) % 3)]);
 			edges.insert(de);
@@ -71,22 +70,46 @@ real_t ConcavePolygonShape3D::get_enclosing_radius() const {
 }
 
 void ConcavePolygonShape3D::_update_shape() {
+	Dictionary d;
+	d["faces"] = faces;
+	d["backface_collision"] = backface_collision;
+	PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), d);
+
 	Shape3D::_update_shape();
 }
 
 void ConcavePolygonShape3D::set_faces(const Vector<Vector3> &p_faces) {
-	PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), p_faces);
+	faces = p_faces;
+	_update_shape();
 	notify_change_to_owners();
 }
 
 Vector<Vector3> ConcavePolygonShape3D::get_faces() const {
-	return PhysicsServer3D::get_singleton()->shape_get_data(get_shape());
+	return faces;
+}
+
+void ConcavePolygonShape3D::set_backface_collision_enabled(bool p_enabled) {
+	backface_collision = p_enabled;
+
+	if (!faces.is_empty()) {
+		_update_shape();
+		notify_change_to_owners();
+	}
+}
+
+bool ConcavePolygonShape3D::is_backface_collision_enabled() const {
+	return backface_collision;
 }
 
 void ConcavePolygonShape3D::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_faces", "faces"), &ConcavePolygonShape3D::set_faces);
 	ClassDB::bind_method(D_METHOD("get_faces"), &ConcavePolygonShape3D::get_faces);
+
+	ClassDB::bind_method(D_METHOD("set_backface_collision_enabled", "enabled"), &ConcavePolygonShape3D::set_backface_collision_enabled);
+	ClassDB::bind_method(D_METHOD("is_backface_collision_enabled"), &ConcavePolygonShape3D::is_backface_collision_enabled);
+
 	ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_faces", "get_faces");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "backface_collision"), "set_backface_collision_enabled", "is_backface_collision_enabled");
 }
 
 ConcavePolygonShape3D::ConcavePolygonShape3D() :

+ 6 - 0
scene/resources/concave_polygon_shape_3d.h

@@ -36,6 +36,9 @@
 class ConcavePolygonShape3D : public Shape3D {
 	GDCLASS(ConcavePolygonShape3D, Shape3D);
 
+	Vector<Vector3> faces;
+	bool backface_collision = false;
+
 	struct DrawEdge {
 		Vector3 a;
 		Vector3 b;
@@ -65,6 +68,9 @@ public:
 	void set_faces(const Vector<Vector3> &p_faces);
 	Vector<Vector3> get_faces() const;
 
+	void set_backface_collision_enabled(bool p_enabled);
+	bool is_backface_collision_enabled() const;
+
 	virtual Vector<Vector3> get_debug_mesh_lines() const override;
 	virtual real_t get_enclosing_radius() const override;
 

+ 118 - 31
servers/physics_3d/collision_solver_3d_sat.cpp

@@ -626,7 +626,7 @@ public:
 		}
 	}
 
-	_FORCE_INLINE_ bool test_axis(const Vector3 &p_axis) {
+	_FORCE_INLINE_ bool test_axis(const Vector3 &p_axis, bool p_directional = false) {
 		Vector3 axis = p_axis;
 
 		if (Math::abs(axis.x) < CMP_EPSILON &&
@@ -662,7 +662,12 @@ public:
 		//use the smallest depth
 
 		if (min_B < 0.0) { // could be +0.0, we don't want it to become -0.0
-			min_B = -min_B;
+			if (p_directional) {
+				min_B = max_B;
+				axis = -axis;
+			} else {
+				min_B = -min_B;
+			}
 		}
 
 		if (max_B < min_B) {
@@ -1006,23 +1011,31 @@ static void _collision_sphere_face(const Shape3DSW *p_a, const Transform &p_tran
 		p_transform_b.xform(face_B->vertex[2]),
 	};
 
-	if (!separator.test_axis((vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized())) {
+	Vector3 normal = (vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized();
+
+	if (!separator.test_axis(normal, !face_B->backface_collision)) {
 		return;
 	}
 
 	// edges and points of B
 	for (int i = 0; i < 3; i++) {
 		Vector3 n1 = vertex[i] - p_transform_a.origin;
+		if (n1.dot(normal) < 0.0) {
+			n1 *= -1.0;
+		}
 
-		if (!separator.test_axis(n1.normalized())) {
+		if (!separator.test_axis(n1.normalized(), !face_B->backface_collision)) {
 			return;
 		}
 
 		Vector3 n2 = vertex[(i + 1) % 3] - vertex[i];
 
 		Vector3 axis = n1.cross(n2).cross(n2).normalized();
+		if (axis.dot(normal) < 0.0) {
+			axis *= -1.0;
+		}
 
-		if (!separator.test_axis(axis)) {
+		if (!separator.test_axis(axis, !face_B->backface_collision)) {
 			return;
 		}
 	}
@@ -1467,15 +1480,20 @@ static void _collision_box_face(const Shape3DSW *p_a, const Transform &p_transfo
 		p_transform_b.xform(face_B->vertex[2]),
 	};
 
-	if (!separator.test_axis((vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized())) {
+	Vector3 normal = (vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized();
+
+	if (!separator.test_axis(normal, !face_B->backface_collision)) {
 		return;
 	}
 
 	// faces of A
 	for (int i = 0; i < 3; i++) {
 		Vector3 axis = p_transform_a.basis.get_axis(i).normalized();
+		if (axis.dot(normal) < 0.0) {
+			axis *= -1.0;
+		}
 
-		if (!separator.test_axis(axis)) {
+		if (!separator.test_axis(axis, !face_B->backface_collision)) {
 			return;
 		}
 	}
@@ -1486,9 +1504,12 @@ static void _collision_box_face(const Shape3DSW *p_a, const Transform &p_transfo
 		Vector3 e = vertex[i] - vertex[(i + 1) % 3];
 
 		for (int j = 0; j < 3; j++) {
-			Vector3 axis = p_transform_a.basis.get_axis(j);
+			Vector3 axis = e.cross(p_transform_a.basis.get_axis(j)).normalized();
+			if (axis.dot(normal) < 0.0) {
+				axis *= -1.0;
+			}
 
-			if (!separator.test_axis(e.cross(axis).normalized())) {
+			if (!separator.test_axis(axis, !face_B->backface_collision)) {
 				return;
 			}
 		}
@@ -1508,8 +1529,11 @@ static void _collision_box_face(const Shape3DSW *p_a, const Transform &p_transfo
 					(cnormal_a.z < 0) ? -box_A->get_half_extents().z : box_A->get_half_extents().z));
 
 			Vector3 axis_ab = support_a - vertex[v];
+			if (axis_ab.dot(normal) < 0.0) {
+				axis_ab *= -1.0;
+			}
 
-			if (!separator.test_axis(axis_ab.normalized())) {
+			if (!separator.test_axis(axis_ab.normalized(), !face_B->backface_collision)) {
 				return;
 			}
 
@@ -1519,7 +1543,12 @@ static void _collision_box_face(const Shape3DSW *p_a, const Transform &p_transfo
 				//a ->b
 				Vector3 axis_a = p_transform_a.basis.get_axis(i);
 
-				if (!separator.test_axis(axis_ab.cross(axis_a).cross(axis_a).normalized())) {
+				Vector3 axis = axis_ab.cross(axis_a).cross(axis_a).normalized();
+				if (axis.dot(normal) < 0.0) {
+					axis *= -1.0;
+				}
+
+				if (!separator.test_axis(axis, !face_B->backface_collision)) {
 					return;
 				}
 			}
@@ -1544,7 +1573,12 @@ static void _collision_box_face(const Shape3DSW *p_a, const Transform &p_transfo
 
 						Vector3 n = (p2 - p1);
 
-						if (!separator.test_axis((point - p2).cross(n).cross(n).normalized())) {
+						Vector3 axis = (point - p2).cross(n).cross(n).normalized();
+						if (axis.dot(normal) < 0.0) {
+							axis *= -1.0;
+						}
+
+						if (!separator.test_axis(axis, !face_B->backface_collision)) {
 							return;
 						}
 					}
@@ -1759,7 +1793,9 @@ static void _collision_capsule_face(const Shape3DSW *p_a, const Transform &p_tra
 		p_transform_b.xform(face_B->vertex[2]),
 	};
 
-	if (!separator.test_axis((vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized())) {
+	Vector3 normal = (vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized();
+
+	if (!separator.test_axis(normal, !face_B->backface_collision)) {
 		return;
 	}
 
@@ -1770,13 +1806,22 @@ static void _collision_capsule_face(const Shape3DSW *p_a, const Transform &p_tra
 	for (int i = 0; i < 3; i++) {
 		// edge-cylinder
 		Vector3 edge_axis = vertex[i] - vertex[(i + 1) % 3];
+
 		Vector3 axis = edge_axis.cross(capsule_axis).normalized();
+		if (axis.dot(normal) < 0.0) {
+			axis *= -1.0;
+		}
 
-		if (!separator.test_axis(axis)) {
+		if (!separator.test_axis(axis, !face_B->backface_collision)) {
 			return;
 		}
 
-		if (!separator.test_axis((p_transform_a.origin - vertex[i]).cross(capsule_axis).cross(capsule_axis).normalized())) {
+		Vector3 dir_axis = (p_transform_a.origin - vertex[i]).cross(capsule_axis).cross(capsule_axis).normalized();
+		if (dir_axis.dot(normal) < 0.0) {
+			dir_axis *= -1.0;
+		}
+
+		if (!separator.test_axis(dir_axis, !face_B->backface_collision)) {
 			return;
 		}
 
@@ -1785,16 +1830,22 @@ static void _collision_capsule_face(const Shape3DSW *p_a, const Transform &p_tra
 			Vector3 sphere_pos = p_transform_a.origin + ((j == 0) ? capsule_axis : -capsule_axis);
 
 			Vector3 n1 = sphere_pos - vertex[i];
+			if (n1.dot(normal) < 0.0) {
+				n1 *= -1.0;
+			}
 
-			if (!separator.test_axis(n1.normalized())) {
+			if (!separator.test_axis(n1.normalized(), !face_B->backface_collision)) {
 				return;
 			}
 
 			Vector3 n2 = edge_axis;
 
 			axis = n1.cross(n2).cross(n2);
+			if (axis.dot(normal) < 0.0) {
+				axis *= -1.0;
+			}
 
-			if (!separator.test_axis(axis.normalized())) {
+			if (!separator.test_axis(axis.normalized(), !face_B->backface_collision)) {
 				return;
 			}
 		}
@@ -1891,18 +1942,21 @@ static void _collision_cylinder_face(const Shape3DSW *p_a, const Transform &p_tr
 		p_transform_b.xform(face_B->vertex[2]),
 	};
 
+	Vector3 normal = (vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized();
+
 	// Face B normal.
-	if (!separator.test_axis((vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized())) {
+	if (!separator.test_axis(normal, !face_B->backface_collision)) {
 		return;
 	}
 
 	Vector3 cyl_axis = p_transform_a.basis.get_axis(1).normalized();
+	if (cyl_axis.dot(normal) < 0.0) {
+		cyl_axis *= -1.0;
+	}
 
 	// Cylinder end caps.
-	{
-		if (!separator.test_axis(cyl_axis)) {
-			return;
-		}
+	if (!separator.test_axis(cyl_axis, !face_B->backface_collision)) {
+		return;
 	}
 
 	// Edges of B, cylinder lateral surface.
@@ -1913,7 +1967,11 @@ static void _collision_cylinder_face(const Shape3DSW *p_a, const Transform &p_tr
 			continue;
 		}
 
-		if (!separator.test_axis(axis.normalized())) {
+		if (axis.dot(normal) < 0.0) {
+			axis *= -1.0;
+		}
+
+		if (!separator.test_axis(axis.normalized(), !face_B->backface_collision)) {
 			return;
 		}
 	}
@@ -1922,8 +1980,11 @@ static void _collision_cylinder_face(const Shape3DSW *p_a, const Transform &p_tr
 	for (int i = 0; i < 3; i++) {
 		const Vector3 &point = vertex[i];
 		Vector3 axis = Plane(cyl_axis, 0).project(point).normalized();
+		if (axis.dot(normal) < 0.0) {
+			axis *= -1.0;
+		}
 
-		if (!separator.test_axis(axis)) {
+		if (!separator.test_axis(axis, !face_B->backface_collision)) {
 			return;
 		}
 	}
@@ -1956,8 +2017,11 @@ static void _collision_cylinder_face(const Shape3DSW *p_a, const Transform &p_tr
 
 			// Axis is orthogonal both to tangent and edge direction.
 			Vector3 axis = tangent.cross(edge_dir);
+			if (axis.dot(normal) < 0.0) {
+				axis *= -1.0;
+			}
 
-			if (!separator.test_axis(axis.normalized())) {
+			if (!separator.test_axis(axis.normalized(), !face_B->backface_collision)) {
 				return;
 			}
 		}
@@ -2097,7 +2161,9 @@ static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform
 		p_transform_b.xform(face_B->vertex[2]),
 	};
 
-	if (!separator.test_axis((vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized())) {
+	Vector3 normal = (vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized();
+
+	if (!separator.test_axis(normal, !face_B->backface_collision)) {
 		return;
 	}
 
@@ -2105,8 +2171,11 @@ static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform
 	for (int i = 0; i < face_count; i++) {
 		//Vector3 axis = p_transform_a.xform( faces[i].plane ).normal;
 		Vector3 axis = p_transform_a.basis.xform(faces[i].plane.normal).normalized();
+		if (axis.dot(normal) < 0.0) {
+			axis *= -1.0;
+		}
 
-		if (!separator.test_axis(axis)) {
+		if (!separator.test_axis(axis, !face_B->backface_collision)) {
 			return;
 		}
 	}
@@ -2119,8 +2188,11 @@ static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform
 			Vector3 e2 = vertex[j] - vertex[(j + 1) % 3];
 
 			Vector3 axis = e1.cross(e2).normalized();
+			if (axis.dot(normal) < 0.0) {
+				axis *= -1.0;
+			}
 
-			if (!separator.test_axis(axis)) {
+			if (!separator.test_axis(axis, !face_B->backface_collision)) {
 				return;
 			}
 		}
@@ -2132,7 +2204,12 @@ static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform
 			Vector3 va = p_transform_a.xform(vertices[i]);
 
 			for (int j = 0; j < 3; j++) {
-				if (!separator.test_axis((va - vertex[j]).normalized())) {
+				Vector3 axis = (va - vertex[j]).normalized();
+				if (axis.dot(normal) < 0.0) {
+					axis *= -1.0;
+				}
+
+				if (!separator.test_axis(axis, !face_B->backface_collision)) {
 					return;
 				}
 			}
@@ -2147,7 +2224,12 @@ static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform
 			for (int j = 0; j < 3; j++) {
 				Vector3 e3 = vertex[j];
 
-				if (!separator.test_axis((e1 - e3).cross(n).cross(n).normalized())) {
+				Vector3 axis = (e1 - e3).cross(n).cross(n).normalized();
+				if (axis.dot(normal) < 0.0) {
+					axis *= -1.0;
+				}
+
+				if (!separator.test_axis(axis, !face_B->backface_collision)) {
 					return;
 				}
 			}
@@ -2161,7 +2243,12 @@ static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform
 			for (int j = 0; j < vertex_count; j++) {
 				Vector3 e3 = p_transform_a.xform(vertices[j]);
 
-				if (!separator.test_axis((e1 - e3).cross(n).cross(n).normalized())) {
+				Vector3 axis = (e1 - e3).cross(n).cross(n).normalized();
+				if (axis.dot(normal) < 0.0) {
+					axis *= -1.0;
+				}
+
+				if (!separator.test_axis(axis, !face_B->backface_collision)) {
 					return;
 				}
 			}

+ 35 - 24
servers/physics_3d/shape_3d_sw.cpp

@@ -1134,7 +1134,7 @@ void FaceShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_
 	Vector3 n = p_normal;
 
 	/** TEST FACE AS SUPPORT **/
-	if (normal.dot(n) > _FACE_IS_VALID_SUPPORT_THRESHOLD) {
+	if (Math::abs(normal.dot(n)) > _FACE_IS_VALID_SUPPORT_THRESHOLD) {
 		r_amount = 3;
 		r_type = FEATURE_FACE;
 		for (int i = 0; i < 3; i++) {
@@ -1187,7 +1187,11 @@ bool FaceShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_e
 	if (c) {
 		r_normal = Plane(vertex[0], vertex[1], vertex[2]).normal;
 		if (r_normal.dot(p_end - p_begin) > 0) {
-			r_normal = -r_normal;
+			if (backface_collision) {
+				r_normal = -r_normal;
+			} else {
+				c = false;
+			}
 		}
 	}
 
@@ -1285,30 +1289,24 @@ void ConcavePolygonShape3DSW::_cull_segment(int p_idx, _SegmentCullParams *p_par
 	}
 
 	if (bvh->face_index >= 0) {
-		Vector3 res;
-		Vector3 vertices[3] = {
-			p_params->vertices[p_params->faces[bvh->face_index].indices[0]],
-			p_params->vertices[p_params->faces[bvh->face_index].indices[1]],
-			p_params->vertices[p_params->faces[bvh->face_index].indices[2]]
-		};
+		const Face *f = &p_params->faces[bvh->face_index];
+		FaceShape3DSW *face = p_params->face;
+		face->normal = f->normal;
+		face->vertex[0] = p_params->vertices[f->indices[0]];
+		face->vertex[1] = p_params->vertices[f->indices[1]];
+		face->vertex[2] = p_params->vertices[f->indices[2]];
 
-		if (Geometry3D::segment_intersects_triangle(
-					p_params->from,
-					p_params->to,
-					vertices[0],
-					vertices[1],
-					vertices[2],
-					&res)) {
+		Vector3 res;
+		Vector3 normal;
+		if (face->intersect_segment(p_params->from, p_params->to, res, normal)) {
 			real_t d = p_params->dir.dot(res) - p_params->dir.dot(p_params->from);
-			//TODO, seems segmen/triangle intersection is broken :(
-			if (d > 0 && d < p_params->min_d) {
+			if ((d > 0) && (d < p_params->min_d)) {
 				p_params->min_d = d;
 				p_params->result = res;
-				p_params->normal = Plane(vertices[0], vertices[1], vertices[2]).normal;
+				p_params->normal = normal;
 				p_params->collisions++;
 			}
 		}
-
 	} else {
 		if (bvh->left >= 0) {
 			_cull_segment(bvh->left, p_params);
@@ -1329,17 +1327,20 @@ bool ConcavePolygonShape3DSW::intersect_segment(const Vector3 &p_begin, const Ve
 	const Vector3 *vr = vertices.ptr();
 	const BVH *br = bvh.ptr();
 
+	FaceShape3DSW face;
+	face.backface_collision = backface_collision;
+
 	_SegmentCullParams params;
 	params.from = p_begin;
 	params.to = p_end;
-	params.collisions = 0;
 	params.dir = (p_end - p_begin).normalized();
 
 	params.faces = fr;
 	params.vertices = vr;
 	params.bvh = br;
 
-	params.min_d = 1e20;
+	params.face = &face;
+
 	// cull
 	_cull_segment(0, &params);
 
@@ -1401,6 +1402,7 @@ void ConcavePolygonShape3DSW::cull(const AABB &p_local_aabb, Callback p_callback
 	const BVH *br = bvh.ptr();
 
 	FaceShape3DSW face; // use this to send in the callback
+	face.backface_collision = backface_collision;
 
 	_CullParams params;
 	params.aabb = local_aabb;
@@ -1532,7 +1534,7 @@ void ConcavePolygonShape3DSW::_fill_bvh(_VolumeSW_BVH *p_bvh_tree, BVH *p_bvh_ar
 	memdelete(p_bvh_tree);
 }
 
-void ConcavePolygonShape3DSW::_setup(Vector<Vector3> p_faces) {
+void ConcavePolygonShape3DSW::_setup(const Vector<Vector3> &p_faces, bool p_backface_collision) {
 	int src_face_count = p_faces.size();
 	if (src_face_count == 0) {
 		configure(AABB());
@@ -1587,15 +1589,24 @@ void ConcavePolygonShape3DSW::_setup(Vector<Vector3> p_faces) {
 	int idx = 0;
 	_fill_bvh(bvh_tree, bvh_arrayw2, idx);
 
+	backface_collision = p_backface_collision;
+
 	configure(_aabb); // this type of shape has no margin
 }
 
 void ConcavePolygonShape3DSW::set_data(const Variant &p_data) {
-	_setup(p_data);
+	Dictionary d = p_data;
+	ERR_FAIL_COND(!d.has("faces"));
+
+	_setup(d["faces"], d["backface_collision"]);
 }
 
 Variant ConcavePolygonShape3DSW::get_data() const {
-	return get_faces();
+	Dictionary d;
+	d["faces"] = get_faces();
+	d["backface_collision"] = backface_collision;
+
+	return d;
 }
 
 ConcavePolygonShape3DSW::ConcavePolygonShape3DSW() {

+ 16 - 12
servers/physics_3d/shape_3d_sw.h

@@ -334,34 +334,37 @@ struct ConcavePolygonShape3DSW : public ConcaveShape3DSW {
 
 	struct _CullParams {
 		AABB aabb;
-		Callback callback;
-		void *userdata;
-		const Face *faces;
-		const Vector3 *vertices;
-		const BVH *bvh;
-		FaceShape3DSW *face;
+		Callback callback = nullptr;
+		void *userdata = nullptr;
+		const Face *faces = nullptr;
+		const Vector3 *vertices = nullptr;
+		const BVH *bvh = nullptr;
+		FaceShape3DSW *face = nullptr;
 	};
 
 	struct _SegmentCullParams {
 		Vector3 from;
 		Vector3 to;
-		const Face *faces;
-		const Vector3 *vertices;
-		const BVH *bvh;
 		Vector3 dir;
+		const Face *faces = nullptr;
+		const Vector3 *vertices = nullptr;
+		const BVH *bvh = nullptr;
+		FaceShape3DSW *face = nullptr;
 
 		Vector3 result;
 		Vector3 normal;
-		real_t min_d;
-		int collisions;
+		real_t min_d = 1e20;
+		int collisions = 0;
 	};
 
+	bool backface_collision = false;
+
 	void _cull_segment(int p_idx, _SegmentCullParams *p_params) const;
 	void _cull(int p_idx, _CullParams *p_params) const;
 
 	void _fill_bvh(_VolumeSW_BVH *p_bvh_tree, BVH *p_bvh_array, int &p_idx);
 
-	void _setup(Vector<Vector3> p_faces);
+	void _setup(const Vector<Vector3> &p_faces, bool p_backface_collision);
 
 public:
 	Vector<Vector3> get_faces() const;
@@ -424,6 +427,7 @@ public:
 struct FaceShape3DSW : public Shape3DSW {
 	Vector3 normal; //cache
 	Vector3 vertex[3];
+	bool backface_collision = false;
 
 	virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_CONCAVE_POLYGON; }
 

+ 4 - 2
tests/test_physics_3d.cpp

@@ -187,8 +187,10 @@ protected:
 		RenderingServer *vs = RenderingServer::get_singleton();
 		PhysicsServer3D *ps = PhysicsServer3D::get_singleton();
 		RID trimesh_shape = ps->shape_create(PhysicsServer3D::SHAPE_CONCAVE_POLYGON);
-		ps->shape_set_data(trimesh_shape, p_faces);
-		p_faces = ps->shape_get_data(trimesh_shape); // optimized one
+		Dictionary trimesh_params;
+		trimesh_params["faces"] = p_faces;
+		trimesh_params["backface_collision"] = false;
+		ps->shape_set_data(trimesh_shape, trimesh_params);
 		Vector<Vector3> normals; // for drawing
 		for (int i = 0; i < p_faces.size() / 3; i++) {
 			Plane p(p_faces[i * 3 + 0], p_faces[i * 3 + 1], p_faces[i * 3 + 2]);