diff --git a/Source/Engine/Particles/Graph/ParticleEmitterGraph.h b/Source/Engine/Particles/Graph/ParticleEmitterGraph.h
index f5946c226..91dae0ed2 100644
--- a/Source/Engine/Particles/Graph/ParticleEmitterGraph.h
+++ b/Source/Engine/Particles/Graph/ParticleEmitterGraph.h
@@ -37,12 +37,12 @@ public:
///
/// Flag valid for used particle nodes that need per-particle data to evaluate its value (including dependant nodes linked to input boxes). Used to skip per-particle graph evaluation if graph uses the same value for all particles (eg. is not using per-particle seed or position node).
///
- bool UsesParticleData;
+ bool UsesParticleData = false;
///
/// Flag valid for used particle nodes that result in constant data (nothing random nor particle data).
///
- bool IsConstant;
+ bool IsConstant = true;
///
/// The cached particle attribute indices used by the simulation graph to access particle properties.
@@ -50,6 +50,8 @@ public:
int32 Attributes[PARTICLE_EMITTER_MAX_ATTRIBUTES_REFS_PER_NODE];
};
+void InitParticleEmitterFunctionCall(const Guid& assetId, AssetReference& asset, bool& usesParticleData, ParticleLayout& layout);
+
///
/// The Particle Emitter Graph used to simulate particles.
///
@@ -157,8 +159,6 @@ public:
if (node->Used)
return;
node->Used = true;
- node->UsesParticleData = false;
- node->IsConstant = true;
#define USE_ATTRIBUTE(name, valueType, slot) \
{ \
@@ -292,14 +292,11 @@ public:
case GRAPH_NODE_MAKE_TYPE(14, 214):
case GRAPH_NODE_MAKE_TYPE(14, 215):
case GRAPH_NODE_MAKE_TYPE(14, 216):
- {
node->IsConstant = false;
break;
- }
// Particle Emitter Function
case GRAPH_NODE_MAKE_TYPE(14, 300):
- node->Assets[0] = Content::LoadAsync((Guid)node->Values[0]);
- node->UsesParticleData = true; // TODO: analyze emitter function graph to detect if it's actually using any particle data at all (even from inputs after inline)
+ InitParticleEmitterFunctionCall((Guid)node->Values[0], node->Assets[0], node->UsesParticleData, Layout);
break;
// Particle Index
case GRAPH_NODE_MAKE_TYPE(14, 301):
@@ -564,7 +561,7 @@ public:
return true;
// Compute particle data layout and initialize used nodes (for only used nodes, start depth searching rom the modules)
- Layout.AddAttribute(TEXT("Position"), ParticleAttribute::ValueTypes::Float3);
+ //Layout.AddAttribute(TEXT("Position"), ParticleAttribute::ValueTypes::Float3);
#define PROCESS_MODULES(modules) for (int32 i = 0; i < modules.Count(); i++) { modules[i]->Used = false; InitializeNode(modules[i]); }
PROCESS_MODULES(SpawnModules);
PROCESS_MODULES(InitModules);
diff --git a/Source/Engine/Particles/ParticleEmitterFunction.cpp b/Source/Engine/Particles/ParticleEmitterFunction.cpp
index c91bc0d82..5abb4a434 100644
--- a/Source/Engine/Particles/ParticleEmitterFunction.cpp
+++ b/Source/Engine/Particles/ParticleEmitterFunction.cpp
@@ -9,6 +9,27 @@
#endif
#include "Engine/Content/Factories/BinaryAssetFactory.h"
+void InitParticleEmitterFunctionCall(const Guid& assetId, AssetReference& asset, bool& usesParticleData, ParticleLayout& layout)
+{
+ const auto function = Content::Load(assetId);
+ asset = function;
+ if (function)
+ {
+ // Insert any used particle data into the calling graph
+ for (const ParticleAttribute& e : function->Graph.Layout.Attributes)
+ {
+ if (layout.FindAttribute(e.Name, e.ValueType) == -1)
+ layout.AddAttribute(e.Name, e.ValueType);
+ }
+
+ // Detect if function needs to be evaluated per-particle
+ for (int32 i = 0; i < function->Outputs.Count() && !usesParticleData; i++)
+ {
+ usesParticleData = function->Graph.Nodes[function->Outputs.Get()[i]].UsesParticleData;
+ }
+ }
+}
+
REGISTER_BINARY_ASSET(ParticleEmitterFunction, "FlaxEngine.ParticleEmitterFunction", false);
ParticleEmitterFunction::ParticleEmitterFunction(const SpawnParams& params, const AssetInfo* info)
diff --git a/Source/Engine/Visject/VisjectGraph.h b/Source/Engine/Visject/VisjectGraph.h
index 5836afb2f..085c05de0 100644
--- a/Source/Engine/Visject/VisjectGraph.h
+++ b/Source/Engine/Visject/VisjectGraph.h
@@ -262,11 +262,11 @@ protected:
FORCE_INLINE Value tryGetValue(Box* box)
{
- return box && box->HasConnection() ? eatBox(box->GetParent(), box->FirstConnection()) : Value::Zero;
+ return box && box->Connections.HasItems() ? eatBox(box->GetParent(), (VisjectGraphBox*)box->Connections.Get()[0]) : Value::Zero;
}
FORCE_INLINE Value tryGetValue(Box* box, const Value& defaultValue)
{
- return box && box->HasConnection() ? eatBox(box->GetParent(), box->FirstConnection()) : defaultValue;
+ return box && box->Connections.HasItems() ? eatBox(box->GetParent(), (VisjectGraphBox*)box->Connections.Get()[0]) : defaultValue;
}
};