浏览代码

Merge pull request #88207 from lawnjelly/view_mesh_stats

[3.x] Editor 3D view mesh stats
lawnjelly 1 年之前
父节点
当前提交
561a8eaf6e
共有 4 个文件被更改,包括 186 次插入4 次删除
  1. 116 4
      editor/plugins/spatial_editor_plugin.cpp
  2. 2 0
      editor/plugins/spatial_editor_plugin.h
  3. 49 0
      scene/resources/mesh.cpp
  4. 19 0
      scene/resources/mesh.h

+ 116 - 4
editor/plugins/spatial_editor_plugin.cpp

@@ -47,6 +47,7 @@
 #include "scene/3d/collision_shape.h"
 #include "scene/3d/collision_shape.h"
 #include "scene/3d/lod_manager.h"
 #include "scene/3d/lod_manager.h"
 #include "scene/3d/mesh_instance.h"
 #include "scene/3d/mesh_instance.h"
+#include "scene/3d/multimesh_instance.h"
 #include "scene/3d/physics_body.h"
 #include "scene/3d/physics_body.h"
 #include "scene/3d/room_manager.h"
 #include "scene/3d/room_manager.h"
 #include "scene/3d/visual_instance.h"
 #include "scene/3d/visual_instance.h"
@@ -2779,6 +2780,19 @@ void SpatialEditorViewport::_notification(int p_what) {
 
 
 		_update_camera(delta);
 		_update_camera(delta);
 
 
+		bool show_selected_info = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_SELECTED_INFO)) && (message_time <= 0);
+
+		struct SelectedInfo {
+			bool filled = false;
+			uint32_t tri_count = 0;
+			uint32_t vertex_count = 0;
+			uint32_t index_count = 0;
+			uint32_t mesh_count = 0;
+			uint32_t multimesh_count = 0;
+			uint32_t surface_count = 0;
+			uint32_t array_format = 0;
+		} selected_info;
+
 		Map<Node *, Object *> &selection = editor_selection->get_selection();
 		Map<Node *, Object *> &selection = editor_selection->get_selection();
 
 
 		bool changed = false;
 		bool changed = false;
@@ -2790,6 +2804,48 @@ void SpatialEditorViewport::_notification(int p_what) {
 				continue;
 				continue;
 			}
 			}
 
 
+			// Only retrieve stats for selected items if we are currently showing the selection stats box.
+			if (show_selected_info) {
+				MeshInstance *mi = Object::cast_to<MeshInstance>(sp);
+				if (mi) {
+					const Ref<Mesh> &mesh = mi->get_mesh();
+					if (mesh.is_valid()) {
+						selected_info.filled = true;
+						const Mesh::CachedStats &stats = mesh->get_cached_stats();
+						selected_info.tri_count += stats.triangle_count;
+						selected_info.vertex_count += stats.vertex_count;
+						selected_info.index_count += stats.index_count;
+						selected_info.mesh_count += 1;
+						selected_info.surface_count += mesh->get_surface_count();
+						selected_info.array_format |= stats.array_format;
+					}
+				}
+
+				MultiMeshInstance *mmi = Object::cast_to<MultiMeshInstance>(sp);
+				if (mmi) {
+					const Ref<MultiMesh> &mm = mmi->get_multimesh();
+					if (mm.is_valid()) {
+						const Ref<Mesh> &mesh = mm->get_mesh();
+						int icount = mm->get_visible_instance_count();
+						if (icount < 0) {
+							icount = mm->get_instance_count();
+						}
+
+						if (mesh.is_valid() && icount) {
+							selected_info.filled = true;
+							const Mesh::CachedStats &stats = mesh->get_cached_stats();
+							selected_info.tri_count += stats.triangle_count * icount;
+							selected_info.vertex_count += stats.vertex_count * icount;
+							selected_info.index_count += stats.index_count * icount;
+							selected_info.mesh_count += icount;
+							selected_info.multimesh_count += 1;
+							selected_info.surface_count += mesh->get_surface_count() * icount;
+							selected_info.array_format |= stats.array_format;
+						}
+					}
+				}
+			}
+
 			SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
 			SpatialEditorSelectedItem *se = editor_selection->get_node_editor_data<SpatialEditorSelectedItem>(sp);
 			if (!se) {
 			if (!se) {
 				continue;
 				continue;
@@ -2841,11 +2897,17 @@ void SpatialEditorViewport::_notification(int p_what) {
 			if (message != last_message) {
 			if (message != last_message) {
 				surface->update();
 				surface->update();
 				last_message = message;
 				last_message = message;
-			}
 
 
-			message_time -= get_physics_process_delta_time();
-			if (message_time < 0) {
-				surface->update();
+				// If there is now no message,
+				// disable the timing counter.
+				if (message == "") {
+					message_time = 0;
+				}
+			} else {
+				message_time -= get_physics_process_delta_time();
+				if (message_time < 0) {
+					surface->update();
+				}
 			}
 			}
 		}
 		}
 
 
@@ -2893,6 +2955,29 @@ void SpatialEditorViewport::_notification(int p_what) {
 			info_label->set_text(text);
 			info_label->set_text(text);
 		}
 		}
 
 
