UnitQuaternion& UnitQuaternion::FastLerp( const UnitQuaternion& p, const UnitQuaternion& q, Scalar t ) { if (!UseFastLerp) return Lerp(p,q,t); Start_Timer(SlerpTime); Set_Statistic(SlerpCount, SlerpCount+1); Verify(quaternionFastLerpTableBuilt); Scalar cosom,sclp,sclq; cosom = p.x*q.x + p.y*q.y + p.z*q.z + p.w*q.w; if ( (1.0f + cosom) > 0.01f) { // usual case if ( (1.0f - cosom) > 0.00001f ) { //usual case //table_entry = (int)Scaled_Float_To_Bits(cosom, MinCosom, MaxCosom, 10); float tabled_float = cosom - MinCosom; int cos_table_entry = Truncate_Float_To_Word(((tabled_float*CosomRangeOverOne) * CosBiggestNumber)); Verify(cos_table_entry >= 0); Verify(cos_table_entry <= QuaternionLerpTableSize); #if 0 sclp = Sin((1.0f - t)*Omega_Table[cos_table_entry]) * SinomOverOne_Table[cos_table_entry]; sclq = Sin(t*Omega_Table[cos_table_entry]) * SinomOverOne_Table[cos_table_entry]; #else float difference, percent, lerped_sin; tabled_float = ((1.0f - t)*Omega_Table[cos_table_entry]) - MinSin; int sclp_table_entry = Truncate_Float_To_Word(((tabled_float*SinRangeOverOne) * SinBiggestNumber)); if (!(sclp_table_entry < SinTableSize)) { Max_Clamp(sclp_table_entry, SinTableSize-1); } Verify(sclp_table_entry >= 0 && sclp_table_entry < SinTableSize); difference = tabled_float - (SinIncrement * sclp_table_entry); percent = difference / SinIncrement; int lerp_to_entry = sclp_table_entry + 1; Max_Clamp(lerp_to_entry, SinTableSize-1); lerped_sin = Stuff::Lerp(Sin_Table[sclp_table_entry], Sin_Table[lerp_to_entry], percent); sclp = lerped_sin * SinomOverOne_Table[cos_table_entry]; tabled_float = (t*Omega_Table[cos_table_entry]) - MinSin; int sclq_table_entry = Truncate_Float_To_Word(((tabled_float*SinRangeOverOne) * SinBiggestNumber)); Verify(sclq_table_entry >= 0 && sclq_table_entry < SinTableSize); difference = tabled_float - (SinIncrement * sclq_table_entry); percent = difference / SinIncrement; lerp_to_entry = sclq_table_entry + 1; Max_Clamp(lerp_to_entry, SinTableSize-1); lerped_sin = Stuff::Lerp(Sin_Table[sclq_table_entry], Sin_Table[lerp_to_entry], percent); sclq = lerped_sin * SinomOverOne_Table[cos_table_entry]; #endif } else { // ends very close -- just lerp sclp = 1.0f - t; sclq = t; } x = sclp*p.x + sclq*q.x; y = sclp*p.y + sclq*q.y; z = sclp*p.z + sclq*q.z; w = sclp*p.w + sclq*q.w; } else { //SPEW(("jerryeds","SPECIAL CASE")); /* p and q nearly opposite on sphere-- this is a 360 degree rotation, but the axis of rotation is undefined, so slerp really is undefined too. So this apparently picks an arbitrary plane of rotation. However, I think this code is incorrect. */ //really we want the shortest distance. They are almost on top of each other. UnitQuaternion r; r.Subtract(q, p); Vector3D scaled_rotation; scaled_rotation = r; scaled_rotation *= t; UnitQuaternion scaled_quat; scaled_quat = scaled_rotation; Multiply(scaled_quat, p); Normalize(); } Stop_Timer(SlerpTime); return *this; }
//------------------------------------------------------------------------------ // 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; }