浏览代码

Fixed delay when CPUParticles & CPUParticles2D start being emitted

Particles were processed only on the next frame after the emission started, causing a one frame delay in rendering. Now the first process cycle is started during the same frame, which makes them consistent with Particles & Particles2D.

Fixes #32890
PouleyKetchoupp 5 年之前
父节点
当前提交
5bf516a062
共有 4 个文件被更改,包括 173 次插入138 次删除
  1. 76 65
      scene/2d/cpu_particles_2d.cpp
  2. 1 0
      scene/2d/cpu_particles_2d.h
  3. 95 73
      scene/3d/cpu_particles.cpp
  4. 1 0
      scene/3d/cpu_particles.h

+ 76 - 65
scene/2d/cpu_particles_2d.cpp

@@ -37,6 +37,9 @@
 
 void CPUParticles2D::set_emitting(bool p_emitting) {
 
+	if (emitting == p_emitting)
+		return;
+
 	emitting = p_emitting;
 	if (emitting)
 		set_process_internal(true);
@@ -535,6 +538,74 @@ static float rand_from_seed(uint32_t &seed) {
 	return float(seed % uint32_t(65536)) / 65535.0;
 }
 
+void CPUParticles2D::_update_internal() {
+
+	if (particles.size() == 0 || !is_visible_in_tree()) {
+		_set_redraw(false);
+		return;
+	}
+
+	float delta = get_process_delta_time();
+	if (emitting) {
+		inactive_time = 0;
+	} else {
+		inactive_time += delta;
+		if (inactive_time > lifetime * 1.2) {
+			set_process_internal(false);
+			_set_redraw(false);
+
+			//reset variables
+			time = 0;
+			inactive_time = 0;
+			frame_remainder = 0;
+			cycle = 0;
+			return;
+		}
+	}
+	_set_redraw(true);
+
+	if (time == 0 && pre_process_time > 0.0) {
+
+		float frame_time;
+		if (fixed_fps > 0)
+			frame_time = 1.0 / fixed_fps;
+		else
+			frame_time = 1.0 / 30.0;
+
+		float todo = pre_process_time;
+
+		while (todo >= 0) {
+			_particles_process(frame_time);
+			todo -= frame_time;
+		}
+	}
+
+	if (fixed_fps > 0) {
+		float frame_time = 1.0 / fixed_fps;
+		float decr = frame_time;
+
+		float ldelta = delta;
+		if (ldelta > 0.1) { //avoid recursive stalls if fps goes below 10
+			ldelta = 0.1;
+		} else if (ldelta <= 0.0) { //unlikely but..
+			ldelta = 0.001;
+		}
+		float todo = frame_remainder + ldelta;
+
+		while (todo >= frame_time) {
+			_particles_process(frame_time);
+			todo -= decr;
+		}
+
+		frame_remainder = todo;
+
+	} else {
+		_particles_process(delta);
+	}
+
+	_update_particle_data_buffer();
+}
+
 void CPUParticles2D::_particles_process(float p_delta) {
 
 	p_delta *= speed_scale;
@@ -1000,6 +1071,10 @@ void CPUParticles2D::_notification(int p_what) {
 	}
 
 	if (p_what == NOTIFICATION_DRAW) {
+		// first update before rendering to avoid one frame delay after emitting starts
+		if (emitting && (time == 0))
+			_update_internal();
+
 		if (!redraw)
 			return; // don't add to render list
 
@@ -1017,71 +1092,7 @@ void CPUParticles2D::_notification(int p_what) {
 	}
 
 	if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
-
-		if (particles.size() == 0 || !is_visible_in_tree()) {
-			_set_redraw(false);
-			return;
-		}
-
-		float delta = get_process_delta_time();
-		if (emitting) {
-			inactive_time = 0;
-		} else {
-			inactive_time += delta;
-			if (inactive_time > lifetime * 1.2) {
-				set_process_internal(false);
-				_set_redraw(false);
-
-				//reset variables
-				time = 0;
-				inactive_time = 0;
-				frame_remainder = 0;
-				cycle = 0;
-				return;
-			}
-		}
-		_set_redraw(true);
-
-		if (time == 0 && pre_process_time > 0.0) {
-
-			float frame_time;
-			if (fixed_fps > 0)
-				frame_time = 1.0 / fixed_fps;
-			else
-				frame_time = 1.0 / 30.0;
-
-			float todo = pre_process_time;
-
-			while (todo >= 0) {
-				_particles_process(frame_time);
-				todo -= frame_time;
-			}
-		}
-
-		if (fixed_fps > 0) {
-			float frame_time = 1.0 / fixed_fps;
-			float decr = frame_time;
-
-			float ldelta = delta;
-			if (ldelta > 0.1) { //avoid recursive stalls if fps goes below 10
-				ldelta = 0.1;
-			} else if (ldelta <= 0.0) { //unlikely but..
-				ldelta = 0.001;
-			}
-			float todo = frame_remainder + ldelta;
-
-			while (todo >= frame_time) {
-				_particles_process(frame_time);
-				todo -= decr;
-			}
-
-			frame_remainder = todo;
-
-		} else {
-			_particles_process(delta);
-		}
-
-		_update_particle_data_buffer();
+		_update_internal();
 	}
 
 	if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {

+ 1 - 0
scene/2d/cpu_particles_2d.h

@@ -174,6 +174,7 @@ private:
 
 	Vector2 gravity;
 
+	void _update_internal();
 	void _particles_process(float p_delta);
 	void _update_particle_data_buffer();
 

+ 95 - 73
scene/3d/cpu_particles.cpp

@@ -46,9 +46,17 @@ PoolVector<Face3> CPUParticles::get_faces(uint32_t p_usage_flags) const {
 
 void CPUParticles::set_emitting(bool p_emitting) {
 
+	if (emitting == p_emitting)
+		return;
+
 	emitting = p_emitting;
-	if (emitting)
+	if (emitting) {
 		set_process_internal(true);
+
+		// first update before rendering to avoid one frame delay after emitting starts
+		if (time == 0)
+			_update_internal();
+	}
 }
 
 void CPUParticles::set_amount(int p_amount) {
@@ -508,6 +516,81 @@ static float rand_from_seed(uint32_t &seed) {
 	return float(seed % uint32_t(65536)) / 65535.0;
 }
 
+void CPUParticles::_update_internal() {
+
+	if (particles.size() == 0 || !is_visible_in_tree()) {
+		_set_redraw(false);
+		return;
+	}
+
+	float delta = get_process_delta_time();
+	if (emitting) {
+		inactive_time = 0;
+	} else {
+		inactive_time += delta;
+		if (inactive_time > lifetime * 1.2) {
+			set_process_internal(false);
+			_set_redraw(false);
+
+			//reset variables
+			time = 0;
+			inactive_time = 0;
+			frame_remainder = 0;
+			cycle = 0;
+			return;
+		}
+	}
+	_set_redraw(true);
+
+	bool processed = false;
+
+	if (time == 0 && pre_process_time > 0.0) {
+
+		float frame_time;
+		if (fixed_fps > 0)
+			frame_time = 1.0 / fixed_fps;
+		else
+			frame_time = 1.0 / 30.0;
+
+		float todo = pre_process_time;
+
+		while (todo >= 0) {
+			_particles_process(frame_time);
+			processed = true;
+			todo -= frame_time;
+		}
+	}
+
+	if (fixed_fps > 0) {
+		float frame_time = 1.0 / fixed_fps;
+		float decr = frame_time;
+
+		float ldelta = delta;
+		if (ldelta > 0.1) { //avoid recursive stalls if fps goes below 10
+			ldelta = 0.1;
+		} else if (ldelta <= 0.0) { //unlikely but..
+			ldelta = 0.001;
+		}
+		float todo = frame_remainder + ldelta;
+
+		while (todo >= frame_time) {
+			_particles_process(frame_time);
+			processed = true;
+			todo -= decr;
+		}
+
+		frame_remainder = todo;
+
+	} else {
+		_particles_process(delta);
+		processed = true;
+	}
+
+	if (processed) {
+		_update_particle_data_buffer();
+	}
+}
+
 void CPUParticles::_particles_process(float p_delta) {
 
 	p_delta *= speed_scale;
@@ -1068,85 +1151,24 @@ void CPUParticles::_notification(int p_what) {
 
 	if (p_what == NOTIFICATION_ENTER_TREE) {
 		set_process_internal(emitting);
+
+		// first update before rendering to avoid one frame delay after emitting starts
+		if (emitting && (time == 0))
+			_update_internal();
 	}
 
 	if (p_what == NOTIFICATION_EXIT_TREE) {
 		_set_redraw(false);
 	}
 
-	if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
-
-		if (particles.size() == 0 || !is_visible_in_tree()) {
-			_set_redraw(false);
-			return;
-		}
-
-		float delta = get_process_delta_time();
-		if (emitting) {
-			inactive_time = 0;
-		} else {
-			inactive_time += delta;
-			if (inactive_time > lifetime * 1.2) {
-				set_process_internal(false);
-				_set_redraw(false);
-
-				//reset variables
-				time = 0;
-				inactive_time = 0;
-				frame_remainder = 0;
-				cycle = 0;
-				return;
-			}
-		}
-		_set_redraw(true);
-
-		bool processed = false;
-
-		if (time == 0 && pre_process_time > 0.0) {
-
-			float frame_time;
-			if (fixed_fps > 0)
-				frame_time = 1.0 / fixed_fps;
-			else
-				frame_time = 1.0 / 30.0;
-
-			float todo = pre_process_time;
-
-			while (todo >= 0) {
-				_particles_process(frame_time);
-				processed = true;
-				todo -= frame_time;
-			}
-		}
-
-		if (fixed_fps > 0) {
-			float frame_time = 1.0 / fixed_fps;
-			float decr = frame_time;
-
-			float ldelta = delta;
-			if (ldelta > 0.1) { //avoid recursive stalls if fps goes below 10
-				ldelta = 0.1;
-			} else if (ldelta <= 0.0) { //unlikely but..
-				ldelta = 0.001;
-			}
-			float todo = frame_remainder + ldelta;
-
-			while (todo >= frame_time) {
-				_particles_process(frame_time);
-				processed = true;
-				todo -= decr;
-			}
-
-			frame_remainder = todo;
-
-		} else {
-			_particles_process(delta);
-			processed = true;
-		}
+	if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
+		// first update before rendering to avoid one frame delay after emitting starts
+		if (emitting && (time == 0))
+			_update_internal();
+	}
 
-		if (processed) {
-			_update_particle_data_buffer();
-		}
+	if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
+		_update_internal();
 	}
 
 	if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {

+ 1 - 0
scene/3d/cpu_particles.h

@@ -173,6 +173,7 @@ private:
 
 	Vector3 gravity;
 
+	void _update_internal();
 	void _particles_process(float p_delta);
 	void _update_particle_data_buffer();