+		selected_info_label->set_visible(show_selected_info && selected_info.filled);
+		if (show_selected_info) {
+			if (selected_info.filled) {
+				String text;
+				if (selected_info.multimesh_count > 0) {
+					text += TTR("MultiMeshes:") + " " + itos(selected_info.multimesh_count) + "\n";
+				}
+				if (selected_info.mesh_count > 1) {
+					text += TTR("Meshes:") + " " + itos(selected_info.mesh_count) + "\n";
+				}
+				if (selected_info.surface_count > 1) {
+					text += TTR("Surfaces:") + " " + itos(selected_info.surface_count) + "\n";
+				}
+				text += TTR("Triangles:") + " " + itos(selected_info.tri_count) + "\n";
+				text += TTR("Vertices:") + " " + itos(selected_info.vertex_count) + "\n";
+				text += TTR("Indices:") + " " + itos(selected_info.index_count);
+
+				selected_info_label->set_text(text);
+			} else {
+				selected_info_label->set_text("");
+			}
+		}
+
 		// FPS Counter.
 		// FPS Counter.
 		bool show_fps = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_FPS));
 		bool show_fps = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_FPS));
 		fps_label->set_visible(show_fps);
 		fps_label->set_visible(show_fps);
@@ -2959,6 +3044,7 @@ void SpatialEditorViewport::_notification(int p_what) {
 		preview_camera->add_style_override("disabled", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
 		preview_camera->add_style_override("disabled", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
 
 
 		info_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
 		info_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
+		selected_info_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
 		fps_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
 		fps_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
 		cinema_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
 		cinema_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
 		locked_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
 		locked_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
@@ -3374,6 +3460,12 @@ void SpatialEditorViewport::_menu_option(int p_option) {
 			bool current = view_menu->get_popup()->is_item_checked(idx);
 			bool current = view_menu->get_popup()->is_item_checked(idx);
 			view_menu->get_popup()->set_item_checked(idx, !current);
 			view_menu->get_popup()->set_item_checked(idx, !current);
 
 
+		} break;
+		case VIEW_SELECTED_INFO: {
+			int idx = view_menu->get_popup()->get_item_index(VIEW_SELECTED_INFO);
+			bool current = view_menu->get_popup()->is_item_checked(idx);
+			view_menu->get_popup()->set_item_checked(idx, !current);
+
 		} break;
 		} break;
 		case VIEW_FPS: {
 		case VIEW_FPS: {
 			int idx = view_menu->get_popup()->get_item_index(VIEW_FPS);
 			int idx = view_menu->get_popup()->get_item_index(VIEW_FPS);
@@ -3744,6 +3836,14 @@ void SpatialEditorViewport::set_state(const Dictionary &p_state) {
 			_menu_option(VIEW_INFORMATION);
 			_menu_option(VIEW_INFORMATION);
 		}
 		}
 	}
 	}
+	if (p_state.has("selected_info")) {
+		bool selected_info = p_state["selected_info"];
+
+		int idx = view_menu->get_popup()->get_item_index(VIEW_SELECTED_INFO);
+		if (view_menu->get_popup()->is_item_checked(idx) != selected_info) {
+			_menu_option(VIEW_SELECTED_INFO);
+		}
+	}
 	if (p_state.has("fps")) {
 	if (p_state.has("fps")) {
 		bool fps = p_state["fps"];
 		bool fps = p_state["fps"];
 
 
@@ -3806,6 +3906,7 @@ Dictionary SpatialEditorViewport::get_state() const {
 	d["doppler"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUDIO_DOPPLER));
 	d["doppler"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUDIO_DOPPLER));
 	d["gizmos"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_GIZMOS));
 	d["gizmos"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_GIZMOS));
 	d["information"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_INFORMATION));
 	d["information"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_INFORMATION));
+	d["selected_info"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_SELECTED_INFO));
 	d["fps"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_FPS));
 	d["fps"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_FPS));
 	d["half_res"] = viewport_container->get_stretch_shrink() > 1;
 	d["half_res"] = viewport_container->get_stretch_shrink() > 1;
 	d["cinematic_preview"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_CINEMATIC_PREVIEW));
 	d["cinematic_preview"] = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_CINEMATIC_PREVIEW));
