Browse Source

Merge pull request #52338 from lawnjelly/portals_fix_portal_import

Portals - fix import of portal normal + small bug fixes
Rémi Verschelde 4 years ago
parent
commit
f85ad007c0
3 changed files with 40 additions and 17 deletions
  1. 32 16
      scene/3d/portal.cpp
  2. 1 1
      scene/3d/portal.h
  3. 7 0
      scene/3d/room_manager.cpp

+ 32 - 16
scene/3d/portal.cpp

@@ -360,6 +360,7 @@ bool Portal::create_from_mesh_instance(const MeshInstance *p_mi) {
 
 
 	Array arrays = rmesh->surface_get_arrays(0);
 	Array arrays = rmesh->surface_get_arrays(0);
 	PoolVector<Vector3> vertices = arrays[VS::ARRAY_VERTEX];
 	PoolVector<Vector3> vertices = arrays[VS::ARRAY_VERTEX];
+	PoolVector<int> indices = arrays[VS::ARRAY_INDEX];
 
 
 	// get the model space verts and find center
 	// get the model space verts and find center
 	int num_source_points = vertices.size();
 	int num_source_points = vertices.size();
@@ -391,9 +392,28 @@ bool Portal::create_from_mesh_instance(const MeshInstance *p_mi) {
 		}
 		}
 	}
 	}
 
 
+	ERR_FAIL_COND_V(pts_world.size() < 3, false);
+
+	// create the normal from 3 vertices .. either indexed, or use the first 3
+	Vector3 three_pts[3];
+	if (indices.size() >= 3) {
+		for (int n = 0; n < 3; n++) {
+			ERR_FAIL_COND_V(indices[n] >= num_source_points, false);
+			three_pts[n] = tr_source.xform(vertices[indices[n]]);
+		}
+	} else {
+		for (int n = 0; n < 3; n++) {
+			three_pts[n] = pts_world[n];
+		}
+	}
+	Vector3 normal = Plane(three_pts[0], three_pts[1], three_pts[2]).normal;
+	if (_portal_plane_convention) {
+		normal = -normal;
+	}
+
 	// get the verts sorted with winding, assume that the triangle initial winding
 	// get the verts sorted with winding, assume that the triangle initial winding
 	// tells us the normal and hence which way the world space portal should be facing
 	// tells us the normal and hence which way the world space portal should be facing
-	_sort_verts_clockwise(_portal_plane_convention, pts_world);
+	_sort_verts_clockwise(normal, pts_world);
 
 
 	// back calculate the plane from *all* the portal points, this will give us a nice average plane
 	// back calculate the plane from *all* the portal points, this will give us a nice average plane
 	// (in case of wonky portals where artwork isn't bang on)
 	// (in case of wonky portals where artwork isn't bang on)
@@ -401,7 +421,14 @@ bool Portal::create_from_mesh_instance(const MeshInstance *p_mi) {
 
 
 	// change the portal transform to match our plane and the center of the portal
 	// change the portal transform to match our plane and the center of the portal
 	Transform tr_global;
 	Transform tr_global;
-	tr_global.set_look_at(Vector3(0, 0, 0), _plane.normal, Vector3(0, 1, 0));
+
+	// prevent warnings when poly normal matches the up vector
+	Vector3 up(0, 1, 0);
+	if (Math::abs(_plane.normal.dot(up)) > 0.9) {
+		up = Vector3(1, 0, 0);
+	}
+
+	tr_global.set_look_at(Vector3(0, 0, 0), _plane.normal, up);
 	tr_global.origin = _pt_center_world;
 	tr_global.origin = _pt_center_world;
 
 
 	// We can't directly set this global transform on the portal, because the parent node may already
 	// We can't directly set this global transform on the portal, because the parent node may already
@@ -558,23 +585,12 @@ void Portal::_sanitize_points() {
 	_update_aabb();
 	_update_aabb();
 }
 }
 
 
