1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
#include "UnityPrefix.h"
#include "ExternalForcesModule.h"
#include "Runtime/BaseClasses/ObjectDefines.h"
#include "Runtime/Serialize/TransferFunctions/SerializeTransfer.h"
#include "../ParticleSystemUtils.h"
#include "Runtime/Graphics/Transform.h"
#include "Runtime/Geometry/Intersection.h"
#include "Runtime/Geometry/Sphere.h"
#include "Runtime/Terrain/Wind.h"
#include "Runtime/Input/TimeManager.h"
void ApplyRadialForce(ParticleSystemParticles& ps, const size_t fromIndex, const size_t toIndex, const Vector3f position, const float radius, const float force, const float dt)
{
for(int q = fromIndex; q < toIndex; q++)
{
Vector3f toForce = position - ps.position[q];
float distanceToForce = Magnitude(toForce);
toForce = NormalizeSafe(toForce);
float forceFactor = clamp(distanceToForce/radius, 0.0f, 1.0f);
forceFactor = 1.0f - forceFactor * forceFactor;
Vector3f delta = toForce * force * forceFactor * dt;
ps.velocity[q] += delta;
}
}
void ApplyDirectionalForce(ParticleSystemParticles& ps, const size_t fromIndex, const size_t toIndex, const Vector3f position, const Vector3f direction, const float radius, const float force, const float dt)
{
for(int q = fromIndex; q < toIndex; q++)
{
Vector3f delta = direction * force * dt;
ps.velocity[q] += delta;
}
}
ExternalForcesModule::ExternalForcesModule () : ParticleSystemModule(false)
, m_Multiplier (1.0f)
{
}
void ExternalForcesModule::Update (const ParticleSystemReadOnlyState& roState, const ParticleSystemState& state, ParticleSystemParticles& ps, const size_t fromIndex, const size_t toIndex, float dt)
{
Matrix4x4f matrix = Matrix4x4f::identity;
if(roState.useLocalSpace)
Matrix4x4f::Invert_General3D(state.localToWorld, matrix);
AABB aabb = state.minMaxAABB;
for(int i = 0; i < state.numCachedForces; i++)
{
const ParticleSystemExternalCachedForce& cachedForce = state.cachedForces[i];
const Vector3f position = matrix.MultiplyPoint3(cachedForce.position);
const Vector3f direction = matrix.MultiplyVector3(cachedForce.direction);
const float radius = cachedForce.radius;
const float force = cachedForce.forceMain * m_Multiplier;
const WindZone::WindZoneMode forceType = (WindZone::WindZoneMode)cachedForce.forceType;
if(WindZone::Spherical == forceType)
{
Sphere sphere (position, radius);
if(!IntersectAABBSphere (aabb, sphere))
continue;
ApplyRadialForce(ps, fromIndex, toIndex, position, radius, force, dt);
}
else if(WindZone::Directional == forceType)
ApplyDirectionalForce(ps, fromIndex, toIndex, position, direction, radius, force, dt);
}
}
// TODO: Perform culling here, instead of caching all of them
void ExternalForcesModule::AllocateAndCache(const ParticleSystemReadOnlyState& roState, ParticleSystemState& state)
{
float time = GetTimeManager ().GetTimeSinceLevelLoad ();
WindManager::WindZoneList& windZones = WindManager::GetInstance().GetList();
state.numCachedForces = 0;
for (WindManager::WindZoneList::iterator it = windZones.begin (); it != windZones.end (); ++it)
state.numCachedForces++;
// Allocate
state.cachedForces = ALLOC_TEMP_MANUAL(ParticleSystemExternalCachedForce, state.numCachedForces);
// Cache
int i = 0;
for (WindManager::WindZoneList::iterator it = windZones.begin (); it != windZones.end (); ++it)
{
const WindZone& zone = **it;
ParticleSystemExternalCachedForce& cachedForce = state.cachedForces[i++];
cachedForce.position = zone.GetComponent (Transform).GetPosition();
cachedForce.direction = zone.GetComponent (Transform).GetLocalToWorldMatrix().GetAxisZ();
cachedForce.forceType = zone.GetMode();
cachedForce.radius = zone.GetRadius();
float phase = time * kPI * zone.GetWindPulseFrequency();
float pulse = (cos (phase) + cos (phase * 0.375f) + cos (phase * 0.05f)) * 0.333f;
pulse = 1.0f + (pulse * zone.GetWindPulseMagnitude());
cachedForce.forceMain = zone.GetWindMain() * pulse;
// Maybe implement using turbulence and time based phasing?
// ForceTurbulenceMultiply (maybe) // @TODO: Figure out what to do about turbulence. Do perlin field? Expensive but maybe cool! If use it: only do it when turbulence force is set to something
//cachedForce.force = 1.0f;
}
}
void ExternalForcesModule::FreeCache(ParticleSystemState& state)
{
if(state.cachedForces)
FREE_TEMP_MANUAL(state.cachedForces);
state.cachedForces = NULL;
state.numCachedForces = 0;
}
template<class TransferFunction>
void ExternalForcesModule::Transfer (TransferFunction& transfer)
{
ParticleSystemModule::Transfer (transfer);
transfer.Transfer (m_Multiplier, "multiplier");
}
INSTANTIATE_TEMPLATE_TRANSFER(ExternalForcesModule)
|