@@ -4344,6 +4445,7 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed
 	view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_gizmos", TTR("View Gizmos")), VIEW_GIZMOS);
 	view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_gizmos", TTR("View Gizmos")), VIEW_GIZMOS);
 	view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_GIZMOS), true);
 	view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_GIZMOS), true);
 	view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_information", TTR("View Information")), VIEW_INFORMATION);
 	view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_information", TTR("View Information")), VIEW_INFORMATION);
+	view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_selected_info", TTR("View Selected Mesh Stats")), VIEW_SELECTED_INFO);
 	view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_fps", TTR("View FPS")), VIEW_FPS);
 	view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_fps", TTR("View FPS")), VIEW_FPS);
 	view_menu->get_popup()->add_separator();
 	view_menu->get_popup()->add_separator();
 	view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_half_resolution", TTR("Half Resolution")), VIEW_HALF_RESOLUTION);
 	view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_half_resolution", TTR("Half Resolution")), VIEW_HALF_RESOLUTION);
@@ -4428,6 +4530,16 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed
 	surface->add_child(info_label);
 	surface->add_child(info_label);
 	info_label->hide();
 	info_label->hide();
 
 
+	selected_info_label = memnew(Label);
+	selected_info_label->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_BEGIN, 10 * EDSCALE);
+	selected_info_label->set_anchor_and_margin(MARGIN_TOP, ANCHOR_END, -20 * EDSCALE);
+	selected_info_label->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_BEGIN, 90 * EDSCALE);
+	selected_info_label->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, -10 * EDSCALE);
+	selected_info_label->set_h_grow_direction(GROW_DIRECTION_END);
+	selected_info_label->set_v_grow_direction(GROW_DIRECTION_BEGIN);
+	surface->add_child(selected_info_label);
+	selected_info_label->hide();
+
 	cinema_label = memnew(Label);
 	cinema_label = memnew(Label);
 	cinema_label->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 10 * EDSCALE);
 	cinema_label->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 10 * EDSCALE);
 	cinema_label->set_h_grow_direction(GROW_DIRECTION_END);
 	cinema_label->set_h_grow_direction(GROW_DIRECTION_END);

+ 2 - 0
editor/plugins/spatial_editor_plugin.h

