Forráskód Böngészése

Merge pull request #60517 from Calinou/3d-editor-audiostreamplayer3d-add-gizmo

JFonS 3 éve
szülő
commit
8abace0f79

+ 85 - 0
editor/plugins/node_3d_editor_gizmos.cpp

@@ -1497,6 +1497,9 @@ AudioStreamPlayer3DGizmoPlugin::AudioStreamPlayer3DGizmoPlugin() {
 	create_icon_material("stream_player_3d_icon", Node3DEditor::get_singleton()->get_theme_icon(SNAME("Gizmo3DSamplePlayer"), SNAME("EditorIcons")));
 	create_material("stream_player_3d_material_primary", gizmo_color);
 	create_material("stream_player_3d_material_secondary", gizmo_color * Color(1, 1, 1, 0.35));
+	// Enable vertex colors for the billboard material as the gizmo color depends on the
+	// AudioStreamPlayer3D attenuation type and source (Unit Size or Max Distance).
+	create_material("stream_player_3d_material_billboard", Color(1, 1, 1), true, false, true);
 	create_handle_material("handles");
 }
 
@@ -1580,6 +1583,88 @@ void AudioStreamPlayer3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
 
 	const Ref<Material> icon = get_material("stream_player_3d_icon", p_gizmo);
 
+	if (player->get_attenuation_model() != AudioStreamPlayer3D::ATTENUATION_DISABLED || player->get_max_distance() > CMP_EPSILON) {
+		// Draw a circle to represent sound volume attenuation.
+		// Use only a billboard circle to represent radius.
+		// This helps distinguish AudioStreamPlayer3D gizmos from OmniLight3D gizmos.
+		const Ref<Material> lines_billboard_material = get_material("stream_player_3d_material_billboard", p_gizmo);
+
+		// Soft distance cap varies depending on attenuation model, as some will fade out more aggressively than others.
+		// Multipliers were empirically determined through testing.
+		float soft_multiplier;
+		switch (player->get_attenuation_model()) {
+			case AudioStreamPlayer3D::ATTENUATION_INVERSE_DISTANCE:
+				soft_multiplier = 12.0;
+				break;
+			case AudioStreamPlayer3D::ATTENUATION_INVERSE_SQUARE_DISTANCE:
+				soft_multiplier = 4.0;
+				break;
+			case AudioStreamPlayer3D::ATTENUATION_LOGARITHMIC:
+				soft_multiplier = 3.25;
+				break;
+			default:
+				// Ensures Max Distance's radius visualization is not capped by Unit Size
+				// (when the attenuation mode is Disabled).
+				soft_multiplier = 10000.0;
+				break;
+		}
+
+		// Draw the distance at which the sound can be reasonably heard.
+		// This can be either a hard distance cap with the Max Distance property (if set above 0.0),
+		// or a soft distance cap with the Unit Size property (sound never reaches true zero).
+		// When Max Distance is 0.0, `r` represents the distance above which the
+		// sound can't be heard in *most* (but not all) scenarios.
+		float r;
+		if (player->get_max_distance() > CMP_EPSILON) {
+			r = MIN(player->get_unit_size() * soft_multiplier, player->get_max_distance());
+		} else {
+			r = player->get_unit_size() * soft_multiplier;
+		}
+		Vector<Vector3> points_billboard;
+
+		for (int i = 0; i < 120; i++) {
+			// Create a circle.
+			const float ra = Math::deg2rad((float)(i * 3));
+			const float rb = Math::deg2rad((float)((i + 1) * 3));
+			const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r;
+			const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r;
+
+			// Draw a billboarded circle.
+			points_billboard.push_back(Vector3(a.x, a.y, 0));
+			points_billboard.push_back(Vector3(b.x, b.y, 0));
+		}
+
+		Color color;
+		switch (player->get_attenuation_model()) {
+			// Pick cold colors for all attenuation models (except Disabled),
+			// so that soft caps can be easily distinguished from hard caps
+			// (which use warm colors).
+			case AudioStreamPlayer3D::ATTENUATION_INVERSE_DISTANCE:
+				color = Color(0.4, 0.8, 1);
+				break;
+			case AudioStreamPlayer3D::ATTENUATION_INVERSE_SQUARE_DISTANCE:
+				color = Color(0.4, 0.5, 1);
+				break;
+			case AudioStreamPlayer3D::ATTENUATION_LOGARITHMIC:
+				color = Color(0.4, 0.2, 1);
+				break;
+			default:
+				// Disabled attenuation mode.
+				// This is never reached when Max Distance is 0, but the
+				// hue-inverted form of this color will be used if Max Distance is greater than 0.
+				color = Color(1, 1, 1);
+				break;
+		}
+
+		if (player->get_max_distance() > CMP_EPSILON) {
+			// Sound is hard-capped by max distance. The attenuation model still matters,
+			// so invert the hue of the color that was chosen above.
+			color.set_h(color.get_h() + 0.5);
+		}
+
+		p_gizmo->add_lines(points_billboard, lines_billboard_material, true, color);
+	}
+
 	if (player->is_emission_angle_enabled()) {
 		const float pc = player->get_emission_angle();
 		const float ofs = -Math::cos(Math::deg2rad(pc));

+ 3 - 0
scene/3d/audio_stream_player_3d.cpp

@@ -541,6 +541,7 @@ float AudioStreamPlayer3D::get_unit_db() const {
 
 void AudioStreamPlayer3D::set_unit_size(float p_volume) {
 	unit_size = p_volume;
+	update_gizmos();
 }
 
 float AudioStreamPlayer3D::get_unit_size() const {
@@ -669,6 +670,7 @@ void AudioStreamPlayer3D::_bus_layout_changed() {
 void AudioStreamPlayer3D::set_max_distance(float p_metres) {
 	ERR_FAIL_COND(p_metres < 0.0);
 	max_distance = p_metres;
+	update_gizmos();
 }
 
 float AudioStreamPlayer3D::get_max_distance() const {
@@ -729,6 +731,7 @@ float AudioStreamPlayer3D::get_attenuation_filter_db() const {
 void AudioStreamPlayer3D::set_attenuation_model(AttenuationModel p_model) {
 	ERR_FAIL_INDEX((int)p_model, 4);
 	attenuation_model = p_model;
+	update_gizmos();
 }
 
 AudioStreamPlayer3D::AttenuationModel AudioStreamPlayer3D::get_attenuation_model() const {