summaryrefslogtreecommitdiff
path: root/Runtime/Filters/Particles/MeshParticleEmitter.cpp
diff options
context:
space:
mode:
authorchai <chaifix@163.com>2019-08-14 22:50:43 +0800
committerchai <chaifix@163.com>2019-08-14 22:50:43 +0800
commit15740faf9fe9fe4be08965098bbf2947e096aeeb (patch)
treea730ec236656cc8cab5b13f088adfaed6bb218fb /Runtime/Filters/Particles/MeshParticleEmitter.cpp
+Unity Runtime codeHEADmaster
Diffstat (limited to 'Runtime/Filters/Particles/MeshParticleEmitter.cpp')
-rw-r--r--Runtime/Filters/Particles/MeshParticleEmitter.cpp353
1 files changed, 353 insertions, 0 deletions
diff --git a/Runtime/Filters/Particles/MeshParticleEmitter.cpp b/Runtime/Filters/Particles/MeshParticleEmitter.cpp
new file mode 100644
index 0000000..16ea50c
--- /dev/null
+++ b/Runtime/Filters/Particles/MeshParticleEmitter.cpp
@@ -0,0 +1,353 @@
+#include "UnityPrefix.h"
+#include "MeshParticleEmitter.h"
+#include "Runtime/Input/TimeManager.h"
+#include "Runtime/Graphics/Transform.h"
+#include "Runtime/Math/Random/Random.h"
+#include "Runtime/Serialize/TransferFunctions/SerializeTransfer.h"
+#include "Runtime/Filters/Mesh/MeshUtility.h"
+#include "Runtime/Core/Callbacks/GlobalCallbacks.h"
+
+using namespace std;
+
+static Rand gMeshEmitterRand (4);
+
+MeshParticleEmitter::MeshParticleEmitter (MemLabelId label, ObjectCreationMode mode)
+: Super(label, mode)
+{
+ m_VertexIndex = false;
+}
+
+MeshParticleEmitter::~MeshParticleEmitter ()
+{
+}
+
+void MeshParticleEmitter::Reset ()
+{
+ Super::Reset();
+ m_InterpolateTriangles = false;
+ m_Systematic = false;
+ m_MinNormalVelocity = 0.0F;
+ m_MaxNormalVelocity = 0.0F;
+}
+
+void MeshParticleEmitter::SetupParticles (
+ ParticleArray& particles,
+ const Vector3f& velocityOffset,
+ const Matrix3x3f& rotation,
+ int firstIndex)
+{
+ Mesh* mesh = m_Mesh;
+
+ MinMaxAABB& aabb = m_PrivateInfo.aabb;
+
+ Matrix4x4f scale;
+ GetComponent (Transform).CalculateTransformMatrixScaleDelta (scale);
+
+ Matrix3x3f rotationAndScale = Matrix3x3f(scale);
+ rotationAndScale = rotation * rotationAndScale;
+ rotationAndScale.InvertTranspose ();
+
+ float deltaTime = GetDeltaTime ();
+
+ // If there's an invalid mesh, then just emit from the center
+ if (mesh == NULL || mesh->GetSubMeshCount () == 0 || mesh->GetSubMeshFast (0).indexCount == 0 || !mesh->HasVertexData())
+ {
+ Vector3f v;
+ StrideIterator<Vector3f> vertices(&v, 0);
+ StrideIterator<Vector3f> normals;
+
+ for (int i = firstIndex;i<particles.size ();i++)
+ {
+ SetupParticle (0, particles[i], velocityOffset, scale, rotation, rotationAndScale, deltaTime, vertices, normals);
+ aabb.Encapsulate (particles[i].position);
+ }
+ return;
+ }
+
+ SubMesh& submesh = mesh->GetSubMeshFast (0);
+ int vertexCount = mesh->GetVertexCount();
+
+ StrideIterator<Vector3f> vertices = mesh->GetVertexBegin();
+ StrideIterator<Vector3f> normals = mesh->GetNormalBegin();
+ const UInt16* buffer = mesh->GetSubMeshBuffer16(0);
+
+ if (!m_Systematic)
+ {
+ if (m_InterpolateTriangles)
+ {
+ if (submesh.topology == kPrimitiveTriangleStripDeprecated)
+ {
+ for (int i = firstIndex;i<particles.size ();i++)
+ {
+ SetupParticleStrip (particles[i], velocityOffset, scale, rotation, rotationAndScale, deltaTime, vertices, normals, buffer, submesh.indexCount);
+ aabb.Encapsulate (particles[i].position);
+ }
+ }
+ else if (submesh.topology == kPrimitiveTriangles)
+ {
+ for (int i = firstIndex;i<particles.size ();i++)
+ {
+ SetupParticleTri (particles[i], velocityOffset, scale, rotation, rotationAndScale, deltaTime, vertices, normals, buffer, submesh.indexCount/3);
+ aabb.Encapsulate (particles[i].position);
+ }
+ }
+ }
+ else {
+ if (vertexCount != 0)
+ {
+ for (int i = firstIndex;i<particles.size ();i++) {
+ SetupParticle (RangedRandom (gMeshEmitterRand, 0, vertexCount), particles[i], velocityOffset, scale, rotation, rotationAndScale, deltaTime, vertices, normals);
+ aabb.Encapsulate (particles[i].position);
+ }
+ }
+ }
+ }
+ else {
+ if (vertexCount != 0)
+ {
+ // Just in case the mesh changed while the particle emitter was running
+ if (m_VertexIndex >= vertexCount)
+ m_VertexIndex = 0;
+
+ for (int i = firstIndex;i<particles.size ();i++) {
+ SetupParticle (m_VertexIndex, particles[i], velocityOffset, scale, rotation, rotationAndScale, deltaTime, vertices, normals);
+ aabb.Encapsulate (particles[i].position);
+
+ m_VertexIndex++;
+ if (m_VertexIndex >= vertexCount)
+ m_VertexIndex = 0;
+ }
+ }
+ }
+}
+
+void MeshParticleEmitter::SetupParticle (
+ int vertexIndex,
+ Particle& p,
+ const Vector3f& velocityOffset,
+ const Matrix4x4f& scale,
+ const Matrix3x3f& rotation,
+ const Matrix3x3f& normalTransform,
+ float deltaTime,
+ StrideIterator<Vector3f> vertices,
+ StrideIterator<Vector3f> normals)
+{
+ InitParticleEnergy(gMeshEmitterRand, p, deltaTime);
+
+ // position/normal of particle is vertex/vertex normal from mesh
+ Vector3f positionOnMesh = vertices[vertexIndex];
+ positionOnMesh = scale.MultiplyPoint3 (positionOnMesh);
+
+ Vector3f normal;
+ if (!normals.IsNull ())
+ {
+ normal = normalTransform.MultiplyVector3 (normals[vertexIndex]);
+ normal = NormalizeFast (normal);
+ }
+ else
+ normal = Vector3f(0,0,0);
+
+
+ // Set particle starting position
+ p.position = m_PreviousEmitterPos;
+ p.position += velocityOffset * RangedRandom (gMeshEmitterRand, 0.0F, deltaTime);
+ p.position += (m_EmitterPos - m_PreviousEmitterPos) * Random01 (gMeshEmitterRand);
+ p.position += rotation.MultiplyVector3 (positionOnMesh);
+
+ // Set velocity
+ p.velocity = velocityOffset + normal * RangedRandom (gMeshEmitterRand, m_MinNormalVelocity, m_MaxNormalVelocity);
+ p.velocity += rotation.MultiplyVector3 (RandomPointInsideEllipsoid (gMeshEmitterRand, m_RndVelocity));
+
+ p.rotation = m_RndInitialRotations ? RangedRandom (gMeshEmitterRand, 0.0f, 2*kPI):0.0F;
+ float angularVelocity = m_AngularVelocity;
+#if SUPPORT_REPRODUCE_LOG
+ if (m_RndAngularVelocity > Vector3f::epsilon)
+#endif
+ angularVelocity += RangedRandom (gMeshEmitterRand, -m_RndAngularVelocity, m_RndAngularVelocity);
+ p.angularVelocity = Deg2Rad(angularVelocity);
+
+ p.color = ColorRGBA32 (255, 255, 255, 255);
+
+ // Set size
+ p.size = RangedRandom (gMeshEmitterRand, m_MinSize, m_MaxSize);
+}
+
+void MeshParticleEmitter::SetupParticleTri (
+ Particle& p,
+ const Vector3f& velocityOffset,
+ const Matrix4x4f& scale,
+ const Matrix3x3f& rotation,
+ const Matrix3x3f& normalTransform,
+ float deltaTime,
+ StrideIterator<Vector3f> vertices,
+ StrideIterator<Vector3f> normals,
+ const UInt16* indices,
+ int triCount)
+{
+ InitParticleEnergy(gMeshEmitterRand, p, deltaTime);
+
+ int triIndex = RangedRandom (gMeshEmitterRand, 0, (int)triCount);
+ const UInt16* face = indices + triIndex * 3;
+ Vector3f barycenter = RandomBarycentricCoord (gMeshEmitterRand);
+
+ // Interpolate vertex with barycentric coordinate
+ Vector3f positionOnMesh = barycenter.x * vertices[face[0]] + barycenter.y * vertices[face[1]] + barycenter.z * vertices[face[2]];
+ positionOnMesh = scale.MultiplyPoint3 (positionOnMesh);
+
+ Vector3f normal;
+ if (!normals.IsNull ())
+ {
+ // Interpolate normal with barycentric coordinate
+ Vector3f const& normal1 = normals[face[0]];
+ Vector3f const& normal2 = normals[face[1]];
+ Vector3f const& normal3 = normals[face[2]];
+ normal = barycenter.x * normal1 + barycenter.y * normal2 + barycenter.z * normal3;
+ normal = normalTransform.MultiplyVector3 (normal);
+ normal = NormalizeFast (normal);
+ }
+ else
+ normal = Vector3f(0,0,0);
+
+ // Set particle starting position
+ p.position = m_PreviousEmitterPos;
+ p.position += velocityOffset * RangedRandom (gMeshEmitterRand, 0.0F, deltaTime);
+ p.position += (m_EmitterPos - m_PreviousEmitterPos) * Random01 (gMeshEmitterRand);
+ p.position += rotation.MultiplyVector3 (positionOnMesh);
+
+ // Set velocity
+ p.velocity = velocityOffset + normal * RangedRandom (gMeshEmitterRand, m_MinNormalVelocity, m_MaxNormalVelocity);
+ p.velocity += rotation.MultiplyVector3 (RandomPointInsideEllipsoid (gMeshEmitterRand, m_RndVelocity));
+
+ p.rotation = m_RndInitialRotations ? RangedRandom (gMeshEmitterRand, 0.0f, 2*kPI):0.0F;
+ float angularVelocity = m_AngularVelocity;
+#if SUPPORT_REPRODUCE_LOG
+ if (m_RndAngularVelocity > Vector3f::epsilon)
+#endif
+ angularVelocity += RangedRandom (gMeshEmitterRand, -m_RndAngularVelocity, m_RndAngularVelocity);
+ p.angularVelocity = Deg2Rad(angularVelocity);
+
+ p.color = ColorRGBA32 (255, 255, 255, 255);
+
+ // Set size
+ p.size = RangedRandom (gMeshEmitterRand, m_MinSize, m_MaxSize);
+}
+
+void MeshParticleEmitter::SetupParticleStrip (
+ Particle& p,
+ const Vector3f& velocityOffset,
+ const Matrix4x4f& scale,
+ const Matrix3x3f& rotation,
+ const Matrix3x3f& normalTransform,
+ float deltaTime,
+ StrideIterator<Vector3f> vertices,
+ StrideIterator<Vector3f> normals,
+ const UInt16* strip,
+ int stripSize)
+{
+ InitParticleEnergy(gMeshEmitterRand, p, deltaTime);
+
+ // Extract indices from tristrip
+ int stripIndex = RangedRandom (gMeshEmitterRand, 2, stripSize);
+ UInt16 a = strip[stripIndex-2];
+ UInt16 b = strip[stripIndex-1];
+ UInt16 c = strip[stripIndex];
+ // Ignore degenerate triangles
+ while (a == b || a == c || b == c)
+ {
+ stripIndex = RangedRandom (gMeshEmitterRand, 2, stripSize);
+ a = strip[stripIndex-2];
+ b = strip[stripIndex-1];
+ c = strip[stripIndex];
+ while (a == b || a == c || b == c)
+ {
+ stripIndex++;
+ if (stripIndex >= stripSize)
+ break;
+ a = strip[stripIndex-2];
+ b = strip[stripIndex-1];
+ c = strip[stripIndex];
+ }
+ }
+
+ Vector3f barycenter = RandomBarycentricCoord (gMeshEmitterRand);
+
+ // Interpolate vertex with barycentric coordinate
+ Vector3f positionOnMesh = barycenter.x * vertices[a] + barycenter.y * vertices[b] + barycenter.z * vertices[c];
+ positionOnMesh = scale.MultiplyPoint3 (positionOnMesh);
+
+
+ Vector3f normal;
+ if (!normals.IsNull ())
+ {
+ // Interpolate normal with barycentric coordinate
+ Vector3f normal1 = normals[a];
+ Vector3f normal2 = normals[b];
+ Vector3f normal3 = normals[c];
+ normal = barycenter.x * normal1 + barycenter.y * normal2 + barycenter.z * normal3;
+ normal = normalTransform.MultiplyVector3 (normal);
+ normal = NormalizeFast (normal);
+ }
+ else
+ {
+ normal = Vector3f(0,0,0);
+ }
+
+ // Set particle starting position
+ p.position = m_PreviousEmitterPos;
+ p.position += velocityOffset * RangedRandom (gMeshEmitterRand, 0.0F, deltaTime);
+ p.position += (m_EmitterPos - m_PreviousEmitterPos) * Random01 (gMeshEmitterRand);
+ p.position += rotation.MultiplyVector3 (positionOnMesh);
+
+ // Set velocity
+ p.velocity = velocityOffset + normal * RangedRandom (gMeshEmitterRand, m_MinNormalVelocity, m_MaxNormalVelocity);
+ p.velocity += rotation.MultiplyVector3 (RandomPointInsideEllipsoid (gMeshEmitterRand, m_RndVelocity));
+
+ p.rotation = m_RndInitialRotations ? RangedRandom (gMeshEmitterRand, 0.0f, 2*kPI):0.0F;
+ float angularVelocity = m_AngularVelocity;
+#if SUPPORT_REPRODUCE_LOG
+ if (m_RndAngularVelocity > Vector3f::epsilon)
+#endif
+ angularVelocity += RangedRandom (gMeshEmitterRand, -m_RndAngularVelocity, m_RndAngularVelocity);
+ p.angularVelocity = Deg2Rad(angularVelocity);
+
+ p.color = ColorRGBA32 (255, 255, 255, 255);
+
+ // Set size
+ p.size = RangedRandom (gMeshEmitterRand, m_MinSize, m_MaxSize);
+}
+
+static void ResetRandSeedForMeshParticleEmitter ()
+{
+ gMeshEmitterRand.SetSeed (4);
+}
+
+void MeshParticleEmitter::InitializeClass ()
+{
+ GlobalCallbacks::Get().resetRandomAfterLevelLoad.Register(ResetRandSeedForMeshParticleEmitter);
+}
+
+void MeshParticleEmitter::CleanupClass ()
+{
+ GlobalCallbacks::Get().resetRandomAfterLevelLoad.Unregister(ResetRandSeedForMeshParticleEmitter);
+}
+
+IMPLEMENT_CLASS_HAS_INIT (MeshParticleEmitter)
+IMPLEMENT_OBJECT_SERIALIZE (MeshParticleEmitter)
+
+template<class TransferFunction> inline
+void MeshParticleEmitter::Transfer (TransferFunction& transfer)
+{
+ Super::Transfer (transfer);
+ TRANSFER (m_InterpolateTriangles);
+ TRANSFER (m_Systematic);
+ transfer.Align();
+ TRANSFER (m_MinNormalVelocity);
+ TRANSFER (m_MaxNormalVelocity);
+ TRANSFER (m_Mesh);
+}
+
+void MeshParticleEmitter::SetMesh (PPtr<Mesh> mesh)
+{
+ m_Mesh = mesh;
+ SetDirty();
+}