-void Portal::_sort_verts_clockwise(bool portal_plane_convention, Vector<Vector3> &r_verts) {
+void Portal::_sort_verts_clockwise(const Vector3 &p_portal_normal, Vector<Vector3> &r_verts) {
 	// cannot sort less than 3 verts
 	// cannot sort less than 3 verts
 	if (r_verts.size() < 3) {
 	if (r_verts.size() < 3) {
 		return;
 		return;
 	}
 	}
 
 
-	// assume first 3 points determine the desired normal, if these first 3 points are garbage,
-	// the routine will not work.
-	Plane portal_plane;
-	if (portal_plane_convention) {
-		portal_plane = Plane(r_verts[0], r_verts[2], r_verts[1]);
-	} else {
-		portal_plane = Plane(r_verts[0], r_verts[1], r_verts[2]);
-	}
-
-	const Vector3 &portal_normal = portal_plane.normal;
-
 	// find centroid
 	// find centroid
 	int num_points = r_verts.size();
 	int num_points = r_verts.size();
 	_pt_center_world = Vector3(0, 0, 0);
 	_pt_center_world = Vector3(0, 0, 0);
@@ -590,7 +606,7 @@ void Portal::_sort_verts_clockwise(bool portal_plane_convention, Vector<Vector3>
 		Vector3 a = r_verts[n] - _pt_center_world;
 		Vector3 a = r_verts[n] - _pt_center_world;
 		a.normalize();
 		a.normalize();
 
 
-		Plane p = Plane(r_verts[n], _pt_center_world, _pt_center_world + portal_normal);
+		Plane p = Plane(r_verts[n], _pt_center_world, _pt_center_world + p_portal_normal);
 
 
 		double smallest_angle = -1;
 		double smallest_angle = -1;
 		int smallest = -1;
 		int smallest = -1;
@@ -623,7 +639,7 @@ void Portal::_sort_verts_clockwise(bool portal_plane_convention, Vector<Vector3>
 	// the wrong way.
 	// the wrong way.
 	Plane plane = Plane(r_verts[0], r_verts[1], r_verts[2]);
 	Plane plane = Plane(r_verts[0], r_verts[1], r_verts[2]);
 
 
-	if (portal_normal.dot(plane.normal) < 0.0f) {
+	if (p_portal_normal.dot(plane.normal) < 0.0) {
 		// reverse winding order of verts
 		// reverse winding order of verts
 		r_verts.invert();
 		r_verts.invert();
 	}
 	}

+ 1 - 1
scene/3d/portal.h

@@ -110,7 +110,7 @@ private:
 	void _sanitize_points();
 	void _sanitize_points();
 	void _update_aabb();
 	void _update_aabb();
 	static Vector3 _vec2to3(const Vector2 &p_pt) { return Vector3(p_pt.x, p_pt.y, 0.0); }
 	static Vector3 _vec2to3(const Vector2 &p_pt) { return Vector3(p_pt.x, p_pt.y, 0.0); }
-	void _sort_verts_clockwise(bool portal_plane_convention, Vector<Vector3> &r_verts);
+	void _sort_verts_clockwise(const Vector3 &p_portal_normal, Vector<Vector3> &r_verts);
 	Plane _plane_from_points_newell(const Vector<Vector3> &p_pts);
 	Plane _plane_from_points_newell(const Vector<Vector3> &p_pts);
 	void resolve_links(const LocalVector<Room *, int32_t> &p_rooms, const RID &p_from_room_rid);
 	void resolve_links(const LocalVector<Room *, int32_t> &p_rooms, const RID &p_from_room_rid);
 	void _changed();
 	void _changed();

+ 7 - 0
scene/3d/room_manager.cpp

@@ -873,7 +873,14 @@ void RoomManager::_second_pass_portals(Spatial *p_roomlist, LocalVector<Portal *
 			String string_link_room = string_link_room_shortname + "-room";
 			String string_link_room = string_link_room_shortname + "-room";
 
 
 			if (string_link_room_shortname != "") {
 			if (string_link_room_shortname != "") {
+				// try the room name plus the postfix first, this will be the most common case during import
 				Room *linked_room = Object::cast_to<Room>(p_roomlist->find_node(string_link_room, true, false));
 				Room *linked_room = Object::cast_to<Room>(p_roomlist->find_node(string_link_room, true, false));
+
+				// try the short name as a last ditch attempt
+				if (!linked_room) {
+					linked_room = Object::cast_to<Room>(p_roomlist->find_node(string_link_room_shortname, true, false));
+				}
+
 				if (linked_room) {
 				if (linked_room) {
 					NodePath path = portal->get_path_to(linked_room);
 					NodePath path = portal->get_path_to(linked_room);
 					portal->set_linked_room_internal(path);
 					portal->set_linked_room_internal(path);