BVB Source Codes

CRYENGINE Show FeatureLocation.cpp Source code

Return Download CRYENGINE: download FeatureLocation.cpp Source code - Download CRYENGINE Source code - Type:.cpp
  1. // Copyright 2001-2016 Crytek GmbH / Crytek Group. All rights reserved.
  2.  
  3. // -------------------------------------------------------------------------
  4. //  Created:     29/09/2014 by Filipe amim
  5. //  Description:
  6. // -------------------------------------------------------------------------
  7. //
  8. ////////////////////////////////////////////////////////////////////////////
  9.  
  10. #include "StdAfx.h"
  11. #include <CrySystem/CryUnitTest.h>
  12. #include <CryMath/SNoise.h>
  13. #include <CrySerialization/Math.h>
  14. #include "ParticleSystem/ParticleFeature.h"
  15. #include "ParticleSystem/ParticleEmitter.h"
  16. #include "ParamMod.h"
  17. #include "Target.h"
  18.  
  19. CRY_PFX2_DBG
  20.  
  21. namespace pfx2
  22. {
  23.  
  24. //////////////////////////////////////////////////////////////////////////
  25. // CFeatureLocationOffset
  26.  
  27. class CFeatureLocationOffset : public CParticleFeature
  28. {
  29. public:
  30.         CRY_PFX2_DECLARE_FEATURE
  31.  
  32.         CFeatureLocationOffset()
  33.                 : m_offset(ZERO)
  34.                 , m_scale(1.0f)
  35.                 , CParticleFeature(gpu_pfx2::eGpuFeatureType_LocationOffset)
  36.         {}
  37.  
  38.         virtual void AddToComponent(CParticleComponent* pComponent, SComponentParams* pParams) override
  39.         {
  40.                 pComponent->AddToUpdateList(EUL_GetExtents, this);
  41.                 pComponent->AddToUpdateList(EUL_InitUpdate, this);
  42.                 m_scale.AddToComponent(pComponent, this);
  43.  
  44.                 if (auto pInt = GetGpuInterface())
  45.                 {
  46.                         gpu_pfx2::SFeatureParametersLocationOffset params;
  47.                         params.offset = m_offset;
  48.                         params.scale = m_scale.GetBaseValue();
  49.                         pInt->SetParameters(params);
  50.                 }
  51.         }
  52.  
  53.         virtual void Serialize(Serialization::IArchive& ar) override
  54.         {
  55.                 CParticleFeature::Serialize(ar);
  56.                 ar(m_offset, "Offset", "Offset");
  57.                 ar(m_scale, "Scale", "Scale");
  58.         }
  59.  
  60.         virtual void GetSpatialExtents(const SUpdateContext& context, Array<const float, uint> scales, Array<float, uint> extents) override
  61.         {
  62.                 if (!m_scale.HasModifiers())
  63.                         return;
  64.  
  65.                 TFloatArray sizes(*context.m_pMemHeap, context.m_parentContainer.GetLastParticleId());
  66.                 auto modRange = m_scale.GetValues(context, sizes, EMD_PerInstance, true);
  67.  
  68.                 const size_t numInstances = context.m_runtime.GetNumInstances();
  69.                 for (size_t i = 0; i < numInstances; ++i)
  70.                 {
  71.                         const TParticleId parentId = context.m_runtime.GetInstance(i).m_parentId;
  72.                         float e = abs(sizes[parentId]) * modRange.Length();
  73.                         e = e * scales[i] + 1.0f;
  74.                         extents[i] += e;
  75.                 }
  76.         }
  77.  
  78.         virtual void InitParticles(const SUpdateContext& context) override
  79.         {
  80.                 CRY_PROFILE_FUNCTION(PROFILE_PARTICLE);
  81.  
  82.                 CParticleContainer& parentContainer = context.m_parentContainer;
  83.                 CParticleContainer& container = context.m_container;
  84.                 const Quat defaultQuat = context.m_runtime.GetEmitter()->GetLocation().q;
  85.                 IPidStream parentIds = container.GetIPidStream(EPDT_ParentId);
  86.                 IQuatStream parentQuats = parentContainer.GetIQuatStream(EPQF_Orientation, defaultQuat);
  87.                 IOVec3Stream positions = container.GetIOVec3Stream(EPVF_Position);
  88.                 STempModBuffer scales(context, m_scale);
  89.                 scales.ModifyInit(context, m_scale, container.GetSpawnedRange());
  90.  
  91.                 Vec3 oOffset = m_offset;
  92.                 CRY_PFX2_FOR_SPAWNED_PARTICLES(context)
  93.                 {
  94.                         const TParticleId parentId = parentIds.Load(particleId);
  95.                         const float scale = scales.m_stream.SafeLoad(particleId);
  96.                         const Vec3 wPosition0 = positions.Load(particleId);
  97.                         const Quat wQuat = parentQuats.SafeLoad(parentId);
  98.                         const Vec3 wOffset = wQuat * oOffset;
  99.                         const Vec3 wPosition1 = wPosition0 + wOffset * scale;
  100.                         positions.Store(particleId, wPosition1);
  101.                 }
  102.                 CRY_PFX2_FOR_END;
  103.         }
  104.  
  105. private:
  106.         Vec3 m_offset;
  107.         CParamMod<SModParticleSpawnInit, UFloat10> m_scale;
  108. };
  109.  
  110. CRY_PFX2_IMPLEMENT_FEATURE(CParticleFeature, CFeatureLocationOffset, "Location", "Offset", colorLocation);
  111.  
  112. //////////////////////////////////////////////////////////////////////////
  113. // CFeatureLocationBox
  114.  
  115. class CFeatureLocationBox : public CParticleFeature
  116. {
  117. public:
  118.         CRY_PFX2_DECLARE_FEATURE
  119.  
  120.         CFeatureLocationBox()
  121.                 : m_box(ZERO)
  122.                 , CParticleFeature(gpu_pfx2::eGpuFeatureType_LocationBox)
  123.         {}
  124.  
  125.         virtual void AddToComponent(CParticleComponent* pComponent, SComponentParams* pParams) override
  126.         {
  127.                 pComponent->AddToUpdateList(EUL_InitUpdate, this);
  128.                 pComponent->AddToUpdateList(EUL_GetExtents, this);
  129.                 m_scale.AddToComponent(pComponent, this);
  130.                 if (auto pInt = GetGpuInterface())
  131.                 {
  132.                         gpu_pfx2::SFeatureParametersLocationBox params;
  133.                         params.box = m_box;
  134.                         params.scale = m_scale.GetBaseValue();
  135.                         pInt->SetParameters(params);
  136.                 }
  137.         }
  138.  
  139.         virtual void Serialize(Serialization::IArchive& ar) override
  140.         {
  141.                 CParticleFeature::Serialize(ar);
  142.                 ar(m_box, "Dimension", "Dimension");
  143.                 ar(m_scale, "Scale", "Scale");
  144.         }
  145.  
  146.         virtual void GetSpatialExtents(const SUpdateContext& context, Array<const float, uint> scales, Array<float, uint> extents) override
  147.         {
  148.                 size_t numInstances = context.m_runtime.GetNumInstances();
  149.                 TFloatArray sizes(*context.m_pMemHeap, context.m_parentContainer.GetLastParticleId());
  150.                 auto modRange = m_scale.GetValues(context, sizes, EMD_PerInstance, true);
  151.                 float avg = (modRange.start + modRange.end) * 0.5f;
  152.  
  153.                 for (size_t i = 0; i < numInstances; ++i)
  154.                 {
  155.                         // Increase each dimension by 1 to include boundaries; works properly for boxes, rects, and lines
  156.                         const TParticleId parentId = context.m_runtime.GetInstance(i).m_parentId;
  157.                         const float s = scales[i] * sizes[parentId] * avg;
  158.                         extents[i] += (m_box.x * s + 1.0f) * (m_box.y * s + 1.0f) * (m_box.z * s + 1.0f);
  159.                 }
  160.         }
  161.  
  162.         virtual void InitParticles(const SUpdateContext& context) override
  163.         {
  164.                 CRY_PFX2_PROFILE_DETAIL;
  165.  
  166.                 CParticleContainer& parentContainer = context.m_parentContainer;
  167.                 CParticleContainer& container = context.m_container;
  168.                 const Quat defaultQuat = context.m_runtime.GetEmitter()->GetLocation().q;
  169.                 IPidStream parentIds = container.GetIPidStream(EPDT_ParentId);
  170.                 IQuatStream parentQuats = parentContainer.GetIQuatStream(EPQF_Orientation, defaultQuat);
  171.                 IOVec3Stream positions = container.GetIOVec3Stream(EPVF_Position);
  172.                 STempModBuffer scales(context, m_scale);
  173.                 scales.ModifyInit(context, m_scale, container.GetSpawnedRange());
  174.  
  175.                 CRY_PFX2_FOR_SPAWNED_PARTICLES(context)
  176.                 {
  177.                         const TParticleId parentId = parentIds.Load(particleId);
  178.                         const float scale = scales.m_stream.SafeLoad(particleId);
  179.                         const Vec3 wPosition0 = positions.Load(particleId);
  180.                         const Quat wQuat = parentQuats.SafeLoad(parentId);
  181.                         const Vec3 oOffset = Vec3(
  182.                           context.m_spawnRng.RandSNorm() * m_box.x,
  183.                           context.m_spawnRng.RandSNorm() * m_box.y,
  184.                           context.m_spawnRng.RandSNorm() * m_box.z);
  185.                         const Vec3 wOffset = wQuat * oOffset;
  186.                         const Vec3 wPosition1 = wPosition0 + wOffset * scale;
  187.                         positions.Store(particleId, wPosition1);
  188.                 }
  189.                 CRY_PFX2_FOR_END;
  190.         }
  191.  
  192. private:
  193.         Vec3 m_box;
  194.         CParamMod<SModParticleSpawnInit, UFloat10> m_scale;
  195. };
  196.  
  197. CRY_PFX2_IMPLEMENT_FEATURE(CParticleFeature, CFeatureLocationBox, "Location", "Box", colorLocation);
  198.  
  199. //////////////////////////////////////////////////////////////////////////
  200. // CFeatureLocationSphere
  201.  
  202. class CFeatureLocationSphere : public CParticleFeature
  203. {
  204. public:
  205.         CRY_PFX2_DECLARE_FEATURE
  206.  
  207.         CFeatureLocationSphere()
  208.                 : m_radius(0.0f)
  209.                 , m_velocity(0.0f)
  210.                 , m_axisScale(1.0f, 1.0f, 1.0f)
  211.                 , CParticleFeature(gpu_pfx2::eGpuFeatureType_LocationSphere)
  212.         {}
  213.  
  214.         virtual void AddToComponent(CParticleComponent* pComponent, SComponentParams* pParams) override
  215.         {
  216.                 pComponent->AddToUpdateList(EUL_InitUpdate, this);
  217.                 pComponent->AddToUpdateList(EUL_GetExtents, this);
  218.                 m_radius.AddToComponent(pComponent, this);
  219.                 m_velocity.AddToComponent(pComponent, this);
  220.                 if (auto pInt = GetGpuInterface())
  221.                 {
  222.                         gpu_pfx2::SFeatureParametersLocationSphere params;
  223.                         params.scale = m_axisScale;
  224.                         params.radius = m_radius.GetBaseValue();
  225.                         params.velocity = m_velocity.GetBaseValue();
  226.                         pInt->SetParameters(params);
  227.                 }
  228.         }
  229.  
  230.         virtual void Serialize(Serialization::IArchive& ar) override
  231.         {
  232.                 CParticleFeature::Serialize(ar);
  233.                 ar(m_radius, "Radius", "Radius");
  234.                 ar(m_velocity, "Velocity", "Velocity");
  235.                 ar(m_axisScale, "AxisScale", "Axis Scale");
  236.         }
  237.  
  238.         virtual void InitParticles(const SUpdateContext& context) override
  239.         {
  240.                 CRY_PFX2_PROFILE_DETAIL;
  241.  
  242.                 const float EPSILON = 1.0f / 2048.0f;
  243.                 const bool useRadius = m_radius.GetBaseValue() > EPSILON;
  244.                 const bool useVelocity = abs(m_velocity.GetBaseValue()) > EPSILON;
  245.  
  246.                 if (useRadius && useVelocity)
  247.                         SphericalDist<true, true>(context);
  248.                 else if (useRadius)
  249.                         SphericalDist<true, false>(context);
  250.                 else if (useVelocity)
  251.                         SphericalDist<false, true>(context);
  252.         }
  253.  
  254.         virtual void GetSpatialExtents(const SUpdateContext& context, Array<const float, uint> scales, Array<float, uint> extents) override
  255.         {
  256.                 size_t numInstances = context.m_runtime.GetNumInstances();
  257.                 TFloatArray sizes(*context.m_pMemHeap, context.m_parentContainer.GetLastParticleId());
  258.                 auto modRange = m_radius.GetValues(context, sizes, EMD_PerInstance, true);
  259.  
  260.                 for (size_t i = 0; i < numInstances; ++i)
  261.                 {
  262.                         // Increase each dimension by 1 to include sphere bounds; works properly for spheres and circles
  263.                         const TParticleId parentId = context.m_runtime.GetInstance(i).m_parentId;
  264.                         const Vec3 axisMax = m_axisScale * (scales[i] * sizes[parentId] * modRange.end) + Vec3(1.0f),
  265.                                    axisMin = m_axisScale * (scales[i] * sizes[parentId] * modRange.start);
  266.                         const float v = (axisMax.x * axisMax.y * axisMax.z - axisMin.x * axisMin.y * axisMin.z) * (gf_PI * 4.0f / 3.0f);
  267.                         extents[i] += v;
  268.                 }
  269.         }
  270.  
  271. private:
  272.         template<const bool UseRadius, const bool UseVelocity>
  273.         void SphericalDist(const SUpdateContext& context)
  274.         {
  275.                 CParticleContainer& container = context.m_container;
  276.                 IOVec3Stream positions = container.GetIOVec3Stream(EPVF_Position);
  277.                 IOVec3Stream velocities = container.GetIOVec3Stream(EPVF_Velocity);
  278.                 const float baseRadius = m_radius.GetBaseValue();
  279.                 const float invBaseRadius = __fres(baseRadius);
  280.  
  281.                 STempModBuffer radii(context, m_radius);
  282.                 STempModBuffer velocityMults(context, m_velocity);
  283.                 radii.ModifyInit(context, m_radius, container.GetSpawnedRange());
  284.                 velocityMults.ModifyInit(context, m_velocity, container.GetSpawnedRange());
  285.  
  286.                 CRY_PFX2_FOR_SPAWNED_PARTICLES(context)
  287.                 {
  288.                         const Vec3 sphere = context.m_spawnRng.RandSphere();
  289.                         const Vec3 sphereDist = sphere.CompMul(m_axisScale);
  290.                         const float radiusMult = abs(radii.m_stream.SafeLoad(particleId));
  291.                         const float velocityMult = velocityMults.m_stream.SafeLoad(particleId);
  292.  
  293.                         if (UseRadius)
  294.                         {
  295.                                 const float radius = sqrt(radiusMult * invBaseRadius) * baseRadius;
  296.                                 const Vec3 wPosition0 = positions.Load(particleId);
  297.                                 const Vec3 wPosition1 = wPosition0 + sphereDist * radius;
  298.                                 positions.Store(particleId, wPosition1);
  299.                         }
  300.  
  301.                         if (UseVelocity)
  302.                         {
  303.                                 const Vec3 wVelocity0 = velocities.Load(particleId);
  304.                                 const Vec3 wVelocity1 = wVelocity0 + sphereDist * velocityMult;
  305.                                 velocities.Store(particleId, wVelocity1);
  306.                         }
  307.                 }
  308.                 CRY_PFX2_FOR_END;
  309.         }
  310.  
  311.         CParamMod<SModParticleSpawnInit, UFloat10> m_radius;
  312.         CParamMod<SModParticleSpawnInit, SFloat10> m_velocity;
  313.         Vec3 m_axisScale;
  314. };
  315.  
  316. CRY_PFX2_IMPLEMENT_FEATURE(CParticleFeature, CFeatureLocationSphere, "Location", "Sphere", colorLocation);
  317.  
  318. //////////////////////////////////////////////////////////////////////////
  319. // CFeatureLocationDisc
  320.  
  321. class CFeatureLocationCircle : public CParticleFeature
  322. {
  323. public:
  324.         CRY_PFX2_DECLARE_FEATURE
  325.  
  326.         CFeatureLocationCircle()
  327.                 : m_radius(0.0f)
  328.                 , m_velocity(0.0f)
  329.                 , m_axisScale(1.0f, 1.0f)
  330.                 , CParticleFeature(gpu_pfx2::eGpuFeatureType_LocationCircle)
  331.         {}
  332.  
  333.         virtual void AddToComponent(CParticleComponent* pComponent, SComponentParams* pParams) override
  334.         {
  335.                 pComponent->AddToUpdateList(EUL_InitUpdate, this);
  336.                 pComponent->AddToUpdateList(EUL_GetExtents, this);
  337.                 m_radius.AddToComponent(pComponent, this);
  338.                 m_velocity.AddToComponent(pComponent, this);
  339.                 if (auto pInt = GetGpuInterface())
  340.                 {
  341.                         gpu_pfx2::SFeatureParametersLocationCircle params;
  342.                         params.scale = m_axisScale;
  343.                         params.radius = m_radius.GetBaseValue();
  344.                         params.velocity = m_velocity.GetBaseValue();
  345.                         pInt->SetParameters(params);
  346.                 }
  347.         }
  348.  
  349.         virtual void Serialize(Serialization::IArchive& ar) override
  350.         {
  351.                 CParticleFeature::Serialize(ar);
  352.                 ar(m_radius, "Radius", "Radius");
  353.                 ar(m_velocity, "Velocity", "Velocity");
  354.                 ar(m_axisScale, "AxisScale", "Axis Scale");
  355.         }
  356.  
  357.         virtual void InitParticles(const SUpdateContext& context) override
  358.         {
  359.                 CRY_PFX2_PROFILE_DETAIL;
  360.  
  361.                 const float EPSILON = 1.0f / 2048.0f;
  362.                 const bool useRadius = m_radius.GetBaseValue() > EPSILON;
  363.                 const bool useVelocity = abs(m_velocity.GetBaseValue()) > EPSILON;
  364.  
  365.                 if (useRadius && useVelocity)
  366.                         CircularDist<true, true>(context);
  367.                 else if (useRadius)
  368.                         CircularDist<true, false>(context);
  369.                 else if (useVelocity)
  370.                         CircularDist<false, true>(context);
  371.         }
  372.  
  373.         virtual void GetSpatialExtents(const SUpdateContext& context, Array<const float, uint> scales, Array<float, uint> extents) override
  374.         {
  375.                 const size_t numInstances = context.m_runtime.GetNumInstances();
  376.                 TFloatArray sizes(*context.m_pMemHeap, context.m_parentContainer.GetLastParticleId());
  377.                 auto modRange = m_radius.GetValues(context, sizes, EMD_PerInstance, true);
  378.  
  379.                 for (size_t i = 0; i < numInstances; ++i)
  380.                 {
  381.                         const TParticleId parentId = context.m_runtime.GetInstance(i).m_parentId;
  382.                         const Vec2 axisMax = m_axisScale * (scales[i] * sizes[parentId] * modRange.end) + Vec2(1.0f),
  383.                                    axisMin = m_axisScale * (scales[i] * sizes[parentId] * modRange.start);
  384.                         const float v = (axisMax.x * axisMax.y - axisMin.x * axisMin.y) * gf_PI;
  385.                         extents[i] += v;
  386.                 }
  387.         }
  388.  
  389. private:
  390.         template<const bool UseRadius, const bool UseVelocity>
  391.         void CircularDist(const SUpdateContext& context)
  392.         {
  393.                 CParticleContainer& parentContainer = context.m_parentContainer;
  394.                 CParticleContainer& container = context.m_container;
  395.                 const Quat defaultQuat = context.m_runtime.GetEmitter()->GetLocation().q;
  396.                 IPidStream parentIds = container.GetIPidStream(EPDT_ParentId);
  397.                 IQuatStream parentQuats = parentContainer.GetIQuatStream(EPQF_Orientation, defaultQuat);
  398.                 IOVec3Stream positions = container.GetIOVec3Stream(EPVF_Position);
  399.                 IOVec3Stream velocities = container.GetIOVec3Stream(EPVF_Velocity);
  400.                 const float baseRadius = m_radius.GetBaseValue();
  401.                 const float invBaseRadius = __fres(baseRadius);
  402.  
  403.                 STempModBuffer radii(context, m_radius);
  404.                 STempModBuffer velocityMults(context, m_velocity);
  405.                 radii.ModifyInit(context, m_radius, container.GetSpawnedRange());
  406.                 velocityMults.ModifyInit(context, m_velocity, container.GetSpawnedRange());
  407.  
  408.                 CRY_PFX2_FOR_SPAWNED_PARTICLES(context)
  409.                 {
  410.                         TParticleId parentId = parentIds.Load(particleId);
  411.                         const float radiusMult = abs(radii.m_stream.SafeLoad(particleId));
  412.                         const float velocityMult = velocityMults.m_stream.SafeLoad(particleId);
  413.                         const Quat wQuat = parentQuats.SafeLoad(parentId);
  414.  
  415.                         const Vec2 dist2 = context.m_spawnRng.RandCircle();
  416.                         const Vec3 dist3 = Vec3(dist2.x * m_axisScale.x, dist2.y * m_axisScale.y, 0.0f);
  417.  
  418.                         if (UseRadius)
  419.                         {
  420.                                 const float radius = sqrt(radiusMult * invBaseRadius) * baseRadius;
  421.                                 const Vec3 oPosition = dist3 * radius;
  422.                                 const Vec3 wPosition0 = positions.Load(particleId);
  423.                                 const Vec3 wPosition1 = wPosition0 + wQuat * oPosition;
  424.                                 positions.Store(particleId, wPosition1);
  425.                         }
  426.  
  427.                         if (UseVelocity)
  428.                         {
  429.                                 const Vec3 wVelocity0 = velocities.Load(particleId);
  430.                                 const Vec3 wVelocity1 = wVelocity0 + wQuat * dist3 * velocityMult;
  431.                                 velocities.Store(particleId, wVelocity1);
  432.                         }
  433.                 }
  434.                 CRY_PFX2_FOR_END;
  435.         }
  436.  
  437.         CParamMod<SModParticleSpawnInit, UFloat10> m_radius;
  438.         CParamMod<SModParticleSpawnInit, SFloat10> m_velocity;
  439.         Vec2 m_axisScale;
  440. };
  441.  
  442. CRY_PFX2_IMPLEMENT_FEATURE(CParticleFeature, CFeatureLocationCircle, "Location", "Circle", colorLocation);
  443.  
  444. //////////////////////////////////////////////////////////////////////////
  445. // CFeatureLocationGeometry
  446.  
  447. extern EParticleDataType EPDT_MeshGeometry, EPDT_PhysicalEntity;
  448.  
  449. SERIALIZATION_DECLARE_ENUM(EGeometrySource,
  450.                            Render = GeomType_Render,
  451.                            Physics = GeomType_Physics
  452.                            )
  453.  
  454. SERIALIZATION_DECLARE_ENUM(EGeometryLocation,
  455.                            Vertices = GeomForm_Vertices,
  456.                            Edges = GeomForm_Edges,
  457.                            Surface = GeomForm_Surface,
  458.                            Volume = GeomForm_Volume
  459.                            )
  460.  
  461. class CFeatureLocationGeometry : public CParticleFeature
  462. {
  463. public:
  464.         CRY_PFX2_DECLARE_FEATURE
  465.  
  466.         CFeatureLocationGeometry()
  467.                 : m_offset(0.0f)
  468.                 , m_velocity(0.0f)
  469.                 , m_source(EGeometrySource::Render)
  470.                 , m_location(EGeometryLocation::Surface)
  471.                 , m_orientToNormal(false) {}
  472.  
  473.         virtual void AddToComponent(CParticleComponent* pComponent, SComponentParams* pParams) override
  474.         {
  475.                 pComponent->AddToUpdateList(EUL_MainPreUpdate, this);
  476.                 pComponent->AddToUpdateList(EUL_GetExtents, this);
  477.                 m_offset.AddToComponent(pComponent, this);
  478.                 m_velocity.AddToComponent(pComponent, this);
  479.                 if (m_orientToNormal)
  480.                         pComponent->AddParticleData(EPQF_Orientation);
  481.  
  482.                 if (CParticleComponent* pParentComponent = pComponent->GetParentComponent())
  483.                 {
  484.                         if (IMeshObj* pMesh = pParentComponent->GetComponentParams().m_pMesh)
  485.                                 pMesh->GetExtent((EGeomForm)m_location);
  486.                 }
  487.         }
  488.  
  489.         virtual void Serialize(Serialization::IArchive& ar) override
  490.         {
  491.                 CParticleFeature::Serialize(ar);
  492.                 ar(m_source, "Source", "Source");
  493.                 ar(m_location, "Location", "Location");
  494.                 ar(m_offset, "Offset", "Offset");
  495.                 ar(m_velocity, "Velocity", "Velocity");
  496.                 ar(m_orientToNormal, "OrientParticles", "Orient Particles");
  497.         }
  498.  
  499.         virtual void MainPreUpdate(CParticleComponentRuntime* pComponentRuntime) override
  500.         {
  501.                 CRY_PROFILE_FUNCTION(PROFILE_PARTICLE);
  502.  
  503.                 if (CParticleEmitter* pEmitter = pComponentRuntime->GetEmitter())
  504.                 {
  505.                         pEmitter->UpdateEmitGeomFromEntity();
  506.                         const GeomRef& emitterGeometry = pEmitter->GetEmitterGeometry();
  507.                         const EGeomType geomType = (EGeomType)m_source;
  508.                         const EGeomForm geomForm = (EGeomForm)m_location;
  509.                         emitterGeometry.GetExtent(geomType, geomForm);
  510.                 }
  511.         }
  512.  
  513.         virtual void InitParticles(const SUpdateContext& context) override
  514.         {
  515.                 CRY_PROFILE_FUNCTION(PROFILE_PARTICLE);
  516.  
  517.                 const float EPSILON = 1.0f / 2048.0f;
  518.                 const bool useVelocity = abs(m_velocity.GetBaseValue()) > EPSILON;
  519.  
  520.                 if (useVelocity)
  521.                         SampleGeometry<true>(context);
  522.                 else
  523.                         SampleGeometry<false>(context);
  524.         }
  525.  
  526.         virtual void GetSpatialExtents(const SUpdateContext& context, Array<const float, uint> scales, Array<float, uint> extents) override
  527.         {
  528.                 if (CParticleEmitter* pEmitter = context.m_runtime.GetEmitter())
  529.                 {
  530.                         GeomRef emitterGeometry = pEmitter->GetEmitterGeometry();
  531.                         if (CParticleComponent* pParentComponent = context.m_runtime.GetComponent()->GetParentComponent())
  532.                         {
  533.                                 if (IMeshObj* pMesh = pParentComponent->GetComponentParams().m_pMesh)
  534.                                         emitterGeometry.Set(pMesh);
  535.                         }
  536.                         const bool hasParentParticles = context.m_params.m_parentId != gInvalidId;
  537.                         const TIStream<IMeshObj*> parentMeshes = context.m_parentContainer.GetTIStream<IMeshObj*>(EPDT_MeshGeometry, emitterGeometry.m_pMeshObj);
  538.                         const TIStream<IPhysicalEntity*> parentPhysics = context.m_parentContainer.GetTIStream<IPhysicalEntity*>(EPDT_PhysicalEntity);
  539.  
  540.                         size_t numInstances = context.m_runtime.GetNumInstances();
  541.                         for (size_t i = 0; i < numInstances; ++i)
  542.                         {
  543.                                 if (hasParentParticles)
  544.                                 {
  545.                                         TParticleId parentId = context.m_runtime.GetInstance(i).m_parentId;
  546.                                         if (IMeshObj* mesh = parentMeshes.Load(parentId))
  547.                                                 emitterGeometry.Set(mesh);
  548.                                         if (m_source == EGeometrySource::Physics)
  549.                                         {
  550.                                                 if (IPhysicalEntity* pPhysics = parentPhysics.Load(parentId))
  551.                                                         emitterGeometry.Set(pPhysics);
  552.                                         }
  553.                                 }
  554.                                 float extent = emitterGeometry.GetExtent((EGeomType)m_source, (EGeomForm)m_location);
  555.                                 for (int dim = (int)m_location; dim > 0; --dim)
  556.                                         extent *= scales[i];
  557.                                 extents[i] += extent;
  558.                         }
  559.                 }
  560.         }
  561.  
  562. private:
  563.         template<const bool UseVelocity>
  564.         ILINE void SampleGeometry(const SUpdateContext& context)
  565.         {
  566.                 if (m_orientToNormal)
  567.                         SampleGeometry<UseVelocity, true>(context);
  568.                 else
  569.                         SampleGeometry<UseVelocity, false>(context);
  570.         }
  571.  
  572.         template<const bool UseVelocity, const bool OrientToNormal>
  573.         void SampleGeometry(const SUpdateContext& context)
  574.         {
  575.                 const CParticleEmitter* pEmitter = context.m_runtime.GetEmitter();
  576.                 const CParticleComponent* pParentComponent = context.m_runtime.GetComponent()->GetParentComponent();
  577.  
  578.                 GeomRef emitterGeometry = pEmitter->GetEmitterGeometry();
  579.                 bool geometryCentered = false;
  580.                 if (pParentComponent)
  581.                 {
  582.                         IMeshObj* pMesh = pParentComponent->GetComponentParams().m_pMesh;
  583.                         if (pMesh)
  584.                                 emitterGeometry.Set(pMesh);
  585.                         geometryCentered = pParentComponent->GetComponentParams().m_meshCentered;
  586.                 }
  587.                 if (!emitterGeometry)
  588.                         return;
  589.  
  590.                 const EGeomType geomType = (EGeomType)m_source;
  591.                 const EGeomForm geomForm = (EGeomForm)m_location;
  592.                 QuatTS geomLocation = pEmitter->GetEmitterGeometryLocation();
  593.                 CParticleContainer& container = context.m_container;
  594.                 const CParticleContainer& parentContainer = context.m_parentContainer;
  595.                 const IPidStream parentIds = container.GetIPidStream(EPDT_ParentId);
  596.                 const IVec3Stream parentPositions = parentContainer.GetIVec3Stream(EPVF_Position, geomLocation.t);
  597.                 const IQuatStream parentQuats = parentContainer.GetIQuatStream(EPQF_Orientation, geomLocation.q);
  598.                 const TIStream<IMeshObj*> parentMeshes = parentContainer.GetTIStream<IMeshObj*>(EPDT_MeshGeometry, emitterGeometry.m_pMeshObj);
  599.                 const TIStream<IPhysicalEntity*> parentPhysics = parentContainer.GetTIStream<IPhysicalEntity*>(EPDT_PhysicalEntity);
  600.                 IOVec3Stream positions = container.GetIOVec3Stream(EPVF_Position);
  601.                 IOVec3Stream velocities = container.GetIOVec3Stream(EPVF_Velocity);
  602.                 IOQuatStream orientations = container.GetIOQuatStream(EPQF_Orientation);
  603.                 const bool hasParentParticles = context.m_params.m_parentId != gInvalidId;
  604.  
  605.                 STempModBuffer offsets(context, m_offset);
  606.                 STempModBuffer velocityMults(context, m_velocity);
  607.                 offsets.ModifyInit(context, m_offset, container.GetSpawnedRange());
  608.                 velocityMults.ModifyInit(context, m_velocity, container.GetSpawnedRange());
  609.  
  610.                 CRY_PFX2_FOR_SPAWNED_PARTICLES(context)
  611.                 {
  612.                         if (hasParentParticles)
  613.                         {
  614.                                 TParticleId parentId = parentIds.Load(particleId);
  615.                                 geomLocation.t = parentPositions.SafeLoad(parentId);
  616.                                 geomLocation.q = parentQuats.SafeLoad(parentId);
  617.                                 if (IMeshObj* mesh = parentMeshes.Load(parentId))
  618.                                         emitterGeometry.Set(mesh);
  619.                                 if (m_source == EGeometrySource::Physics)
  620.                                 {
  621.                                         if (IPhysicalEntity* pPhysics = parentPhysics.Load(parentId))
  622.                                                 emitterGeometry.Set(pPhysics);
  623.                                 }
  624.                         }
  625.  
  626.                         CRndGen rng(context.m_spawnRng.Rand());
  627.                         PosNorm randPositionNormal;
  628.                         emitterGeometry.GetRandomPos(
  629.                           randPositionNormal, rng, geomType, geomForm,
  630.                           geomLocation, geometryCentered);
  631.  
  632.                         const float offset = offsets.m_stream.SafeLoad(particleId);
  633.                         const Vec3 wPosition = randPositionNormal.vPos + randPositionNormal.vNorm * offset;
  634.                         positions.Store(particleId, wPosition);
  635.  
  636.                         if (UseVelocity)
  637.                         {
  638.                                 const float velocityMult = velocityMults.m_stream.SafeLoad(particleId);
  639.                                 const Vec3 wVelocity0 = velocities.Load(particleId);
  640.                                 const Vec3 wVelocity1 = wVelocity0 + randPositionNormal.vNorm * velocityMult;
  641.                                 velocities.Store(particleId, wVelocity1);
  642.                         }
  643.  
  644.                         if (OrientToNormal)
  645.                         {
  646.                                 const Quat wOrient0 = orientations.Load(particleId);
  647.                                 const Quat oOrient = Quat::CreateRotationV0V1(randPositionNormal.vNorm, Vec3(0.0f, 0.0f, 1.0f));
  648.                                 const Quat wOrient1 = wOrient0 * oOrient;
  649.                                 orientations.Store(particleId, wOrient1);
  650.                         }
  651.                 }
  652.                 CRY_PFX2_FOR_END;
  653.         }
  654.  
  655.         CParamMod<SModParticleSpawnInit, SFloat10> m_offset;
  656.         CParamMod<SModParticleSpawnInit, SFloat10> m_velocity;
  657.         EGeometrySource                            m_source;
  658.         EGeometryLocation                          m_location;
  659.         bool m_orientToNormal;
  660. };
  661.  
  662. CRY_PFX2_IMPLEMENT_FEATURE(CParticleFeature, CFeatureLocationGeometry, "Location", "Geometry", colorLocation);
  663.  
  664. //////////////////////////////////////////////////////////////////////////
  665. // CFeatureLocationNoise
  666.  
  667. class CFeatureLocationNoise : public CParticleFeature
  668. {
  669. private:
  670.         typedef TValue<uint, THardLimits<1, 6>> UIntOctaves;
  671.  
  672. public:
  673.         CRY_PFX2_DECLARE_FEATURE
  674.  
  675.         CFeatureLocationNoise()
  676.                 : m_amplitude(1.0f)
  677.                 , m_size(1.0f)
  678.                 , m_rate(0.0f)
  679.                 , m_octaves(1)
  680.                 , CParticleFeature(gpu_pfx2::eGpuFeatureType_LocationNoise) {}
  681.  
  682.         virtual void AddToComponent(CParticleComponent* pComponent, SComponentParams* pParams) override
  683.         {
  684.                 pComponent->AddToUpdateList(EUL_InitUpdate, this);
  685.                 m_amplitude.AddToComponent(pComponent, this);
  686.                 if (auto pInt = GetGpuInterface())
  687.                 {
  688.                         gpu_pfx2::SFeatureParametersLocationNoise params;
  689.                         params.amplitude = m_amplitude.GetBaseValue();
  690.                         params.size = m_size;
  691.                         params.rate = m_rate;
  692.                         params.octaves = m_octaves;
  693.                         pInt->SetParameters(params);
  694.                 }
  695.         }
  696.  
  697.         virtual void Serialize(Serialization::IArchive& ar) override
  698.         {
  699.                 CParticleFeature::Serialize(ar);
  700.                 ar(m_amplitude, "Amplitude", "Amplitude");
  701.                 ar(m_size, "Size", "Size");
  702.                 ar(m_rate, "Rate", "Rate");
  703.                 ar(m_octaves, "Octaves", "Octaves");
  704.         }
  705.  
  706.         virtual void InitParticles(const SUpdateContext& context) override
  707.         {
  708.                 CRY_PROFILE_FUNCTION(PROFILE_PARTICLE);
  709.  
  710.                 const float deltaTime = context.m_deltaTime;
  711.                 const float maxSize = (float)(1 << 12);
  712.                 const float minSize = rcp_fast(maxSize); // small enough and prevents SIMD exceptions
  713.                 const float time = mod(context.m_time * m_rate * minSize, 1.0f) * maxSize;
  714.                 const float invSize = rcp_fast(max(minSize, +m_size));
  715.                 CParticleContainer& container = context.m_container;
  716.                 const IFStream ages = container.GetIFStream(EPDT_NormalAge);
  717.                 IOVec3Stream positions = container.GetIOVec3Stream(EPVF_Position);
  718.  
  719.                 STempModBuffer sizes(context, m_amplitude);
  720.                 sizes.ModifyInit(context, m_amplitude, container.GetSpawnedRange());
  721.  
  722.                 CRY_PFX2_FOR_SPAWNED_PARTICLES(context)
  723.                 {
  724.                         const float amplitude = sizes.m_stream.SafeLoad(particleId);
  725.                         const Vec3 wPosition0 = positions.Load(particleId);
  726.                         const float age = ages.Load(particleId);
  727.                         Vec4 sample;
  728.                         sample.x = wPosition0.x * invSize;
  729.                         sample.y = wPosition0.y * invSize;
  730.                         sample.z = wPosition0.z * invSize;
  731.                         sample.w = MAdd(DeltaTime(age, deltaTime), m_rate, time);
  732.                         const Vec3 potential = Fractal(sample, m_octaves);
  733.                         const Vec3 wPosition1 = potential * amplitude + wPosition0;
  734.                         positions.Store(particleId, wPosition1);
  735.                 }
  736.                 CRY_PFX2_FOR_END;
  737.         }
  738.  
  739. private:
  740.         ILINE static Vec3 Potential(const Vec4 sample)
  741.         {
  742.                 const Vec4 offy = Vec4(149, 311, 191, 491);
  743.                 const Vec4 offz = Vec4(233, 197, 43, 59);
  744.                 const Vec3 potential = Vec3(
  745.                   SNoise(sample),
  746.                   SNoise(sample + offy),
  747.                   SNoise(sample + offz));
  748.                 return potential;
  749.         }
  750.  
  751.         ILINE static Vec3 Fractal(const Vec4 sample, const uint octaves)
  752.         {
  753.                 Vec3 total = Vec3(ZERO);
  754.                 float mult = 1.0f;
  755.                 float totalMult = 0.0f;
  756.                 for (uint i = 0; i < octaves; ++i)
  757.                 {
  758.                         totalMult += mult;
  759.                         mult *= 0.5f;
  760.                 }
  761.                 mult = __fres(totalMult);
  762.                 float size = 1.0f;
  763.                 for (uint i = 0; i < octaves; ++i)
  764.                 {
  765.                         total += Potential(sample * size) * mult;
  766.                         size *= 2.0f;
  767.                         mult *= 0.5f;
  768.                 }
  769.                 return total;
  770.         }
  771.  
  772.         CParamMod<SModParticleSpawnInit, SFloat10> m_amplitude;
  773.         UFloat10    m_size;
  774.         UFloat10    m_rate;
  775.         UIntOctaves m_octaves;
  776. };
  777.  
  778. CRY_PFX2_IMPLEMENT_FEATURE(CParticleFeature, CFeatureLocationNoise, "Location", "Noise", colorLocation);
  779.  
  780. //////////////////////////////////////////////////////////////////////////
  781. // CFeatureLocationBeam
  782.  
  783. class CFeatureLocationBeam : public CParticleFeature
  784. {
  785. public:
  786.         CRY_PFX2_DECLARE_FEATURE
  787.  
  788.         CFeatureLocationBeam()
  789.                 : m_source(ETargetSource::Parent)
  790.                 , m_destination(ETargetSource::Target) {}
  791.  
  792.         virtual void AddToComponent(CParticleComponent* pComponent, SComponentParams* pParams) override
  793.         {
  794.                 pComponent->AddToUpdateList(EUL_InitUpdate, this);
  795.                 pComponent->AddToUpdateList(EUL_GetExtents, this);
  796.                 pComponent->AddParticleData(EPDT_SpawnFraction);
  797.         }
  798.  
  799.         virtual void Serialize(Serialization::IArchive& ar) override
  800.         {
  801.                 CParticleFeature::Serialize(ar);
  802.                 ar(m_source, "Source", "Source");
  803.                 if (ar.isInput() && GetVersion(ar) <= 5)
  804.                         ar(m_destination, "Destiny", "Destination");
  805.                 ar(m_destination, "Destination", "Destination");
  806.         }
  807.  
  808.         virtual void InitParticles(const SUpdateContext& context) override
  809.         {
  810.                 CRY_PROFILE_FUNCTION(PROFILE_PARTICLE);
  811.  
  812.                 CParticleContainer& parentContainer = context.m_parentContainer;
  813.                 CParticleContainer& container = context.m_container;
  814.                 const Quat defaultQuat = context.m_runtime.GetEmitter()->GetLocation().q;
  815.                 IPidStream parentIds = container.GetIPidStream(EPDT_ParentId);
  816.                 IQuatStream parentQuats = parentContainer.GetIQuatStream(EPQF_Orientation, defaultQuat);
  817.                 const IFStream fractions = container.GetIFStream(EPDT_SpawnFraction);
  818.                 IOVec3Stream positions = container.GetIOVec3Stream(EPVF_Position);
  819.  
  820.                 CRY_PFX2_FOR_SPAWNED_PARTICLES(context)
  821.                 {
  822.                         const Vec3 wSource = m_source.GetTarget(context, particleId);
  823.                         const Vec3 wDestination = m_destination.GetTarget(context, particleId);
  824.                         const float fraction = fractions.SafeLoad(particleId);
  825.                         const Vec3 wPosition = wSource + (wDestination - wSource) * fraction;
  826.                         positions.Store(particleId, wPosition);
  827.                 }
  828.                 CRY_PFX2_FOR_END;
  829.         }
  830.  
  831.         virtual void GetSpatialExtents(const SUpdateContext& context, Array<const float, uint> scales, Array<float, uint> extents) override
  832.         {
  833.                 size_t numInstances = context.m_runtime.GetNumInstances();
  834.                 for (size_t i = 0; i < numInstances; ++i)
  835.                 {
  836.                         TParticleId parentId = context.m_runtime.GetInstance(i).m_parentId;
  837.                         const Vec3 wSource = m_source.GetTarget(context, parentId, true);
  838.                         const Vec3 wDestination = m_destination.GetTarget(context, parentId, true);
  839.                         extents[i] += (wSource - wDestination).GetLengthFast() * scales[i];
  840.                 }
  841.         }
  842.  
  843. private:
  844.         CTargetSource m_source;
  845.         CTargetSource m_destination;
  846. };
  847.  
  848. CRY_PFX2_IMPLEMENT_FEATURE(CParticleFeature, CFeatureLocationBeam, "Location", "Beam", colorLocation);
  849.  
  850. //////////////////////////////////////////////////////////////////////////
  851. // CFeatureLocationcamera
  852.  
  853. class CFeatureLocationBindToCamera : public CParticleFeature
  854. {
  855. public:
  856.         CRY_PFX2_DECLARE_FEATURE
  857.  
  858.         CFeatureLocationBindToCamera()
  859.                 : m_spawnOnly(false) {}
  860.  
  861.         virtual void AddToComponent(CParticleComponent* pComponent, SComponentParams* pParams) override
  862.         {
  863.                 pComponent->AddToUpdateList(EUL_PostInitUpdate, this);
  864.                 if (!m_spawnOnly)
  865.                         pComponent->AddToUpdateList(EUL_PreUpdate, this);
  866.         }
  867.  
  868.         virtual void Serialize(Serialization::IArchive& ar) override
  869.         {
  870.                 CParticleFeature::Serialize(ar);
  871.                 ar(m_spawnOnly, "SpawnOnly", "Spawn Only");
  872.         }
  873.  
  874.         virtual void PostInitParticles(const SUpdateContext& context) override
  875.         {
  876.                 CRY_PFX2_PROFILE_DETAIL;
  877.  
  878.                 const CCamera& camera = gEnv->p3DEngine->GetRenderingCamera();
  879.                 const QuatT wCameraPose = QuatT(camera.GetMatrix());
  880.  
  881.                 CParticleContainer& container = context.m_container;
  882.                 const CParticleContainer& parentContainer = context.m_parentContainer;
  883.                 const IPidStream parentIds = container.GetIPidStream(EPDT_ParentId);
  884.                 const IVec3Stream parentPositions = parentContainer.GetIVec3Stream(EPVF_Position);
  885.                 const IQuatStream parentOrientations = parentContainer.GetIQuatStream(EPQF_Orientation);
  886.                 IOVec3Stream positions = container.GetIOVec3Stream(EPVF_Position);
  887.                 IOVec3Stream velocities = container.GetIOVec3Stream(EPVF_Velocity);
  888.  
  889.                 CRY_PFX2_FOR_SPAWNED_PARTICLES(context)
  890.                 {
  891.                         const TParticleId parentId = parentIds.Load(particleId);
  892.                         const Vec3 wParentPosition = parentPositions.Load(parentId);
  893.                         const Quat wParentOrientation = parentOrientations.Load(parentId);
  894.                         const QuatT worldToParent = QuatT(wParentPosition, wParentOrientation).GetInverted();
  895.  
  896.                         const Vec3 wPosition0 = positions.Load(particleId);
  897.                         const Vec3 wPosition1 = wCameraPose * (worldToParent * wPosition0);
  898.                         positions.Store(particleId, wPosition1);
  899.  
  900.                         const Vec3 wVelocity0 = velocities.Load(particleId);
  901.                         const Vec3 wVelocity1 = wCameraPose.q * (worldToParent.q * wVelocity0);
  902.                         velocities.Store(particleId, wVelocity1);
  903.                 }
  904.                 CRY_PFX2_FOR_END;
  905.         }
  906.  
  907.         virtual void PreUpdate(const SUpdateContext& context) override
  908.         {
  909.                 CRY_PFX2_PROFILE_DETAIL;
  910.  
  911.                 const CCamera& camera = gEnv->p3DEngine->GetRenderingCamera();
  912.                 const QuatT wCameraPose = QuatT(camera.GetMatrix());
  913.                 const QuatT cameraMotion = GetPSystem()->GetCameraMotion();
  914.  
  915.                 CParticleContainer& container = context.m_container;
  916.                 const CParticleContainer& parentContainer = context.m_parentContainer;
  917.                 const IPidStream parentIds = container.GetIPidStream(EPDT_ParentId);
  918.                 const IVec3Stream parentPositions = parentContainer.GetIVec3Stream(EPVF_Position);
  919.                 IOVec3Stream positions = container.GetIOVec3Stream(EPVF_Position);
  920.                 IOVec3Stream velocities = container.GetIOVec3Stream(EPVF_Velocity);
  921.  
  922.                 CRY_PFX2_FOR_ACTIVE_PARTICLES(context)
  923.                 {
  924.                         const Vec3 wPosition0 = positions.Load(particleId);
  925.                         const Vec3 cPosition0 = wPosition0 - wCameraPose.t;
  926.                         const Vec3 cPosition1 = cameraMotion.q * cPosition0 + cameraMotion.t;
  927.                         const Vec3 wPosition1 = cPosition1 + wCameraPose.t;
  928.                         positions.Store(particleId, wPosition1);
  929.  
  930.                         const Vec3 wVelocity0 = velocities.Load(particleId);
  931.                         const Vec3 wVelocity1 = cameraMotion.q * wVelocity0;
  932.                         velocities.Store(particleId, wVelocity1);
  933.                 }
  934.                 CRY_PFX2_FOR_END;
  935.         }
  936.  
  937. private:
  938.         bool m_spawnOnly;
  939. };
  940.  
  941. CRY_PFX2_IMPLEMENT_FEATURE(CParticleFeature, CFeatureLocationBindToCamera, "Location", "BindToCamera", colorLocation);
  942.  
  943. //////////////////////////////////////////////////////////////////////////
  944. // CFeatureLocationOmni
  945.  
  946. namespace
  947. {
  948. // Box
  949. ILINE Vec3 RandomPosZBox(SChaosKey& chaosKey)
  950. {
  951.         return Vec3(chaosKey.RandSNorm(), chaosKey.RandSNorm(), chaosKey.RandUNorm());
  952. }
  953.  
  954. ILINE bool WrapPosZBox(Vec3& pos)
  955. {
  956.         Vec3 pos0 = pos;
  957.         pos.x -= std::floor(pos.x * 0.5f + 0.5f) * 2.0f;
  958.         pos.y -= std::floor(pos.y * 0.5f + 0.5f) * 2.0f;
  959.         pos.z -= std::floor(pos.z);
  960.         return pos != pos0;
  961. }
  962.  
  963. // Sector
  964. ILINE bool InPosZSector(const Vec3& pos, Vec2 scrWidth, float epsilon = 0.0f)
  965. {
  966.         return abs(pos.x) <= pos.z * scrWidth.x + epsilon
  967.                && abs(pos.y) <= pos.z * scrWidth.y + epsilon;
  968. }
  969.  
  970. ILINE bool InUnitZSector(const Vec3& pos, Vec2 scrWidth, float epsilon = 0.0f)
  971. {
  972.         return InPosZSector(pos, scrWidth, epsilon)
  973.                && pos.GetLengthSquared() <= 1.0f + epsilon * 2.0f;
  974. }
  975.  
  976. ILINE Vec3 RandomUnitZSector(SChaosKey& chaosKey, Vec2 scrWidth)
  977. {
  978.         Vec3 pos(chaosKey.RandSNorm() * scrWidth.x, chaosKey.RandSNorm() * scrWidth.y, chaosKey.RandUNorm());
  979.         float r = pow(pos.z, 0.333333f);
  980.         pos.z = 1.0f;
  981.         pos *= r * rsqrt_fast(pos.GetLengthSquared());
  982.         assert(InUnitZSector(pos, scrWidth, 0.0001f));
  983.         return pos;
  984. }
  985.  
  986. void WrapUnitZSector(Vec3& pos, const Vec3& posPrev, Vec2 scrWidth)
  987. {
  988.         Vec3 delta = posPrev - pos;
  989.  
  990.         float maxMoveIn = 0.0f;
  991.         float minMoveOut = std::numeric_limits<float>::max();
  992.  
  993.         // (P + D t) | N = 0
  994.         // t = -P|N / D|N     ; N unnormalized
  995.         auto GetPlaneDists = [&](float px, float py, float pz)
  996.         {
  997.                 float dist = px * pos.x + py * pos.y + pz * pos.z;
  998.                 float dot = -(px * delta.x + py * delta.y + pz * delta.z);
  999.  
  1000.                 if (dist > 0.0f && dot > 0.0f && dist > dot * maxMoveIn)
  1001.                         maxMoveIn = dist / dot;
  1002.                 else if (dot < 0.0f && dist > dot * minMoveOut)
  1003.                         minMoveOut = dist / dot;
  1004.         };
  1005.  
  1006.         GetPlaneDists(+1, 0, -scrWidth.x);
  1007.         GetPlaneDists(-1, 0, -scrWidth.x);
  1008.         GetPlaneDists(0, +1, -scrWidth.y);
  1009.         GetPlaneDists(0, -1, -scrWidth.y);
  1010.  
  1011.         // Wrap into sphere
  1012.         // r^2 = (P + D t)^2 = 1
  1013.         // P*P + P*D 2t + D*D t^2 = 1
  1014.         // r^2\t = 2 P*D 2 + 2 D*D t
  1015.         float dists[2];
  1016.         float dd = delta | delta, dp = delta | pos, pp = pos | pos;
  1017.         int n = solve_quadratic(dd, dp * 2.0f, pp - 1.0f, dists);
  1018.         while (--n >= 0)
  1019.         {
  1020.                 float dr = dp + dd * dists[n];
  1021.                 if (dr < 0.0f)
  1022.                         maxMoveIn = max(maxMoveIn, dists[n]);
  1023.                 else if (dists[n] > 0.0f)
  1024.                         minMoveOut = min(minMoveOut, dists[n]);
  1025.         }
  1026.  
  1027.         if (maxMoveIn > 0.0f)
  1028.         {
  1029.                 const float moveDist = (minMoveOut - maxMoveIn) * trunc(minMoveOut / (minMoveOut - maxMoveIn));
  1030.                 if (moveDist < 1e6f)
  1031.                         pos += delta * moveDist;
  1032.         }
  1033.         assert(InUnitZSector(pos, scrWidth, 0.001f));
  1034. }
  1035.  
  1036. CRY_UNIT_TEST(WrapSectorTest)
  1037. {
  1038.         SChaosKey chaosKey(0u);
  1039.         for (int i = 0; i < 100; ++i)
  1040.         {
  1041.                 Vec2 scrWidth(chaosKey.Rand(SChaosKey::Range(0.1f, 3.0f)), chaosKey.Rand(SChaosKey::Range(0.1f, 3.0f)));
  1042.                 Vec3 pos = RandomUnitZSector(chaosKey, scrWidth);
  1043.                 Vec3 pos2 = pos + chaosKey.RandSphere();
  1044.                 if (!InUnitZSector(pos2, scrWidth))
  1045.                 {
  1046.                         Vec3 pos3 = pos2;
  1047.                         WrapUnitZSector(pos3, pos, scrWidth);
  1048.                 }
  1049.         }
  1050. };
  1051.  
  1052. template<int A>
  1053. ILINE void RotateZ(Vec3& pos, float s, float c)
  1054. {
  1055.         float z = c * pos.z + s * pos[A];
  1056.         pos[A] = c * pos[A] - s * pos.z;
  1057.         pos.z = z;
  1058. }
  1059.  
  1060. template<int A>
  1061. ILINE bool WrapRotation(Vec3& pos, Vec3& posPrev, Vec3& posRot, Vec2 scrWidth)
  1062. {
  1063.         if (abs(posRot[A]) > posRot.z * scrWidth[A])
  1064.         {
  1065.                 float angScr = atan(scrWidth[A]);
  1066.                 float ang = atan2(abs(posRot[A]), posRot.z);
  1067.                 float angRot = (angScr + angScr) * trunc((angScr + ang) / (angScr + angScr)) * fsgnf(posRot[A]);
  1068.                 float s, c;
  1069.                 sincos(angRot, &s, &c);
  1070.                 RotateZ<A>(posRot, s, c);
  1071.                 posPrev = posRot;
  1072.                 RotateZ<A>(pos, s, c);
  1073.                 return true;
  1074.         }
  1075.         return false;
  1076. }
  1077.  
  1078. ILINE int WrapRotation(Vec3& pos, Vec3& posPrev, const Matrix33& camRot, Vec2 scrWidth)
  1079. {
  1080.         Vec3 posRot = camRot * posPrev;
  1081.         int wrapped = WrapRotation<0>(pos, posPrev, posRot, scrWidth)
  1082.                       + WrapRotation<1>(pos, posPrev, posRot, scrWidth);
  1083.         assert(InPosZSector(posRot, scrWidth, 0.001f));
  1084.         return wrapped;
  1085. }
  1086.  
  1087. CRY_UNIT_TEST(WrapRotationTest)
  1088. {
  1089.         SChaosKey chaosKey(0u);
  1090.         for (int i = 0; i < 100; ++i)
  1091.         {
  1092.                 Vec2 scrWidth(chaosKey.Rand(SChaosKey::Range(0.1f, 3.0f)), chaosKey.Rand(SChaosKey::Range(0.1f, 3.0f)));
  1093.                 Vec3 pos = RandomUnitZSector(chaosKey, scrWidth);
  1094.                 if (i % 4 == 0)
  1095.                         pos.x = 0;
  1096.                 else if (i % 4 == 1)
  1097.                         pos.y = 0;
  1098.                 AngleAxis rot;
  1099.                 rot.axis = i % 4 == 0 ? Vec3(1, 0, 0) : i % 4 == 1 ? Vec3(0, 1, 0) : Vec3(chaosKey.RandCircle());
  1100.                 rot.angle = chaosKey.RandUNorm() * gf_PI;
  1101.                 Vec3 pos2 = AngleAxis(-rot.angle, rot.axis) * pos;
  1102.                 if (!InPosZSector(pos2, scrWidth))
  1103.                 {
  1104.                         Vec3 pos1 = pos;
  1105.                         Vec3 pos3 = pos2;
  1106.                         WrapRotation(pos3, pos1, Matrix33::CreateRotationAA(-rot.angle, rot.axis), scrWidth);
  1107.                 }
  1108.         }
  1109. };
  1110. }
  1111.  
  1112. EParticleDataType PDT(EPVF_AuxPosition, float, 3);
  1113.  
  1114. class CFeatureLocationOmni : public CParticleFeature
  1115. {
  1116. public:
  1117.         CRY_PFX2_DECLARE_FEATURE
  1118.  
  1119.         virtual void AddToComponent(CParticleComponent* pComponent, SComponentParams* pParams) override
  1120.         {
  1121.                 pComponent->AddParticleData(EPVF_AuxPosition);
  1122.                 pComponent->AddToUpdateList(EUL_GetExtents, this);
  1123.                 pComponent->AddToUpdateList(EUL_InitUpdate, this);
  1124.                 pComponent->AddToUpdateList(EUL_Update, this);
  1125.                 m_visibility.AddToComponent(pComponent, this);
  1126.         }
  1127.  
  1128.         virtual void Serialize(Serialization::IArchive& ar) override
  1129.         {
  1130.                 CParticleFeature::Serialize(ar);
  1131.                 SERIALIZE_VAR(ar, m_visibility);
  1132.                 SERIALIZE_VAR(ar, m_wrapSector);
  1133.                 SERIALIZE_VAR(ar, m_wrapRotation);
  1134.                 SERIALIZE_VAR(ar, m_useEmitterLocation);
  1135.         }
  1136.  
  1137.         virtual void GetSpatialExtents(const SUpdateContext& context, Array<const float, uint> scales, Array<float, uint> extents) override
  1138.         {
  1139.                 UpdateCameraData(context);
  1140.                 const float visibility = m_visibility.GetValueRange(context).end;
  1141.                 const size_t numInstances = context.m_runtime.GetNumInstances();
  1142.                 for (size_t i = 0; i < numInstances; ++i)
  1143.                 {
  1144.                         const Vec3 box = Vec3(m_camData.scrWidth.x, m_camData.scrWidth.y, 1.0f) * (visibility * scales[i]);
  1145.                         float extent = (box.x * 2.0f + 1.0f) * (box.y * 2.0f + 1.0f) * (box.z + 1.0f);
  1146.                         if (m_wrapSector)
  1147.                                 extent *= 0.25f;
  1148.                         extents[i] += extent;
  1149.                 }
  1150.         }
  1151.  
  1152.         virtual void InitParticles(const SUpdateContext& context) override
  1153.         {
  1154.                 CRY_PFX2_PROFILE_DETAIL;
  1155.  
  1156.                 CParticleContainer& container = context.m_container;
  1157.                 CParticleComponentRuntime& runtime = context.m_runtime;
  1158.  
  1159.                 IOVec3Stream positions = container.GetIOVec3Stream(EPVF_Position);
  1160.                 IOVec3Stream auxPositions = container.GetIOVec3Stream(EPVF_AuxPosition);
  1161.  
  1162.                 UpdateCameraData(context);
  1163.  
  1164.                 CRY_PFX2_FOR_SPAWNED_PARTICLES(context)
  1165.                 {
  1166.                         // Overwrite position
  1167.                         Vec3 pos;
  1168.                         if (m_wrapSector)
  1169.                         {
  1170.                                 pos = RandomUnitZSector(context.m_spawnRng, m_camData.scrWidth);
  1171.                                 auxPositions.Store(particleId, pos);   // in unit-camera space
  1172.                         }
  1173.                         else
  1174.                         {
  1175.                                 pos = RandomPosZBox(context.m_spawnRng);
  1176.                         }
  1177.                         pos = m_camData.toWorld * pos;
  1178.                         positions.Store(particleId, pos);
  1179.                 }
  1180.                 CRY_PFX2_FOR_END;
  1181.         }
  1182.  
  1183.         virtual void Update(const SUpdateContext& context) override
  1184.         {
  1185.                 CRY_PFX2_PROFILE_DETAIL;
  1186.  
  1187.                 CParticleContainer& container = context.m_container;
  1188.                 CParticleComponentRuntime& runtime = context.m_runtime;
  1189.  
  1190.                 IOVec3Stream positions = container.GetIOVec3Stream(EPVF_Position);
  1191.                 IOVec3Stream auxPositions = container.GetIOVec3Stream(EPVF_AuxPosition);
  1192.  
  1193.                 UpdateCameraData(context);
  1194.                 bool doCamRot = m_wrapRotation && m_camData.camRot.angle > 0.001f;
  1195.                 Matrix33 camMat = Matrix33::CreateRotationAA(-m_camData.camRot.angle, m_camData.camRot.axis);
  1196.  
  1197.                 // Wrap positions
  1198.                 if (m_wrapSector)
  1199.                 {
  1200.                         CRY_PFX2_FOR_ACTIVE_PARTICLES(context)
  1201.                         {
  1202.                                 Vec3 pos = positions.Load(particleId);
  1203.                                 Vec3 posCam = m_camData.fromWorld * pos;
  1204.  
  1205.                                 if (!InUnitZSector(posCam, m_camData.scrWidth /*, 0.002f*/))
  1206.                                 {
  1207.                                         Vec3 posCamPrev = auxPositions.Load(particleId);
  1208.  
  1209.                                         // Adjust for camera rotation
  1210.                                         if (doCamRot && WrapRotation(posCam, posCamPrev, camMat, m_camData.scrWidth))
  1211.                                         {
  1212.                                                 if (!InUnitZSector(posCam, m_camData.scrWidth /*, 0.002f*/))
  1213.                                                         WrapUnitZSector(posCam, posCamPrev, m_camData.scrWidth);
  1214.                                         }
  1215.                                         else
  1216.                                         {
  1217.                                                 // Adjust for translation
  1218.                                                 WrapUnitZSector(posCam, posCamPrev, m_camData.scrWidth);
  1219.                                         }
  1220.  
  1221.                                         pos = m_camData.toWorld * posCam;
  1222.                                         positions.Store(particleId, pos);
  1223.                                 }
  1224.                                 auxPositions.Store(particleId, posCam);
  1225.                         }
  1226.                         CRY_PFX2_FOR_END;
  1227.                 }
  1228.                 else
  1229.                 {
  1230.                         CRY_PFX2_FOR_ACTIVE_PARTICLES(context)
  1231.                         {
  1232.                                 Vec3 pos = positions.Load(particleId);
  1233.                                 Vec3 posCam = m_camData.fromWorld * pos;
  1234.  
  1235.                                 if (WrapPosZBox(posCam))
  1236.                                 {
  1237.                                         pos = m_camData.toWorld * posCam;
  1238.                                         positions.Store(particleId, pos);
  1239.                                 }
  1240.                         }
  1241.                         CRY_PFX2_FOR_END;
  1242.                 }
  1243.         }
  1244.  
  1245. private:
  1246.  
  1247.         struct SCameraData
  1248.         {
  1249.                 int32     nFrameId;
  1250.                 Vec2      scrWidth;
  1251.                 Matrix34  toWorld;
  1252.                 Matrix34  fromWorld;
  1253.                 AngleAxis camRot;
  1254.  
  1255.                 SCameraData()
  1256.                         : nFrameId(-1), camRot(0, Vec3(0)) {}
  1257.         };
  1258.         SCameraData m_camData;
  1259.  
  1260.         void UpdateCameraData(const SUpdateContext& context)
  1261.         {
  1262.                 if (gEnv->nMainFrameID == m_camData.nFrameId)
  1263.                         return;
  1264.                 CCamera cam = GetEffectCamera(context);
  1265.                 float visibility = m_visibility.GetValueRange(context).end;
  1266.                 m_camData.toWorld = UnitToWorld(cam, visibility, context.m_params.m_maxParticleSize);
  1267.                 if (m_camData.nFrameId != -1)
  1268.                         // Find rotation from last frame
  1269.                         m_camData.camRot = Quat(m_camData.fromWorld * m_camData.toWorld);
  1270.                 m_camData.fromWorld = m_camData.toWorld.GetInverted();
  1271.                 m_camData.scrWidth = ScreenWidth(cam);
  1272.                 m_camData.nFrameId = gEnv->nMainFrameID;
  1273.         }
  1274.  
  1275.         CCamera GetEffectCamera(const SUpdateContext& context) const
  1276.         {
  1277.                 if (!m_useEmitterLocation)
  1278.                 {
  1279.                         static CCamera camera;
  1280.                         if (!m_freezeCamera)
  1281.                                 camera = gEnv->p3DEngine->GetRenderingCamera();
  1282.                         return camera;
  1283.                 }
  1284.                 else
  1285.                 {
  1286.                         CCamera camera = gEnv->p3DEngine->GetRenderingCamera();
  1287.                         const CParticleEmitter& emitter = *context.m_runtime.GetEmitter();
  1288.                         Matrix34 matEmitter = Matrix34(emitter.GetLocation());
  1289.                         camera.SetMatrix(matEmitter);
  1290.                         return camera;
  1291.                 }
  1292.         }
  1293.  
  1294.         Matrix34 UnitToWorld(const CCamera& cam, float range, float size) const
  1295.         {
  1296.                 // Matrix rotates Z to Y, scales by range, and offsets backward by particle size
  1297.                 Vec2 scrWidth = m_wrapSector ? Vec2(1) : ScreenWidth(cam);
  1298.                 const Matrix34 toCam(
  1299.                   range * scrWidth.x, 0, 0, 0,
  1300.                   0, 0, range, -size,
  1301.                   0, -range * scrWidth.y, 0, 0
  1302.                   );
  1303.  
  1304.                 // Concatenate with camera world location
  1305.                 return cam.GetMatrix() * toCam;
  1306.         }
  1307.  
  1308.         static Vec2 ScreenWidth(const CCamera& cam)
  1309.         {
  1310.                 Vec3 corner = cam.GetEdgeF();
  1311.                 return Vec2(abs(corner.x / corner.y), abs(corner.z / corner.y));
  1312.         }
  1313.  
  1314.         CParamMod<SModEffectField, UFloat100> m_visibility;
  1315.  
  1316.         // Debugging and profiling options
  1317.         bool m_wrapSector         = true;
  1318.         bool m_wrapRotation       = true;
  1319.         bool m_useEmitterLocation = false;
  1320.         bool m_freezeCamera       = false;
  1321. };
  1322.  
  1323. CRY_PFX2_IMPLEMENT_FEATURE(CParticleFeature, CFeatureLocationOmni, "Location", "Omni", colorLocation);
  1324.  
  1325. }
  1326.  
downloadFeatureLocation.cpp Source code - Download CRYENGINE Source code
Related Source Codes/Software:
postal - 2017-06-11
reactide - Reactide is the first dedicated IDE for React web ... 2017-06-11
rkt - rkt is a pod-native container engine for Linux. It... 2017-06-11
uWebSockets - Tiny WebSockets https://for... 2017-06-11
realworld - TodoMVC for the RealWorld - Exemplary fullstack Me... 2017-06-11
CRYENGINE - CRYENGINE is a powerful real-time game development... 2017-06-11
goreplay - GoReplay is an open-source tool for capturing and ... 2017-06-10
pyenv - Simple Python version management 2017-06-10
redux-saga - An alternative side effect model for Redux apps ... 2017-06-10
angular-starter - 2017-06-10

 Back to top