Browse Source

Merge pull request #29700 from clayjohn/cpuparticles_transform_bug

Fix CPU particles bug with local_coords and transform
Rémi Verschelde 6 years ago
parent
commit
9d3342545d
4 changed files with 93 additions and 14 deletions
  1. 39 6
      scene/2d/cpu_particles_2d.cpp
  2. 2 0
      scene/2d/cpu_particles_2d.h
  3. 49 7
      scene/3d/cpu_particles.cpp
  4. 3 1
      scene/3d/cpu_particles.h

+ 39 - 6
scene/2d/cpu_particles_2d.cpp

@@ -86,7 +86,9 @@ void CPUParticles2D::set_randomness_ratio(float p_ratio) {
 void CPUParticles2D::set_use_local_coordinates(bool p_enable) {
 
 	local_coords = p_enable;
+	set_notify_transform(!p_enable);
 }
+
 void CPUParticles2D::set_speed_scale(float p_scale) {
 
 	speed_scale = p_scale;
@@ -860,11 +862,6 @@ void CPUParticles2D::_update_particle_data_buffer() {
 		PoolVector<Particle>::Read r = particles.read();
 		float *ptr = w.ptr();
 
-		Transform2D un_transform;
-		if (!local_coords) {
-			un_transform = get_global_transform().affine_inverse();
-		}
-
 		if (draw_order != DRAW_ORDER_INDEX) {
 			ow = particle_order.write();
 			order = ow.ptr();
@@ -886,7 +883,7 @@ void CPUParticles2D::_update_particle_data_buffer() {
 			Transform2D t = r[idx].transform;
 
 			if (!local_coords) {
-				t = un_transform * t;
+				t = inv_emission_transform * t;
 			}
 
 			if (r[idx].active) {
@@ -1055,6 +1052,42 @@ void CPUParticles2D::_notification(int p_what) {
 
 		_update_particle_data_buffer();
 	}
+
+	if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
+
+		inv_emission_transform = get_global_transform().affine_inverse();
+
+		if (!local_coords) {
+
+			int pc = particles.size();
+
+			PoolVector<float>::Write w = particle_data.write();
+			PoolVector<Particle>::Read r = particles.read();
+			float *ptr = w.ptr();
+
+			for (int i = 0; i < pc; i++) {
+
+				Transform2D t = inv_emission_transform * r[i].transform;
+
+				if (r[i].active) {
+
+					ptr[0] = t.elements[0][0];
+					ptr[1] = t.elements[1][0];
+					ptr[2] = 0;
+					ptr[3] = t.elements[2][0];
+					ptr[4] = t.elements[0][1];
+					ptr[5] = t.elements[1][1];
+					ptr[6] = 0;
+					ptr[7] = t.elements[2][1];
+
+				} else {
+					zeromem(ptr, sizeof(float) * 8);
+				}
+
+				ptr += 13;
+			}
+		}
+	}
 }
 
 void CPUParticles2D::convert_from_particles(Node *p_particles) {

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

@@ -144,6 +144,8 @@ private:
 	int fixed_fps;
 	bool fractional_delta;
 
+	Transform2D inv_emission_transform;
+
 	DrawOrder draw_order;
 
 	Ref<Texture> texture;

+ 49 - 7
scene/3d/cpu_particles.cpp

@@ -915,11 +915,6 @@ void CPUParticles::_update_particle_data_buffer() {
 		PoolVector<Particle>::Read r = particles.read();
 		float *ptr = w.ptr();
 
-		Transform un_transform;
-		if (!local_coords) {
-			un_transform = get_global_transform().affine_inverse();
-		}
-
 		if (draw_order != DRAW_ORDER_INDEX) {
 			ow = particle_order.write();
 			order = ow.ptr();
@@ -937,7 +932,12 @@ void CPUParticles::_update_particle_data_buffer() {
 					Vector3 dir = c->get_global_transform().basis.get_axis(2); //far away to close
 
 					if (local_coords) {
-						dir = un_transform.basis.xform(dir).normalized();
+
+						// will look different from Particles in editor as this is based on the camera in the scenetree
+						// and not the editor camera
+						dir = inv_emission_transform.xform(dir).normalized();
+					} else {
+						dir = dir.normalized();
 					}
 
 					SortArray<int, SortAxis> sorter;
@@ -955,7 +955,7 @@ void CPUParticles::_update_particle_data_buffer() {
 			Transform t = r[idx].transform;
 
 			if (!local_coords) {
-				t = un_transform * t;
+				t = inv_emission_transform * t;
 			}
 
 			if (r[idx].active) {
@@ -1121,6 +1121,46 @@ void CPUParticles::_notification(int p_what) {
 			_update_particle_data_buffer();
 		}
 	}
+
+	if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
+
+		inv_emission_transform = get_global_transform().affine_inverse();
+
+		if (!local_coords) {
+
+			int pc = particles.size();
+
+			PoolVector<float>::Write w = particle_data.write();
+			PoolVector<Particle>::Read r = particles.read();
+			float *ptr = w.ptr();
+
+			for (int i = 0; i < pc; i++) {
+
+				Transform t = inv_emission_transform * r[i].transform;
+
+				if (r[i].active) {
+					ptr[0] = t.basis.elements[0][0];
+					ptr[1] = t.basis.elements[0][1];
+					ptr[2] = t.basis.elements[0][2];
+					ptr[3] = t.origin.x;
+					ptr[4] = t.basis.elements[1][0];
+					ptr[5] = t.basis.elements[1][1];
+					ptr[6] = t.basis.elements[1][2];
+					ptr[7] = t.origin.y;
+					ptr[8] = t.basis.elements[2][0];
+					ptr[9] = t.basis.elements[2][1];
+					ptr[10] = t.basis.elements[2][2];
+					ptr[11] = t.origin.z;
+				} else {
+					zeromem(ptr, sizeof(float) * 12);
+				}
+
+				ptr += 17;
+			}
+
+			can_update = true;
+		}
+	}
 }
 
 void CPUParticles::convert_from_particles(Node *p_particles) {
@@ -1397,6 +1437,8 @@ CPUParticles::CPUParticles() {
 	cycle = 0;
 	redraw = false;
 
+	set_notify_transform(true);
+
 	multimesh = VisualServer::get_singleton()->multimesh_create();
 	VisualServer::get_singleton()->multimesh_set_visible_instances(multimesh, 0);
 	set_base(multimesh);

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

@@ -116,7 +116,7 @@ private:
 		const Particle *particles;
 
 		bool operator()(int p_a, int p_b) const {
-			return particles[p_a].time < particles[p_b].time;
+			return particles[p_a].time > particles[p_b].time;
 		}
 	};
 
@@ -142,6 +142,8 @@ private:
 	int fixed_fps;
 	bool fractional_delta;
 
+	Transform inv_emission_transform;
+
 	volatile bool can_update;
 
 	DrawOrder draw_order;