bool PFOperatorSimpleSpeed::Proceed(IObject* pCont, PreciseTimeValue timeStart, PreciseTimeValue& timeEnd, Object* pSystem, INode* pNode, INode* actionNode, IPFIntegrator* integrator) { // acquire all necessary channels, create additional if needed IParticleChannelNewR* chNew = GetParticleChannelNewRInterface(pCont); if(chNew == NULL) return false; IParticleChannelPTVR* chTime = GetParticleChannelTimeRInterface(pCont); if(chTime == NULL) return false; IParticleChannelAmountR* chAmount = GetParticleChannelAmountRInterface(pCont); if(chAmount == NULL) return false; // the position channel may not be present. For some option configurations it is okay IParticleChannelPoint3R* chPos = GetParticleChannelPositionRInterface(pCont); int iDir = _pblock()->GetInt(kSimpleSpeed_direction, timeStart); if ((chPos == NULL) && ((iDir == kSS_Icon_Center_Out) || (iDir == kSS_Icon_Arrow_Out))) return false; IChannelContainer* chCont; chCont = GetChannelContainerInterface(pCont); if (chCont == NULL) return false; // the channel of interest bool initSpeed = false; IParticleChannelPoint3W* chSpeed = (IParticleChannelPoint3W*)chCont->EnsureInterface(PARTICLECHANNELSPEEDW_INTERFACE, ParticleChannelPoint3_Class_ID, true, PARTICLECHANNELSPEEDR_INTERFACE, PARTICLECHANNELSPEEDW_INTERFACE, true, actionNode, (Object*)NULL, &initSpeed); IParticleChannelPoint3R* chSpeedR = GetParticleChannelSpeedRInterface(pCont); if ((chSpeed == NULL) || (chSpeedR == NULL)) return false; // there are no new particles if (chNew->IsAllOld()) return true; float fUPFScale = 1.0f/TIME_TICKSPERSEC; // conversion units per seconds to units per tick Point3 pt3SpeedVec; RandGenerator* prg = randLinker().GetRandGenerator(pCont); int iQuant = chAmount->Count(); bool wasIgnoringEmitterTMChange = IsIgnoringEmitterTMChange(); if (!wasIgnoringEmitterTMChange) SetIgnoreEmitterTMChange(); for(int i = 0; i < iQuant; i++) { if(chNew->IsNew(i)) { // apply only to new particles TimeValue tv = chTime->GetValue(i).TimeValue(); Matrix3 nodeTM = pNode->GetObjectTM(tv); float fSpeedParam = fUPFScale * GetPFFloat(pblock(), kSimpleSpeed_speed, tv); // change speed in user selected direction switch(iDir) { case kSS_Along_Icon_Arrow: { // icon arrow appears to be in the negative z direction pt3SpeedVec = -Normalize(nodeTM.GetRow(2)); } break; case kSS_Icon_Center_Out: { Point3 pt3IconCenter = nodeTM.GetTrans(); Point3 pt3PartPos = chPos->GetValue(i); pt3SpeedVec = Normalize(pt3PartPos - pt3IconCenter); } break; case kSS_Icon_Arrow_Out: { Point3 pt3PartPos = chPos->GetValue(i); Point3 pt3ArrowVec = nodeTM.GetRow(2); Point3 pt3Tmp = CrossProd(pt3PartPos - nodeTM.GetTrans(), pt3ArrowVec); pt3SpeedVec = Normalize(CrossProd(pt3ArrowVec, pt3Tmp)); } break; case kSS_Rand_3D: { pt3SpeedVec = RandSphereSurface(prg); } break; case kSS_Rand_Horiz: { float fAng = TWOPI * prg->Rand01(); // establish x, y coordinates of random angle, z component zero float x = cos(fAng); float y = sin(fAng); float z = 0.0f; pt3SpeedVec = Point3(x, y, z); } break; case kSS_Inherit_Prev: { if (initSpeed) pt3SpeedVec = Point3::Origin; else pt3SpeedVec = Normalize(chSpeedR->GetValue(i)); } break; } // account for reverse check box int iRev = _pblock()->GetInt(kSimpleSpeed_reverse, 0); float fDirMult = iRev > 0 ? -1.f : 1.f; // calculate variation float fVar = fUPFScale * GetPFFloat(pblock(), kSimpleSpeed_variation, tv); if(fVar > 0.f) fSpeedParam = fSpeedParam + fVar * prg->Rand11(); pt3SpeedVec = fDirMult * fSpeedParam * pt3SpeedVec; // calculate divergence float fDiv = GetPFFloat(pblock(), kSimpleSpeed_divergence, tv); pt3SpeedVec = DivergeVectorRandom(pt3SpeedVec, prg, fDiv); chSpeed->SetValue(i, pt3SpeedVec); } } if (!wasIgnoringEmitterTMChange) ClearIgnoreEmitterTMChange(); return true; }
bool PFOperatorForceSpaceWarp::Proceed(IObject* pCont, PreciseTimeValue timeStart, PreciseTimeValue& timeEnd, Object* pSystem, INode* pNode, INode* actionNode, IPFIntegrator* integrator) { // acquire all necessary channels, create additional if needed IChannelContainer* chCont; chCont = GetChannelContainerInterface(pCont); if (chCont == NULL) return false; IParticleChannelAmountR* chAmount = GetParticleChannelAmountRInterface(pCont); if(chAmount == NULL) return false; int iQuant = chAmount->Count(); if (iQuant < 1) return true; // no particles to proceed IParticleChannelNewR* chNew = GetParticleChannelNewRInterface(pCont); if (chNew == NULL) return false; IParticleChannelIDR* chID = GetParticleChannelIDRInterface(pCont); if (chID == NULL) return false; IParticleChannelPTVR* chTime = GetParticleChannelTimeRInterface(pCont); if(chTime == NULL) return false; IParticleChannelPTVR* chAge = GetParticleChannelBirthTimeRInterface(pCont); if(chAge == NULL) return false; // the channel of interest speed bool initSpeed = false; //channel does not exist so make it and note that we have to fill it out IParticleChannelPoint3W* chSpeedW = (IParticleChannelPoint3W*)chCont->EnsureInterface(PARTICLECHANNELSPEEDW_INTERFACE, ParticleChannelPoint3_Class_ID, true, PARTICLECHANNELSPEEDR_INTERFACE, PARTICLECHANNELSPEEDW_INTERFACE, true, actionNode, NULL, &initSpeed); IParticleChannelPoint3R* chSpeed = GetParticleChannelSpeedRInterface(pCont); if ((chSpeedW == NULL) || (chSpeed == NULL)) return false; bool initPosition = false; IParticleChannelPoint3W* chPosW = (IParticleChannelPoint3W*)chCont->EnsureInterface(PARTICLECHANNELPOSITIONW_INTERFACE, ParticleChannelPoint3_Class_ID, true, PARTICLECHANNELPOSITIONR_INTERFACE, PARTICLECHANNELPOSITIONW_INTERFACE, true, actionNode, NULL, &initPosition); IParticleChannelPoint3R* chPos = GetParticleChannelPositionRInterface(pCont); if ((chPosW == NULL) || (chPos == NULL)) return false; bool useScript = ((scriptPBlock()->GetInt(kForceSpaceWarp_useScriptWiring, 0) != 0) && (scriptPBlock()->GetInt(kForceSpaceWarp_useFloat, 0) == kForceSpaceWarp_useFloat_influence)); IParticleChannelFloatR* chFloat = NULL; if (useScript) { chFloat = GetParticleChannelMXSFloatRInterface(pCont); if (chFloat == NULL) return false; } int timeType = kAbsoluteTime; _pblock()->GetValue(kForceSpaceWarp_Sync,0, timeType, FOREVER); IParticleChannelPTVR* chEventStart = NULL; IParticleChannelPTVW* chEventStartW = NULL; bool initEventStart = false; if (timeType == kEventDuration) { chEventStartW = (IParticleChannelPTVW*) chCont->EnsureInterface(PARTICLECHANNELEVENTSTARTW_INTERFACE, ParticleChannelPTV_Class_ID, true, PARTICLECHANNELEVENTSTARTR_INTERFACE, PARTICLECHANNELEVENTSTARTW_INTERFACE, false, actionNode, NULL, &initEventStart); chEventStart = GetParticleChannelEventStartRInterface(pCont); if ((chEventStart == NULL) || (chEventStartW == NULL)) return false; } int overlapping = pblock()->GetInt(kForceSpaceWarp_Overlapping, 0); // collecting force fields Tab<ForceField*> ff; ForceField* curFF; int i, j; for(i=0; i<pblock()->Count(kForceSpaceWarp_ForceNodeList); i++) { INode* node = pblock()->GetINode(kForceSpaceWarp_ForceNodeList, 0, i); if (node == NULL) continue; Object* ob = GetPFObject(node->GetObjectRef()); if (ob == NULL) continue; if (ob->SuperClassID() == WSM_OBJECT_CLASS_ID) { WSMObject* obref = (WSMObject*)ob; curFF = obref->GetForceField(node); if (curFF != NULL) { if (ob->ClassID() == CS_VFIELDOBJECT_CLASS_ID) { // CS VectorField SW doesn't init properly partobj on GetForceField // this is a quick fix for that (bayboro 3/6/2003) CS_VectorField* vf = (CS_VectorField*)curFF; vf->partobj = GetParticleInterface(pSystem); } ff.Append(1, &curFF); } } } if (ff.Count() == 0) return true; // no force fields // some calls for a reference node TM may initiate REFMSG_CHANGE notification // we have to ignore that while processing the particles bool wasIgnoring = IsIgnoringRefNodeChange(); if (!wasIgnoring) SetIgnoreRefNodeChange(); float influence = 0.0f; for(i = 0; i < iQuant; i++) { TimeValue t = 0; if (timeType == kAbsoluteTime) t = chTime->GetValue(i).TimeValue(); else if (timeType == kParticleAge) t = chTime->GetValue(i).TimeValue() - chAge->GetValue(i).TimeValue(); else { if (initEventStart && chNew->IsNew(i)) chEventStartW->SetValue(i, chTime->GetValue(i)); t = chTime->GetValue(i).TimeValue() - chEventStart->GetValue(i).TimeValue(); } if (useScript) { influence = chFloat->GetValue(i); } else { influence = GetPFFloat(pblock(), kForceSpaceWarp_Influence, t); } Point3 v(0.0f,0.0f,0.0f); if (!initSpeed || !chNew->IsNew(i)) //if we created a speed channel the channel incoming is bogus so just use 0,0,0 ad default v = chSpeed->GetValue(i); Point3 p(0.0f,0.0f,0.0f); if (!initPosition || !chNew->IsNew(i)) //if we created a pos channel the channel incoming is bogus so just use 0,0,0 ad default p = chPos->GetValue(i); Point3 force = Point3::Origin; for(j=0; j<ff.Count(); j++) { // buffer vectors to guard true position and speed from malicious force Point3 pp = p; Point3 vv = v; Point3 nextForce = ff[j]->Force(t,pp,vv,chID->GetParticleBorn(i)) * influence; float lenSq = LengthSquared(nextForce); if (lenSq <= 0.0f) continue; // not a valid force if (overlapping == kForceSpaceWarp_Overlapping_additive) { force += nextForce; } else { if (lenSq > LengthSquared(force)) force = nextForce; } // p = pp; // v = vv; } v += force * float(timeEnd - chTime->GetValue(i)); chPosW->SetValue(i, p); chSpeedW->SetValue(i, v); } for(i=0; i<ff.Count(); i++) if (ff[i] != NULL) ff[i]->DeleteThis(); if (!wasIgnoring) ClearIgnoreRefNodeChange(); return true; }
//+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+ //| From IPFTest | //+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+ bool PFTestScale::Proceed(IObject* pCont, PreciseTimeValue timeStart, PreciseTimeValue& timeEnd, Object* pSystem, INode* pNode, INode* actionNode, IPFIntegrator* integrator, BitArray& testResult, Tab<float>& testTime) { bool exactStep = IsExactIntegrationStep(timeEnd, pSystem); // get the constant properties of the test int testType = pblock()->GetInt(kScaleTest_testType, timeEnd); int axisType = pblock()->GetInt(kScaleTest_axisType, timeEnd); int condType = pblock()->GetInt(kScaleTest_conditionType, timeEnd); int syncType = pblock()->GetInt(kScaleTest_sync, timeEnd); ParamID varParamID = (testType == kScaleTest_testType_scale) ? kScaleTest_scaleVariation : kScaleTest_sizeVariation; bool hasTestVariation = (pblock()->GetFloat(varParamID, 0) != 0.0f); if (!hasTestVariation) { Control* ctrl = pblock()->GetControllerByID(varParamID); if (ctrl != NULL) hasTestVariation = (ctrl->IsAnimated() != 0); } // get channel container interface IChannelContainer* chCont; chCont = GetChannelContainerInterface(pCont); if (chCont == NULL) return false; // acquire absolutely necessary particle channels IParticleChannelAmountR* chAmount = GetParticleChannelAmountRInterface(pCont); if (chAmount == NULL) return false; // can't find number of particles in the container int count = chAmount->Count(); if (count == 0) return true; // no particles to test IParticleChannelPTVR* chTime = GetParticleChannelTimeRInterface(pCont); if (chTime == NULL) return false; // can't read timing info for a particle IParticleChannelNewR* chNew = GetParticleChannelNewRInterface(pCont); if (chNew == NULL) return false; // can't find newly entered particles for duration calculation // acquire more particle channels IParticleChannelPTVR* chBirthTime = NULL; if (syncType == kScaleTest_sync_age) { chBirthTime = GetParticleChannelBirthTimeRInterface(pCont); if (chBirthTime == NULL) return false; // can't read particle age } IParticleChannelPTVR* chEventStartR = NULL; IParticleChannelPTVW* chEventStartW = NULL; bool initEventStart = false; if (syncType == kScaleTest_sync_event) { chEventStartR = (IParticleChannelPTVR*)chCont->EnsureInterface(PARTICLECHANNELEVENTSTARTR_INTERFACE, ParticleChannelPTV_Class_ID, true, PARTICLECHANNELEVENTSTARTR_INTERFACE, PARTICLECHANNELEVENTSTARTW_INTERFACE, false, actionNode, NULL, &initEventStart); if (chEventStartR == NULL) return false; // can't read event start time if (initEventStart) { chEventStartW = GetParticleChannelEventStartWInterface(pCont); if (chEventStartW == NULL) return false; // can't write event start time } } IParticleChannelMeshR* chShape = NULL; if (testType != kScaleTest_testType_scale) { chShape = GetParticleChannelShapeRInterface(pCont); if (chShape == NULL) return false; // can't read particle shape to find bounding box } IParticleChannelPoint3R* chScale = NULL; if (testType != kScaleTest_testType_preSize) { chScale = GetParticleChannelScaleRInterface(pCont); if (chScale == NULL) return false; // can't read particle scale } IParticleChannelFloatR* chRandFloatR = NULL; IParticleChannelFloatW* chRandFloatW = NULL; bool initRandFloat = false; if (hasTestVariation) { chRandFloatW = (IParticleChannelFloatW*)chCont->EnsureInterface(PARTICLECHANNELRANDFLOATW_INTERFACE, ParticleChannelFloat_Class_ID, true, PARTICLECHANNELRANDFLOATR_INTERFACE, PARTICLECHANNELRANDFLOATW_INTERFACE, true, actionNode, (Object*)this, &initRandFloat); chRandFloatR = (IParticleChannelFloatR*)chCont->GetPrivateInterface(PARTICLECHANNELRANDFLOATR_INTERFACE, (Object*)this); if ((chRandFloatR == NULL) || (chRandFloatW == NULL)) return false; // can't set rand float value for newly entered particles } // grab the rand generator for test variation RandGenerator* randGen = randLinker().GetRandGenerator(pCont); if (randGen == NULL) return false; // check all particles testResult.SetSize(count); testResult.ClearAll(); testTime.SetCount(count); for(int i=0; i<count; i++) { if (chNew->IsNew(i)) { // initialize some channels if (initEventStart) chEventStartW->SetValue(i, chTime->GetValue(i)); if (initRandFloat) chRandFloatW->SetValue(i, randGen->Rand11()); } PreciseTimeValue syncTime = chTime->GetValue(i); switch(syncType) { case kScaleTest_sync_age: syncTime -= chBirthTime->GetValue(i); break; case kScaleTest_sync_event: syncTime -= chEventStartR->GetValue(i); break; } TimeValue syncTimeTV = TimeValue(syncTime); float testValue = 0.0f; if (testType == kScaleTest_testType_scale) { testValue = GetPFFloat(pblock(), kScaleTest_scaleValue, syncTimeTV); if (hasTestVariation) testValue += chRandFloatR->GetValue(i)*GetPFFloat(pblock(), kScaleTest_scaleVariation, syncTimeTV); } else { testValue = GetPFFloat(pblock(), kScaleTest_sizeValue, syncTimeTV); if (hasTestVariation) testValue += chRandFloatR->GetValue(i)*GetPFFloat(pblock(), kScaleTest_sizeVariation, syncTimeTV); } Point3 cur3DValue; if (testType == kScaleTest_testType_scale) { cur3DValue = chScale->GetValue(i); } else { Mesh* curMesh = const_cast <Mesh*>(chShape->GetValue(i)); if (curMesh == NULL) continue; Box3 curBox = curMesh->getBoundingBox(); cur3DValue = curBox.pmax - curBox.pmin; if (testType == kScaleTest_testType_postSize) cur3DValue *= chScale->GetValue(i); } float currentValue = 0.0f; switch(axisType) { case kScaleTest_axisType_average: currentValue = (cur3DValue.x + cur3DValue.y + cur3DValue.z)/3.0f; break; case kScaleTest_axisType_minimum: currentValue = min(cur3DValue.x, min(cur3DValue.y, cur3DValue.z)); break; case kScaleTest_axisType_median: currentValue = max(min(cur3DValue.x, cur3DValue.y), max(min(cur3DValue.x, cur3DValue.z), min(cur3DValue.y, cur3DValue.z))); break; case kScaleTest_axisType_maximum: currentValue = max(cur3DValue.x, max(cur3DValue.y, cur3DValue.z)); break; case kScaleTest_axisType_x: currentValue = cur3DValue.x; break; case kScaleTest_axisType_y: currentValue = cur3DValue.y; break; case kScaleTest_axisType_z: currentValue = cur3DValue.z; break; } bool testSatisfied = (condType == kScaleTest_conditionType_less) ? (currentValue < testValue) : (currentValue > testValue); if (testSatisfied && exactStep) { testResult.Set(i); testTime[i] = 0.0f; } } return true; }
//+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+ //| From IPFTest | //+>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>+ bool PFTestSpeed::Proceed(IObject* pCont, PreciseTimeValue timeStart, PreciseTimeValue& timeEnd, Object* pSystem, INode* pNode, INode* actionNode, IPFIntegrator* integrator, BitArray& testResult, Tab<float>& testTime) { bool exactStep = IsExactIntegrationStep(timeEnd, pSystem); // get the constant properties of the test int testType = pblock()->GetInt(kSpeedTest_testType, timeEnd); int condType = pblock()->GetInt(kSpeedTest_conditionType, timeEnd); int syncType = pblock()->GetInt(kSpeedTest_sync, timeEnd); ParamID varParamID = (testType == kSpeedTest_testType_steering) ? kSpeedTest_angleVariation : kSpeedTest_unitVariation; bool hasTestVariation = (pblock()->GetFloat(varParamID, 0) != 0.0f); if (!hasTestVariation) { Control* ctrl = pblock()->GetControllerByID(varParamID); if (ctrl != NULL) hasTestVariation = (ctrl->IsAnimated() != 0); } if (testType >= kSpeedTest_testType_whenAccels) { hasTestVariation = false; syncType = kSpeedTest_sync_time; } bool needPrevValue = (testType >= kSpeedTest_testType_accel); // get channel container interface IChannelContainer* chCont; chCont = GetChannelContainerInterface(pCont); if (chCont == NULL) return false; // acquire absolutely necessary particle channels IParticleChannelAmountR* chAmount = GetParticleChannelAmountRInterface(pCont); if (chAmount == NULL) return false; // can't find number of particles in the container int count = chAmount->Count(); if (count == 0) return true; // no particles to test IParticleChannelPTVR* chTime = GetParticleChannelTimeRInterface(pCont); if (chTime == NULL) return false; // can't read timing info for a particle IParticleChannelNewR* chNew = GetParticleChannelNewRInterface(pCont); if (chNew == NULL) return false; // can't find newly entered particles for duration calculation IParticleChannelPoint3R* chSpeed = GetParticleChannelSpeedRInterface(pCont); if (chSpeed == NULL) return false; // can't read speed values // acquire more particle channels IParticleChannelPTVR* chBirthTime = NULL; if (syncType == kSpeedTest_sync_age && (testType < kSpeedTest_testType_whenAccels)) { chBirthTime = GetParticleChannelBirthTimeRInterface(pCont); if (chBirthTime == NULL) return false; // can't read particle age } IParticleChannelPTVR* chEventStartR = NULL; IParticleChannelPTVW* chEventStartW = NULL; bool initEventStart = false; if (syncType == kSpeedTest_sync_event && (testType < kSpeedTest_testType_whenAccels)) { chEventStartR = (IParticleChannelPTVR*)chCont->EnsureInterface(PARTICLECHANNELEVENTSTARTR_INTERFACE, ParticleChannelPTV_Class_ID, true, PARTICLECHANNELEVENTSTARTR_INTERFACE, PARTICLECHANNELEVENTSTARTW_INTERFACE, false, actionNode, NULL, &initEventStart); if (chEventStartR == NULL) return false; // can't read event start time if (initEventStart) { chEventStartW = GetParticleChannelEventStartWInterface(pCont); if (chEventStartW == NULL) return false; // can't write event start time } } IParticleChannelFloatR* chRandFloatR = NULL; IParticleChannelFloatW* chRandFloatW = NULL; bool initRandFloat = false; if (hasTestVariation) { chRandFloatW = (IParticleChannelFloatW*)chCont->EnsureInterface(PARTICLECHANNELRANDFLOATW_INTERFACE, ParticleChannelFloat_Class_ID, true, PARTICLECHANNELRANDFLOATR_INTERFACE, PARTICLECHANNELRANDFLOATW_INTERFACE, true, actionNode, (Object*)this, &initRandFloat); chRandFloatR = (IParticleChannelFloatR*)chCont->GetPrivateInterface(PARTICLECHANNELRANDFLOATR_INTERFACE, (Object*)this); if ((chRandFloatR == NULL) || (chRandFloatW == NULL)) return false; // can't set rand float value for newly entered particles } IParticleChannelPoint3R* chPrevSpeedR = NULL; IParticleChannelPoint3W* chPrevSpeedW = NULL; IParticleChannelPTVR* chPrevTimeR = NULL; IParticleChannelPTVW* chPrevTimeW = NULL; bool initPrevValue = false; if (needPrevValue) { chPrevSpeedW = (IParticleChannelPoint3W*)chCont->EnsureInterface(PARTICLECHANNELPREVSPEEDW_INTERFACE, ParticleChannelPoint3_Class_ID, true, PARTICLECHANNELPREVSPEEDR_INTERFACE, PARTICLECHANNELPREVSPEEDW_INTERFACE, true, actionNode, (Object*)this, &initPrevValue); chPrevSpeedR = (IParticleChannelPoint3R*)chCont->GetPrivateInterface(PARTICLECHANNELPREVSPEEDR_INTERFACE, (Object*)this); chPrevTimeW = (IParticleChannelPTVW*)chCont->EnsureInterface(PARTICLECHANNELPREVTIMEW_INTERFACE, ParticleChannelPTV_Class_ID, true, PARTICLECHANNELPREVTIMER_INTERFACE, PARTICLECHANNELPREVTIMEW_INTERFACE, true, actionNode, (Object*)this, &initPrevValue); chPrevTimeR = (IParticleChannelPTVR*)chCont->GetPrivateInterface(PARTICLECHANNELPREVTIMER_INTERFACE, (Object*)this); if ((chPrevSpeedR == NULL) || (chPrevSpeedW == NULL) || (chPrevTimeR == NULL) || (chPrevTimeW == NULL)) return false; } // grab the rand generator for test variation RandGenerator* randGen = randLinker().GetRandGenerator(pCont); if (randGen == NULL) return false; // check all particles testResult.SetSize(count); testResult.ClearAll(); testTime.SetCount(count); for(int i=0; i<count; i++) { if (chNew->IsNew(i)) { // initialize some channels if (initEventStart) chEventStartW->SetValue(i, chTime->GetValue(i)); if (initRandFloat) chRandFloatW->SetValue(i, randGen->Rand11()); } PreciseTimeValue prevTime; Point3 prevSpeed; Point3 currentSpeed = chSpeed->GetValue(i); PreciseTimeValue currentTime = chTime->GetValue(i); if (needPrevValue) { prevTime = chPrevTimeR->GetValue(i); prevSpeed = chPrevSpeedR->GetValue(i); chPrevTimeW->SetValue(i, currentTime); chPrevSpeedW->SetValue(i, currentSpeed); if (initPrevValue && chNew->IsNew(i)) continue; // particle just came into the event and doesn't have previous value } PreciseTimeValue syncTime = currentTime; switch(syncType) { case kSpeedTest_sync_age: syncTime -= chBirthTime->GetValue(i); break; case kSpeedTest_sync_event: syncTime -= chEventStartR->GetValue(i); break; } TimeValue syncTimeTV = TimeValue(syncTime); float testValue = 0.0f; if (testType < kSpeedTest_testType_whenAccels) { if (testType == kSpeedTest_testType_steering) { testValue = GetPFFloat(pblock(), kSpeedTest_angleValue, syncTimeTV); if (hasTestVariation) testValue += chRandFloatR->GetValue(i)*GetPFFloat(pblock(), kSpeedTest_angleVariation, syncTimeTV); } else { testValue = GetPFFloat(pblock(), kSpeedTest_unitValue, syncTimeTV); if (hasTestVariation) testValue += chRandFloatR->GetValue(i)*GetPFFloat(pblock(), kSpeedTest_unitVariation, syncTimeTV); } testValue /= TIME_TICKSPERSEC; } float currentValue = 0.0f; bool testSatisfied = false; if (testType < kSpeedTest_testType_whenAccels) { if (testType < kSpeedTest_testType_accel) { switch(testType) { case kSpeedTest_testType_speed: currentValue = Length(currentSpeed); break; case kSpeedTest_testType_speedX: currentValue = currentSpeed.x; break; case kSpeedTest_testType_speedY: currentValue = currentSpeed.y; break; case kSpeedTest_testType_speedZ: currentValue = currentSpeed.z; break; } } else if (testType == kSpeedTest_testType_steering) { float timeDif = float(currentTime - prevTime); if (timeDif <= 0.0f) continue; // no time difference float normFactor = Length(currentSpeed)*Length(prevSpeed); if (normFactor <= 0.0f) continue; // steering rate is not calculatable float vv = DotProd(currentSpeed,prevSpeed)/normFactor; float uu = 0.0; if (vv >= 1.0f) uu = 0.0; else if (vv <= -1.0f) uu = PI; else uu = acos(vv); currentValue = uu/timeDif; } else { // acceleration float timeDif = float(currentTime - prevTime); if (timeDif <= 0.0f) continue; // no time difference Point3 curAccel; switch(testType) { case kSpeedTest_testType_accel: currentValue = Length((currentSpeed - prevSpeed)/timeDif); break; case kSpeedTest_testType_accelX: currentValue = (currentSpeed.x - prevSpeed.x)/timeDif; break; case kSpeedTest_testType_accelY: currentValue = (currentSpeed.y - prevSpeed.y)/timeDif; break; case kSpeedTest_testType_accelZ: currentValue = (currentSpeed.z - prevSpeed.z)/timeDif; break; } testValue /= TIME_TICKSPERSEC; // acceleration is per second squared } testSatisfied = (condType == kSpeedTest_conditionType_less) ? (currentValue < testValue) : (currentValue > testValue); } else { if (testType == kSpeedTest_testType_whenAccels) { testSatisfied = (Length(currentSpeed) > Length(prevSpeed)); } else { testSatisfied = (Length(currentSpeed) < Length(prevSpeed)); } } if (testSatisfied && exactStep) { testResult.Set(i); testTime[i] = 0.0f; } } return true; }
bool PFOperatorSimpleOrientation::Proceed(IObject* pCont, PreciseTimeValue timeStart, PreciseTimeValue& timeEnd, Object* pSystem, INode* pNode, INode* actionNode, IPFIntegrator* integrator) { // acquire all necessary channels, create additional if needed IParticleChannelNewR* chNew = GetParticleChannelNewRInterface(pCont); if(chNew == NULL) return false; IParticleChannelPTVR* chTime = GetParticleChannelTimeRInterface(pCont); if(chTime == NULL) return false; IParticleChannelAmountR* chAmount = GetParticleChannelAmountRInterface(pCont); if(chAmount == NULL) return false; // there are no new particles // if (chNew->IsAllOld()) return true; // we may need speed channel for "Speed Space" and "Speed Space Follow" types IParticleChannelPoint3R* chSpeed; int iDir = pblock()->GetInt(kSimpleOrientation_direction, 0); if ((iDir == kSO_Speed) || (iDir == kSO_SpeedFollow)) chSpeed = GetParticleChannelSpeedRInterface(pCont); bool bRestrictToAxis = (pblock()->GetInt(kSimpleOrientation_restrictToAxis, 0) != 0); IChannelContainer* chCont; chCont = GetChannelContainerInterface(pCont); if (chCont == NULL) return false; // the channel of interest IParticleChannelQuatW* chOrient = (IParticleChannelQuatW*)chCont->EnsureInterface(PARTICLECHANNELORIENTATIONW_INTERFACE, ParticleChannelQuat_Class_ID, true, PARTICLECHANNELORIENTATIONR_INTERFACE, PARTICLECHANNELORIENTATIONW_INTERFACE, true ); if (chOrient == NULL) return false; RandGenerator* prg = randLinker().GetRandGenerator(pCont); Matrix3 m3Orient; float fEulerAng[3]; int iQuant = chAmount->Count(); for(int i = 0; i < iQuant; i++) { if((chNew->IsNew(i)) || (iDir == kSO_SpeedFollow)) { // apply only to new particles or to all for "follow" type TimeValue tv = chTime->GetValue(i).TimeValue(); // set particle direction in user selected direction switch(iDir) { case kSO_Rand_3D: { Point3 p3x = RandSphereSurface(prg); Point3 p3y = RandSphereSurface(prg); while(p3x == p3y) p3y = RandSphereSurface(prg); p3y = Normalize(p3y - p3x * DotProd(p3x, p3y)); Point3 p3z = p3x ^ p3y; m3Orient = Matrix3(p3x, p3y, p3z, Point3::Origin); } break; case kSO_Rand_Horiz: { fEulerAng[0] = fEulerAng[1] = 0.0f; fEulerAng[2] = TWOPI * prg->Rand01(); EulerToMatrix(fEulerAng, m3Orient, EULERTYPE_XYZ); } break; case kSO_World: { fEulerAng[0] = GetPFFloat(pblock(), kSimpleOrientation_x, tv); fEulerAng[1] = GetPFFloat(pblock(), kSimpleOrientation_y, tv); fEulerAng[2] = GetPFFloat(pblock(), kSimpleOrientation_z, tv); EulerToMatrix(fEulerAng, m3Orient, EULERTYPE_XYZ); } break; case kSO_Speed: case kSO_SpeedFollow: { fEulerAng[0] = GetPFFloat(pblock(), kSimpleOrientation_x, tv); fEulerAng[1] = GetPFFloat(pblock(), kSimpleOrientation_y, tv); fEulerAng[2] = GetPFFloat(pblock(), kSimpleOrientation_z, tv); if (chSpeed != NULL) m3Orient = SpeedSpaceMatrix(chSpeed->GetValue(i)); else m3Orient = Matrix3(Point3::XAxis, Point3::YAxis, Point3::ZAxis, Point3::Origin); // m3Orient.SetRotate(Quat(m3Orient)); Matrix3 eulerRot; EulerToMatrix(fEulerAng, eulerRot, EULERTYPE_XYZ); // m3Orient = m3Orient * eulerRot; m3Orient = eulerRot * m3Orient; } break; } // account for divergence parameter if ((iDir != kSO_SpeedFollow) && (iDir != kSO_Rand_3D)) { float fDiv = GetPFFloat(pblock(), kSimpleOrientation_divergence, tv); Point3 p3RotAxis = RandSphereSurface(prg); if(fDiv > 0.f) { if (bRestrictToAxis) { p3RotAxis.x = GetPFFloat(pblock(), kSimpleOrientation_axisX, tv); p3RotAxis.y = GetPFFloat(pblock(), kSimpleOrientation_axisY, tv); p3RotAxis.z = GetPFFloat(pblock(), kSimpleOrientation_axisZ, tv); if (LengthSquared(p3RotAxis) > 0.0f) { p3RotAxis = Normalize(p3RotAxis); } else { p3RotAxis = Point3::XAxis; fDiv = 0.0f; } } float fRandDiv = fDiv * prg->Rand11(); m3Orient = m3Orient * RotAngleAxisMatrix(p3RotAxis, fRandDiv); } else { // perform operations that change randomness state prg->Rand11(); } } chOrient->SetValue(i, Quat(m3Orient)); } } return true; }