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; } };