//------------------------------------------------------------------------------ // bool gosFX::PointCloud::AnimateParticle( uint32_t index, const Stuff::LinearMatrix4D* world_to_new_local, Stuff::Time till ) { Check_Object(this); // //----------------------------------------------------------------------- // If this cloud is unparented, we need to transform the point from local // space into world space and set the internal position/velocity pointers // to these temporary values //----------------------------------------------------------------------- // Particle* particle = GetParticle(index); Check_Object(particle); float age = particle->m_age; if(age >= 1.0f) return false; Set_Statistic(Point_Count, Point_Count + 1); Stuff::Vector3D* velocity = &particle->m_localLinearVelocity; Stuff::Point3D* translation = &m_P_localTranslation[index]; int32_t sim_mode = GetSimulationMode(); if(sim_mode == DynamicWorldSpaceSimulationMode) { Check_Object(translation); Check_Object(velocity); particle->m_worldLinearVelocity.Multiply(*velocity, m_localToWorld); particle->m_worldTranslation.Multiply(*translation, m_localToWorld); translation = &particle->m_worldTranslation; velocity = &particle->m_worldLinearVelocity; } Check_Object(translation); Check_Object(velocity); // //------------------------------------------------------------------ // First, calculate the drag on the particle. Drag can never assist // velocity //------------------------------------------------------------------ // float seed = particle->m_seed; Specification* spec = GetSpecification(); Check_Object(spec); Stuff::Vector3D ether; ether.x = spec->m_pEtherVelocityX.ComputeValue(age, seed); ether.y = spec->m_pEtherVelocityY.ComputeValue(age, seed); ether.z = spec->m_pEtherVelocityZ.ComputeValue(age, seed); Stuff::Vector3D accel(Stuff::Vector3D::Identity); // //------------------------------------------------------------------- // Deal with pseudo-world simulation. In this mode, we interpret the // forces as if they are already in worldspace, and we transform them // back to local space //------------------------------------------------------------------- // float drag = -spec->m_pDrag.ComputeValue(age, seed); Max_Clamp(drag, 0.0f); if(sim_mode == StaticWorldSpaceSimulationMode) { Stuff::LinearMatrix4D world_to_effect; world_to_effect.Invert(m_localToWorld); Stuff::Vector3D local_ether; local_ether.MultiplyByInverse(ether, world_to_effect); Stuff::Vector3D rel_vel; rel_vel.Subtract(*velocity, local_ether); accel.Multiply(rel_vel, drag); // //----------------------------------------- // Now, add in acceleration of the particle //----------------------------------------- // Stuff::Vector3D world_accel; world_accel.x = spec->m_pAccelerationX.ComputeValue(age, seed); world_accel.y = spec->m_pAccelerationY.ComputeValue(age, seed); world_accel.z = spec->m_pAccelerationZ.ComputeValue(age, seed); Stuff::Vector3D local_accel; local_accel.Multiply(world_accel, world_to_effect); accel += local_accel; } // //---------------------------------------------------------------------- // Otherwise, just add the forces in the same space the particles are in //---------------------------------------------------------------------- // else { Stuff::Vector3D rel_vel; rel_vel.Subtract(*velocity, ether); accel.Multiply(rel_vel, drag); // //----------------------------------------- // Now, add in acceleration of the particle //----------------------------------------- // accel.x += spec->m_pAccelerationX.ComputeValue(age, seed); accel.y += spec->m_pAccelerationY.ComputeValue(age, seed); accel.z += spec->m_pAccelerationZ.ComputeValue(age, seed); } // //------------------------------------------------- // Compute the particle's new velocity and position //------------------------------------------------- // float time_slice = static_cast<float>(till - m_lastRan); velocity->AddScaled(*velocity, accel, time_slice); translation->AddScaled(*translation, *velocity, time_slice); // //--------------------------------------------------------------------- // If we are unparented, we need to transform the velocity and position // data back into the NEW local space //--------------------------------------------------------------------- // if(sim_mode == DynamicWorldSpaceSimulationMode) { Check_Object(world_to_new_local); particle->m_localLinearVelocity.Multiply( particle->m_worldLinearVelocity, *world_to_new_local ); m_P_localTranslation[index].Multiply( particle->m_worldTranslation, *world_to_new_local ); } // //------------------ // Animate the color //------------------ // Check_Pointer(m_P_color); m_P_color[index].red = spec->m_pRed.ComputeValue(age, seed); m_P_color[index].green = spec->m_pGreen.ComputeValue(age, seed); m_P_color[index].blue = spec->m_pBlue.ComputeValue(age, seed); m_P_color[index].alpha = spec->m_pAlpha.ComputeValue(age, seed); return true; }
//------------------------------------------------------------------------------ // bool gosFX::ParticleCloud::Execute(ExecuteInfo *info) { Check_Object(this); Check_Object(info); Verify(IsExecuted()); // //-------------------------------------------------------------------- // If we were given a new matrix, see if we have a parent. If so, // concatenate the two and figure out its inverse. If no parent, then // just invert the new matrix, otherwise just use the existing one //-------------------------------------------------------------------- // Stuff::LinearMatrix4D new_world_to_local; Stuff::LinearMatrix4D *matrix = NULL; int sim_mode = GetSimulationMode(); if (sim_mode == DynamicWorldSpaceSimulationMode) { Stuff::LinearMatrix4D local_to_world; local_to_world.Multiply(m_localToParent, *info->m_parentToWorld); new_world_to_local.Invert(local_to_world); matrix = &new_world_to_local; } // //-------------------------------------------------------- // Figure out the birth rate and request the new particles //-------------------------------------------------------- // Specification *spec = GetSpecification(); Check_Object(spec); Stuff::Scalar dT = static_cast<Stuff::Scalar>(info->m_time - m_lastRan); Verify(dT >= 0.0f); Stuff::Scalar prev_age = m_age; m_age += dT * m_ageRate; if (m_age >= 1.0f) m_birthAccumulator = 0.0f; else { Stuff::Scalar new_life = spec->m_particlesPerSecond.ComputeValue(m_age, m_seed); Min_Clamp(new_life, 0.0f); m_birthAccumulator += dT * new_life; } // //----------------------------------- // Deal with all the active particles //----------------------------------- // int i; int last_real = -1; for (i = 0; i < m_activeParticleCount; i++) { // //-------------------------------------------------------------------- // If the particle is active, age it and if it is not yet time to die, // go to the next particle, otherwise kill it //-------------------------------------------------------------------- // Particle *particle = GetParticle(i); Check_Object(particle); if (particle->m_age < 1.0f) { particle->m_age += dT*particle->m_ageRate; if (AnimateParticle(i, matrix, info->m_time)) { last_real = i; continue; } DestroyParticle(i); } // //-------------------------------------------------------------------- // If there are new particles to be born, go ahead and create them now //-------------------------------------------------------------------- // if (m_birthAccumulator >= 1.0f) { Stuff::Point3D translation; CreateNewParticle(i, &translation); if (AnimateParticle(i, matrix, info->m_time)) last_real = i; else DestroyParticle(i); m_birthAccumulator -= 1.0f; } } m_activeParticleCount = last_real + 1; // //---------------------------------------------------------------------- // If there are still new particles to be born, then we must try to grow // the active particle count //---------------------------------------------------------------------- // while ( m_birthAccumulator >= 1.0f && m_activeParticleCount < spec->m_maxParticleCount ) { i = m_activeParticleCount++; Stuff::Point3D translation; CreateNewParticle(i, &translation); if (!AnimateParticle(i, matrix, info->m_time)) { DestroyParticle(i); --m_activeParticleCount; } m_birthAccumulator -= 1.0f; } // //--------------------------------------------------------- // Only allow fractional births to carry over to next frame //--------------------------------------------------------- // m_birthAccumulator -= static_cast<Stuff::Scalar>(floor(m_birthAccumulator)); // //---------------------------- // Now let effect do its thing //---------------------------- // m_age = prev_age; return Effect::Execute(info); }