Пример #1
0
void Particles2D::_notification(int p_what) {

	switch(p_what) {

		case NOTIFICATION_PROCESS: {

			_process_particles( get_process_delta_time() );
		} break;

		case NOTIFICATION_ENTER_TREE: {

			float ppt=preprocess;
			while(ppt>0) {
				_process_particles(0.1);
				ppt-=0.1;
			}
		} break;
		case NOTIFICATION_DRAW: {


			if (particles.size()==0 || lifetime==0)
				return;

			RID ci=get_canvas_item();
			Size2 size(1,1);
			Point2 center;
			int total_frames=1;

			if (!texture.is_null()) {
				size=texture->get_size();
				size.x/=h_frames;
				size.y/=v_frames;
				total_frames=h_frames*v_frames;
			}


			float time_pos=(time/lifetime);

			Particle *pdata=&particles[0];
			int particle_count=particles.size();

			RID texrid;

			if (texture.is_valid())
				texrid = texture->get_rid();

			Matrix32 invxform;
			if (!local_space)
				invxform=get_global_transform().affine_inverse();

			int start_particle = (int)(time * (float)particle_count / lifetime);
			
			for (int id=0;id<particle_count;++id) {
				int i = start_particle + id;
				if (i >= particle_count) {
					i -= particle_count;
				}

				Particle &p=pdata[i];
				if (!p.active)
					continue;

				float ptime = ((float)i / particle_count)*explosiveness;

				if (ptime<time_pos)
					ptime=time_pos-ptime;
				else
					ptime=(1.0-ptime)+time_pos;

				uint32_t rand_seed=p.seed*(i+1);

				Color color;

				if(color_ramp.is_valid())
				{
					color = color_ramp->get_color_at_offset(ptime);
				} else
				{
					color = default_color;
				}


				{
					float huerand=_rand_from_seed(&rand_seed);
					float huerot = param[PARAM_HUE_VARIATION] + randomness[PARAM_HUE_VARIATION] * huerand;

					if (Math::abs(huerot) > CMP_EPSILON) {

						float h=color.get_h();
						float s=color.get_s();
						float v=color.get_v();
						float a=color.a;
						//float preh=h;
						h+=huerot;
						h=Math::abs(Math::fposmod(h,1.0));
						//print_line("rand: "+rtos(randomness[PARAM_HUE_VARIATION])+" rand: "+rtos(huerand));
						//print_line(itos(i)+":hue: "+rtos(preh)+" + "+rtos(huerot)+" = "+rtos(h));
						color.set_hsv(h,s,v);
						color.a=a;
					}
				}

				float initial_size = param[PARAM_INITIAL_SIZE]+param[PARAM_INITIAL_SIZE]*_rand_from_seed(&rand_seed)*randomness[PARAM_FINAL_SIZE];
				float final_size = param[PARAM_FINAL_SIZE]+param[PARAM_FINAL_SIZE]*_rand_from_seed(&rand_seed)*randomness[PARAM_FINAL_SIZE];

				float size_mult=initial_size*(1.0-ptime) + final_size*ptime;

				//Size2 rectsize=size * size_mult;
				//rectsize=rectsize.floor();

				//Rect2 r = Rect2(Vecto,rectsize);

				Matrix32 xform;

				if (p.rot) {

					xform.set_rotation(p.rot);
					xform.translate(-size*size_mult/2.0);
					xform.elements[2]+=p.pos;
				} else {
					xform.elements[2]=-size*size_mult/2.0;
					xform.elements[2]+=p.pos;
				}

				if (!local_space) {
					xform = invxform * xform;
				}


				xform.scale_basis(Size2(size_mult,size_mult));


				VisualServer::get_singleton()->canvas_item_add_set_transform(ci,xform);


				if (texrid.is_valid()) {

					Rect2 src_rect;
					src_rect.size=size;

					if (total_frames>1) {
						int frame = Math::fast_ftoi(Math::floor(p.frame*total_frames)) % total_frames;
						src_rect.pos.x = size.x * (frame%h_frames);
						src_rect.pos.y = size.y * (frame/h_frames);
					}


					texture->draw_rect_region(ci,Rect2(Point2(),size),src_rect,color);
					//VisualServer::get_singleton()->canvas_item_add_texture_rect(ci,r,texrid,false,color);
				} else {
					VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(Point2(),size),color);

				}

			}


		} break;

	}

}
Пример #2
0
void ParticleSystemProcessSW::process(const ParticleSystemSW *p_system,const Transform& p_transform,float p_time) {

	valid=false;
	if (p_system->amount<=0) {
		ERR_EXPLAIN("Invalid amount of particles: "+itos(p_system->amount));
		ERR_FAIL_COND(p_system->amount<=0);
	}
	if (p_system->attractor_count<0 || p_system->attractor_count>VS::MAX_PARTICLE_ATTRACTORS) {
		ERR_EXPLAIN("Invalid amount of particle attractors.");
		ERR_FAIL_COND(p_system->attractor_count<0 || p_system->attractor_count>VS::MAX_PARTICLE_ATTRACTORS);
	}
	float lifetime = p_system->particle_vars[VS::PARTICLE_LIFETIME];
	if (lifetime<CMP_EPSILON) {
		ERR_EXPLAIN("Particle system lifetime too small.");
		ERR_FAIL_COND(lifetime<CMP_EPSILON);
	}
	valid=true;
	int particle_count=MIN(p_system->amount,ParticleSystemSW::MAX_PARTICLES);;


	int emission_point_count = p_system->emission_points.size();
	DVector<Vector3>::Read r;
	if (emission_point_count)
		r=p_system->emission_points.read();

	if (particle_count!=particle_data.size()) {

		//clear the whole system if particle amount changed
		particle_data.clear();
		particle_data.resize(p_system->amount);
		particle_system_time=0;
	}

	float next_time = particle_system_time+p_time;
	
	if (next_time > lifetime)
		next_time=Math::fmod(next_time,lifetime);
		

	ParticleData *pdata=&particle_data[0];
	Vector3 attractor_positions[VS::MAX_PARTICLE_ATTRACTORS];

	for(int i=0;i<p_system->attractor_count;i++) {

		attractor_positions[i]=p_transform.xform(p_system->attractors[i].pos);
	}


	for(int i=0;i<particle_count;i++) {
	
		ParticleData &p=pdata[i];
		
		float restart_time = (i * lifetime / p_system->amount);
		
		bool restart=false;
		
		if ( next_time < particle_system_time ) {

			if (restart_time > particle_system_time || restart_time < next_time )
				restart=true;

		} else if (restart_time > particle_system_time && restart_time < next_time ) {
			restart=true;
		}

		if (restart) {


			if (p_system->emitting) {
				if (emission_point_count==0) { //use AABB
					if (p_system->local_coordinates)
						p.pos = p_system->emission_half_extents * Vector3( _rand_from_seed(&rand_seed), _rand_from_seed(&rand_seed), _rand_from_seed(&rand_seed) );
					else
						p.pos = p_transform.xform( p_system->emission_half_extents * Vector3( _rand_from_seed(&rand_seed), _rand_from_seed(&rand_seed), _rand_from_seed(&rand_seed) ) );
				} else {
					//use preset positions
					if (p_system->local_coordinates)
						p.pos = r[_irand_from_seed(&rand_seed)%emission_point_count];
					else
						p.pos = p_transform.xform( r[_irand_from_seed(&rand_seed)%emission_point_count] );
				}
							
				
				float angle1 = _rand_from_seed(&rand_seed)*p_system->particle_vars[VS::PARTICLE_SPREAD]*Math_PI;
				float angle2 = _rand_from_seed(&rand_seed)*20.0*Math_PI; // make it more random like
				
				Vector3 rot_xz=Vector3( Math::sin(angle1), 0.0, Math::cos(angle1) );
				Vector3 rot = Vector3( Math::cos(angle2)*rot_xz.x,Math::sin(angle2)*rot_xz.x, rot_xz.z);

				p.vel=(rot*p_system->particle_vars[VS::PARTICLE_LINEAR_VELOCITY]+rot*p_system->particle_randomness[VS::PARTICLE_LINEAR_VELOCITY]*_rand_from_seed(&rand_seed));
				if (!p_system->local_coordinates)
					p.vel=p_transform.basis.xform( p.vel );

				p.vel+=p_system->emission_base_velocity;
				
				p.rot=p_system->particle_vars[VS::PARTICLE_INITIAL_ANGLE]+p_system->particle_randomness[VS::PARTICLE_INITIAL_ANGLE]*_rand_from_seed(&rand_seed);				
				p.active=true;
				for(int r=0;r<PARTICLE_RANDOM_NUMBERS;r++)
					p.random[r]=_rand_from_seed(&rand_seed);

			} else {
			
				p.pos=Vector3();
				p.rot=0;
				p.vel=Vector3();
				p.active=false;
			}
		
		} else {
		
			if (!p.active)
				continue;

			Vector3 force;
			//apply gravity
			force=p_system->gravity_normal * (p_system->particle_vars[VS::PARTICLE_GRAVITY]+(p_system->particle_randomness[VS::PARTICLE_GRAVITY]*p.random[0]));
			//apply linear acceleration
			force+=p.vel.normalized() * (p_system->particle_vars[VS::PARTICLE_LINEAR_ACCELERATION]+p_system->particle_randomness[VS::PARTICLE_LINEAR_ACCELERATION]*p.random[1]);
			//apply radial acceleration
			Vector3 org;
			if (!p_system->local_coordinates)
				org=p_transform.origin;
			force+=(p.pos-org).normalized() * (p_system->particle_vars[VS::PARTICLE_RADIAL_ACCELERATION]+p_system->particle_randomness[VS::PARTICLE_RADIAL_ACCELERATION]*p.random[2]);
			//apply tangential acceleration
			force+=(p.pos-org).cross(p_system->gravity_normal).normalized() * (p_system->particle_vars[VS::PARTICLE_TANGENTIAL_ACCELERATION]+p_system->particle_randomness[VS::PARTICLE_TANGENTIAL_ACCELERATION]*p.random[3]);
			//apply attractor forces
			for(int a=0;a<p_system->attractor_count;a++) {

				force+=(p.pos-attractor_positions[a]).normalized() * p_system->attractors[a].force;
			}


			p.vel+=force * p_time;
			if (p_system->particle_vars[VS::PARTICLE_DAMPING]) {

				float v = p.vel.length();
				float damp = p_system->particle_vars[VS::PARTICLE_DAMPING] + p_system->particle_vars[VS::PARTICLE_DAMPING] * p_system->particle_randomness[VS::PARTICLE_DAMPING];
				v -= damp * p_time;
				if (v<0) {
					p.vel=Vector3();
				} else {
					p.vel=p.vel.normalized() * v;
				}

			}
			p.rot+=(p_system->particle_vars[VS::PARTICLE_ANGULAR_VELOCITY]+p_system->particle_randomness[VS::PARTICLE_ANGULAR_VELOCITY]*p.random[4]) *p_time;
			p.pos+=p.vel * p_time;
		}
	}

	particle_system_time=Math::fmod( particle_system_time+p_time, lifetime );


}
Пример #3
0
void Particles2D::_process_particles(float p_delta) {

	if (particles.size()==0 || lifetime==0)
		return;

	p_delta*=time_scale;

	float frame_time=p_delta;

	if (emit_timeout > 0) {
		time_to_live -= frame_time;
		if (time_to_live < 0) {

			emitting = false;
			_change_notify("config/emitting");
		};
	};

	float next_time = time+frame_time;

	if (next_time > lifetime)
		next_time=Math::fmod(next_time,lifetime);


	Particle *pdata=&particles[0];
	int particle_count=particles.size();
	Matrix32 xform;
	if (!local_space)
		xform=get_global_transform();

	active_count=0;

	DVector<Point2>::Read r;
	int emission_point_count=0;
	if (emission_points.size()) {

		emission_point_count=emission_points.size();
		r=emission_points.read();
	}

	int attractor_count=0;
	AttractorCache *attractor_ptr=NULL;

	if (attractors.size()) {
		if (attractors.size()!=attractor_cache.size()) {
			attractor_cache.resize(attractors.size());
		}

		int idx=0;
		Matrix32 m;
		if (local_space) {
			m= get_global_transform().affine_inverse();
		}
		for (Set<ParticleAttractor2D*>::Element *E=attractors.front();E;E=E->next()) {

			attractor_cache[idx].pos=m.xform( E->get()->get_global_pos() );
			attractor_cache[idx].attractor=E->get();
			idx++;
		}

		attractor_ptr=attractor_cache.ptr();
		attractor_count=attractor_cache.size();
	}

	for(int i=0;i<particle_count;i++) {

		Particle &p=pdata[i];

		float restart_time = (i * lifetime / particle_count) * explosiveness;

		bool restart=false;

		if ( next_time < time ) {

			if (restart_time > time || restart_time < next_time )
				restart=true;

		} else if (restart_time > time && restart_time < next_time ) {
			restart=true;
		}

		if (restart) {


			if (emitting) {

				p.pos=emissor_offset;
				if (emission_point_count) {


					Vector2 ep = r[Math::rand()%emission_point_count];
					if (!local_space) {
						p.pos=xform.xform(p.pos+ep*extents);
					} else {
						p.pos+=ep*extents;
					}
				} else {
					if (!local_space) {
						p.pos=xform.xform(p.pos+Vector2(Math::random(-extents.x,extents.x),Math::random(-extents.y,extents.y)));
					} else {
						p.pos+=Vector2(Math::random(-extents.x,extents.x),Math::random(-extents.y,extents.y));
					}
				}
				p.seed=Math::rand() % 12345678;
				uint32_t rand_seed=p.seed*(i+1);

				float angle = Math::deg2rad(param[PARAM_DIRECTION]+_rand_from_seed(&rand_seed)*param[PARAM_SPREAD]);

				p.velocity=Vector2( Math::sin(angle), Math::cos(angle) );
				if (!local_space) {

					p.velocity = xform.basis_xform(p.velocity).normalized();
				}

				p.velocity*=param[PARAM_LINEAR_VELOCITY]+param[PARAM_LINEAR_VELOCITY]*_rand_from_seed(&rand_seed)*randomness[PARAM_LINEAR_VELOCITY];
				p.velocity+=initial_velocity;
				p.active=true;
				p.rot=Math::deg2rad(param[PARAM_INITIAL_ANGLE]+param[PARAM_INITIAL_ANGLE]*randomness[PARAM_INITIAL_ANGLE]*_rand_from_seed(&rand_seed));
				active_count++;

				p.frame=Math::fmod(param[PARAM_ANIM_INITIAL_POS]+randomness[PARAM_ANIM_INITIAL_POS]*_rand_from_seed(&rand_seed),1.0);


			} else {

				p.active=false;
			}

		} else {

			if (!p.active)
				continue;

			uint32_t rand_seed=p.seed*(i+1);

			Vector2 force;

			//apply gravity
			float gravity_dir = Math::deg2rad( param[PARAM_GRAVITY_DIRECTION]+180*randomness[PARAM_GRAVITY_DIRECTION]*_rand_from_seed(&rand_seed));
			force+=Vector2( Math::sin(gravity_dir), Math::cos(gravity_dir) ) * (param[PARAM_GRAVITY_STRENGTH]+param[PARAM_GRAVITY_STRENGTH]*randomness[PARAM_GRAVITY_STRENGTH]*_rand_from_seed(&rand_seed));
			//apply radial
			Vector2 rvec = (p.pos - emissor_offset).normalized();
			force+=rvec*(param[PARAM_RADIAL_ACCEL]+param[PARAM_RADIAL_ACCEL]*randomness[PARAM_RADIAL_ACCEL]*_rand_from_seed(&rand_seed));
			//apply orbit
			float orbitvel = (param[PARAM_ORBIT_VELOCITY]+param[PARAM_ORBIT_VELOCITY]*randomness[PARAM_ORBIT_VELOCITY]*_rand_from_seed(&rand_seed));
			if (orbitvel!=0) {
				Vector2 rel = p.pos - xform.elements[2];
				Matrix32 rot(orbitvel*frame_time,Vector2());
				p.pos = rot.xform(rel) + xform.elements[2];

			}

			Vector2 tvec=rvec.tangent();
			force+=tvec*(param[PARAM_TANGENTIAL_ACCEL]+param[PARAM_TANGENTIAL_ACCEL]*randomness[PARAM_TANGENTIAL_ACCEL]*_rand_from_seed(&rand_seed));

			for(int j=0;j<attractor_count;j++) {

				Vector2 vec = (attractor_ptr[j].pos - p.pos);
				float vl = vec.length();

				if (!attractor_ptr[j].attractor->enabled ||  vl==0 || vl > attractor_ptr[j].attractor->radius)
					continue;



				force+=vec*attractor_ptr[j].attractor->gravity;
				float fvl = p.velocity.length();
				if (fvl && attractor_ptr[j].attractor->absorption) {
					Vector2 target = vec.normalized();
					p.velocity = p.velocity.normalized().linear_interpolate(target,MIN(frame_time*attractor_ptr[j].attractor->absorption,1))*fvl;
				}

				if (attractor_ptr[j].attractor->disable_radius && vl < attractor_ptr[j].attractor->disable_radius) {
					p.active=false;
				}
			}

			p.velocity+=force*frame_time;

			if (param[PARAM_DAMPING]) {
				float dmp = param[PARAM_DAMPING]+param[PARAM_DAMPING]*randomness[PARAM_DAMPING]*_rand_from_seed(&rand_seed);
				float v = p.velocity.length();
				v -= dmp * frame_time;
				if (v<=0) {
					p.velocity=Vector2();
				} else {
					p.velocity=p.velocity.normalized() * v;
				}

			}

			p.pos+=p.velocity*frame_time;
			p.rot+=Math::lerp(param[PARAM_SPIN_VELOCITY],param[PARAM_SPIN_VELOCITY]*randomness[PARAM_SPIN_VELOCITY]*_rand_from_seed(&rand_seed),randomness[PARAM_SPIN_VELOCITY])*frame_time;
			float anim_spd=param[PARAM_ANIM_SPEED_SCALE]+param[PARAM_ANIM_SPEED_SCALE]*randomness[PARAM_ANIM_SPEED_SCALE]*_rand_from_seed(&rand_seed);
			p.frame=Math::fposmod(p.frame+(frame_time/lifetime)*anim_spd,1.0);

			active_count++;

		}


	}



	time=Math::fmod( time+frame_time, lifetime );
	if (!emitting && active_count==0) {
		set_process(false);

	}

	update();


}