@@ -204,6 +204,7 @@ class SpatialEditorViewport : public Control {
 		VIEW_AUDIO_DOPPLER,
 		VIEW_AUDIO_DOPPLER,
 		VIEW_GIZMOS,
 		VIEW_GIZMOS,
 		VIEW_INFORMATION,
 		VIEW_INFORMATION,
+		VIEW_SELECTED_INFO,
 		VIEW_FPS,
 		VIEW_FPS,
 		VIEW_DISPLAY_NORMAL,
 		VIEW_DISPLAY_NORMAL,
 		VIEW_DISPLAY_WIREFRAME,
 		VIEW_DISPLAY_WIREFRAME,
@@ -283,6 +284,7 @@ private:
 	Vector2 previous_mouse_position;
 	Vector2 previous_mouse_position;
 
 
 	Label *info_label;
 	Label *info_label;
+	Label *selected_info_label;
 	Label *cinema_label;
 	Label *cinema_label;
 	Label *locked_label;
 	Label *locked_label;
 	Label *zoom_limit_label;
 	Label *zoom_limit_label;

+ 49 - 0
scene/resources/mesh.cpp

@@ -42,6 +42,52 @@
 
 
 Mesh::ConvexDecompositionFunc Mesh::convex_decomposition_function = nullptr;
 Mesh::ConvexDecompositionFunc Mesh::convex_decomposition_function = nullptr;
 
 
+#ifdef TOOLS_ENABLED
+const Mesh::CachedStats &Mesh::get_cached_stats() const {
+	if (_cached_stats.dirty) {
+		_cached_stats.dirty = false;
+
+		_cached_stats.triangle_count = get_triangle_count();
+
+		// Vertex count.
+		_cached_stats.vertex_count = 0;
+		for (int i = 0; i < get_surface_count(); i++) {
+			_cached_stats.vertex_count += surface_get_array_len(i);
+		}
+
+		// Index count.
+		_cached_stats.index_count = 0;
+		for (int i = 0; i < get_surface_count(); i++) {
+			_cached_stats.index_count += surface_get_index_count(i);
+		}
+
+		// Array format.
+		_cached_stats.array_format = 0;
+		for (int i = 0; i < get_surface_count(); i++) {
+			_cached_stats.array_format |= surface_get_format(i);
+		}
+	}
+
+	return _cached_stats;
+}
+#endif
+
+int Mesh::surface_get_index_count(int p_idx) const {
+	ERR_FAIL_INDEX_V(p_idx, get_surface_count(), 0);
+
+	switch (surface_get_primitive_type(p_idx)) {
+		case PRIMITIVE_TRIANGLES:
+		case PRIMITIVE_TRIANGLE_FAN:
+		case PRIMITIVE_TRIANGLE_STRIP: {
+			return (surface_get_format(p_idx) & ARRAY_FORMAT_INDEX) ? surface_get_array_index_len(p_idx) : surface_get_array_len(p_idx);
+		} break;
+		default: {
+		} break;
+	}
+
+	return 0;
+}
+
 int Mesh::surface_get_triangle_count(int p_idx) const {
 int Mesh::surface_get_triangle_count(int p_idx) const {
 	ERR_FAIL_INDEX_V(p_idx, get_surface_count(), 0);
 	ERR_FAIL_INDEX_V(p_idx, get_surface_count(), 0);
 
 
@@ -625,6 +671,9 @@ void Mesh::set_storage_mode(StorageMode p_storage_mode) {
 void Mesh::clear_cache() const {
 void Mesh::clear_cache() const {
 	triangle_mesh.unref();
 	triangle_mesh.unref();
 	debug_lines.clear();
 	debug_lines.clear();
+#ifdef TOOLS_ENABLED
+	_cached_stats.dirty = true;
+#endif
 }
 }
 
 
 Vector<Ref<Shape>> Mesh::convex_decompose(int p_max_convex_hulls) const {
 Vector<Ref<Shape>> Mesh::convex_decompose(int p_max_convex_hulls) const {

+ 19 - 0
scene/resources/mesh.h

@@ -126,6 +126,14 @@ public:
 		STORAGE_MODE_CPU_AND_GPU,
 		STORAGE_MODE_CPU_AND_GPU,
 	};
 	};
 
 
+	struct CachedStats {
+		bool dirty = true;
+		uint32_t triangle_count = 0;
+		uint32_t vertex_count = 0;
+		uint32_t index_count = 0;
+		uint32_t array_format = 0;
+	};
+
 	virtual int get_surface_count() const = 0;
 	virtual int get_surface_count() const = 0;
 	virtual int surface_get_array_len(int p_idx) const = 0;
 	virtual int surface_get_array_len(int p_idx) const = 0;
 	virtual int surface_get_array_index_len(int p_idx) const = 0;
 	virtual int surface_get_array_index_len(int p_idx) const = 0;
@@ -138,11 +146,15 @@ public:
 	virtual Ref<Material> surface_get_material(int p_idx) const = 0;
 	virtual Ref<Material> surface_get_material(int p_idx) const = 0;
 	virtual int get_blend_shape_count() const = 0;
 	virtual int get_blend_shape_count() const = 0;
 	int surface_get_triangle_count(int p_idx) const;
 	int surface_get_triangle_count(int p_idx) const;
+	int surface_get_index_count(int p_idx) const;
 	virtual StringName get_blend_shape_name(int p_index) const = 0;
 	virtual StringName get_blend_shape_name(int p_index) const = 0;
 	virtual void set_blend_shape_name(int p_index, const StringName &p_name) = 0;
 	virtual void set_blend_shape_name(int p_index, const StringName &p_name) = 0;
 
 
 	int get_triangle_count() const;
 	int get_triangle_count() const;
 	PoolVector<Face3> get_faces() const;
 	PoolVector<Face3> get_faces() const;
+#ifdef TOOLS_ENABLED
+	const CachedStats &get_cached_stats() const;
+#endif
 	Ref<TriangleMesh> generate_triangle_mesh() const;
 	Ref<TriangleMesh> generate_triangle_mesh() const;
 	Ref<TriangleMesh> generate_triangle_mesh_from_aabb() const;
 	Ref<TriangleMesh> generate_triangle_mesh_from_aabb() const;
 	void generate_debug_mesh_lines(Vector<Vector3> &r_lines);
 	void generate_debug_mesh_lines(Vector<Vector3> &r_lines);
@@ -167,6 +179,13 @@ public:
 	Vector<Ref<Shape>> convex_decompose(int p_max_convex_hulls = -1) const;
 	Vector<Ref<Shape>> convex_decompose(int p_max_convex_hulls = -1) const;
 
 
 	Mesh();
 	Mesh();
+
+private:
+#ifdef TOOLS_ENABLED
+	// Only for use in the editor.
+	// No need to bloat exports.
+	mutable CachedStats _cached_stats;
+#endif
 };
 };
 
 
 class ArrayMesh : public Mesh {
 class ArrayMesh : public Mesh {