emitter updates
This commit is contained in:
+45
-104
@@ -335,7 +335,6 @@ void EditorComponent::ChangeRenderPath(RENDERPATH path)
|
||||
lightWnd = new LightWindow(&GetGUI());
|
||||
animWnd = new AnimationWindow(&GetGUI());
|
||||
emitterWnd = new EmitterWindow(&GetGUI());
|
||||
emitterWnd->SetMaterialWnd(materialWnd);
|
||||
forceFieldWnd = new ForceFieldWindow(&GetGUI());
|
||||
oceanWnd = new OceanWindow(&GetGUI());
|
||||
}
|
||||
@@ -1162,27 +1161,23 @@ void EditorComponent::Update(float dt)
|
||||
}
|
||||
}
|
||||
}
|
||||
//if (pickMask & PICK_EMITTER)
|
||||
//{
|
||||
// for (auto& object : model->objects)
|
||||
// {
|
||||
// if (object->eParticleSystems.empty())
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// XMVECTOR disV = XMVector3LinePointDistance(XMLoadFloat3(&pickRay.origin), XMLoadFloat3(&pickRay.origin) + XMLoadFloat3(&pickRay.direction), XMLoadFloat3(&object->translation));
|
||||
// float dis = XMVectorGetX(disV);
|
||||
// if (dis < wiMath::Distance(object->translation, pickRay.origin) * 0.05f && dis < hovered.distance)
|
||||
// {
|
||||
// hovered.Clear();
|
||||
// hovered.transform = object;
|
||||
// hovered.object = object;
|
||||
// hovered.distance = dis;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
if (pickMask & PICK_EMITTER)
|
||||
{
|
||||
for (size_t i = 0; i < scene.emitters.GetCount(); ++i)
|
||||
{
|
||||
Entity entity = scene.emitters.GetEntity(i);
|
||||
const TransformComponent& transform = *scene.transforms.GetComponent(entity);
|
||||
|
||||
XMVECTOR disV = XMVector3LinePointDistance(XMLoadFloat3(&pickRay.origin), XMLoadFloat3(&pickRay.origin) + XMLoadFloat3(&pickRay.direction), XMLoadFloat3(&transform.translation));
|
||||
float dis = XMVectorGetX(disV);
|
||||
if (dis < wiMath::Distance(transform.translation, pickRay.origin) * 0.05f && dis < hovered.distance)
|
||||
{
|
||||
hovered.Clear();
|
||||
hovered.entity = entity;
|
||||
hovered.distance = dis;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pickMask & PICK_ENVPROBE)
|
||||
{
|
||||
for (size_t i = 0; i < scene.probes.GetCount(); ++i)
|
||||
@@ -1405,59 +1400,7 @@ void EditorComponent::Update(float dt)
|
||||
envProbeWnd->SetEntity(picked->entity);
|
||||
forceFieldWnd->SetEntity(picked->entity);
|
||||
cameraWnd->SetEntity(picked->entity);
|
||||
|
||||
//if (picked->object != nullptr)
|
||||
//{
|
||||
// meshWnd->SetMesh(picked->object->mesh);
|
||||
// if (picked->subsetIndex >= 0 && picked->subsetIndex < (int)picked->object->mesh->subsets.size())
|
||||
// {
|
||||
// Material* material = picked->object->mesh->subsets[picked->subsetIndex].material;
|
||||
|
||||
// materialWnd->SetMaterial(material);
|
||||
|
||||
// material->SetUserStencilRef(EDITORSTENCILREF_HIGHLIGHT);
|
||||
// }
|
||||
// //if (picked->object->isArmatureDeformed())
|
||||
// //{
|
||||
// // animWnd->SetArmature(picked->object->mesh->armature);
|
||||
// //}
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// meshWnd->SetMesh(nullptr);
|
||||
// materialWnd->SetMaterial(nullptr);
|
||||
// //animWnd->SetArmature(nullptr);
|
||||
//}
|
||||
|
||||
//if (picked->light != nullptr)
|
||||
//{
|
||||
//}
|
||||
//lightWnd->SetLight(picked->light);
|
||||
//if (picked->decal != nullptr)
|
||||
//{
|
||||
//}
|
||||
//decalWnd->SetDecal(picked->decal);
|
||||
//if (picked->envProbe != nullptr)
|
||||
//{
|
||||
//}
|
||||
//envProbeWnd->SetProbe(picked->envProbe);
|
||||
//forceFieldWnd->SetForceField(picked->forceField);
|
||||
//if (picked->camera != nullptr)
|
||||
//{
|
||||
// cameraWnd->SetProxy(picked->camera);
|
||||
//}
|
||||
|
||||
//if (picked->armature != nullptr)
|
||||
//{
|
||||
// animWnd->SetArmature(picked->armature);
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// animWnd->SetArmature(nullptr);
|
||||
//}
|
||||
|
||||
//objectWnd->SetObject(picked->object);
|
||||
//emitterWnd->SetObject(picked->object);
|
||||
materialWnd->SetEntity(picked->entity);
|
||||
}
|
||||
|
||||
//// Delete
|
||||
@@ -1978,41 +1921,39 @@ void EditorComponent::Compose()
|
||||
}
|
||||
}
|
||||
|
||||
//if (rendererWnd->GetPickType() & PICK_EMITTER)
|
||||
//{
|
||||
// for (auto& y : x->objects)
|
||||
// {
|
||||
// if (y->eParticleSystems.empty())
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
if (rendererWnd->GetPickType() & PICK_EMITTER)
|
||||
{
|
||||
for (size_t i = 0; i < scene.emitters.GetCount(); ++i)
|
||||
{
|
||||
Entity entity = scene.emitters.GetEntity(i);
|
||||
const TransformComponent& transform = *scene.transforms.GetComponent(entity);
|
||||
|
||||
// float dist = wiMath::Distance(y->translation, camera->translation) * 0.08f;
|
||||
float dist = wiMath::Distance(transform.translation, camera->Eye) * 0.08f;
|
||||
|
||||
// wiImageEffects fx;
|
||||
// fx.pos = y->translation;
|
||||
// fx.siz = XMFLOAT2(dist, dist);
|
||||
// fx.typeFlag = ImageType::WORLD;
|
||||
// fx.pivot = XMFLOAT2(0.5f, 0.5f);
|
||||
// fx.col = XMFLOAT4(1, 1, 1, 0.5f);
|
||||
wiImageEffects fx;
|
||||
fx.pos = transform.translation;
|
||||
fx.siz = XMFLOAT2(dist, dist);
|
||||
fx.typeFlag = ImageType::WORLD;
|
||||
fx.pivot = XMFLOAT2(0.5f, 0.5f);
|
||||
fx.col = XMFLOAT4(1, 1, 1, 0.5f);
|
||||
|
||||
// if (hovered.object == y)
|
||||
// {
|
||||
// fx.col = XMFLOAT4(1, 1, 1, 1);
|
||||
// }
|
||||
// for (auto& picked : selected)
|
||||
// {
|
||||
// if (picked->object == y)
|
||||
// {
|
||||
// fx.col = XMFLOAT4(1, 1, 0, 1);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
if (hovered.entity == entity)
|
||||
{
|
||||
fx.col = XMFLOAT4(1, 1, 1, 1);
|
||||
}
|
||||
for (auto& picked : selected)
|
||||
{
|
||||
if (picked->entity == entity)
|
||||
{
|
||||
fx.col = XMFLOAT4(1, 1, 0, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// wiImage::Draw(&emitterTex, fx, GRAPHICSTHREAD_IMMEDIATE);
|
||||
// }
|
||||
//}
|
||||
wiImage::Draw(&emitterTex, fx, GRAPHICSTHREAD_IMMEDIATE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (translator_active && translator->enabled)
|
||||
|
||||
+427
-451
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
class wiEmittedParticle;
|
||||
|
||||
class wiGUI;
|
||||
class wiWindow;
|
||||
class wiLabel;
|
||||
@@ -21,17 +19,17 @@ public:
|
||||
wiECS::Entity entity;
|
||||
void SetEntity(wiECS::Entity entity);
|
||||
|
||||
void SetMaterialWnd(MaterialWindow* wnd);
|
||||
void UpdateData();
|
||||
|
||||
wiEmittedParticle* GetEmitter();
|
||||
wiSceneSystem::wiEmittedParticle* GetEmitter();
|
||||
|
||||
wiGUI* GUI;
|
||||
MaterialWindow* materialWnd;
|
||||
|
||||
wiWindow* emitterWindow;
|
||||
|
||||
wiComboBox* emitterComboBox;
|
||||
wiButton* addButton;
|
||||
wiButton* restartButton;
|
||||
wiComboBox* meshComboBox;
|
||||
wiComboBox* shaderTypeComboBox;
|
||||
wiLabel* infoLabel;
|
||||
wiSlider* maxParticlesSlider;
|
||||
@@ -55,8 +53,6 @@ public:
|
||||
wiSlider* sph_K_Slider;
|
||||
wiSlider* sph_p0_Slider;
|
||||
wiSlider* sph_e_Slider;
|
||||
wiButton* materialSelectButton;
|
||||
wiButton* restartButton;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -133,6 +133,10 @@
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Compute</ShaderType>
|
||||
<ShaderModel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">5.0</ShaderModel>
|
||||
</FxCompile>
|
||||
<FxCompile Include="emittedparticle_emitCS_FROMMESH.hlsl">
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Compute</ShaderType>
|
||||
<ShaderModel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">5.0</ShaderModel>
|
||||
</FxCompile>
|
||||
<FxCompile Include="emittedparticle_finishUpdateCS.hlsl">
|
||||
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Compute</ShaderType>
|
||||
<ShaderModel Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">5.0</ShaderModel>
|
||||
|
||||
@@ -786,6 +786,9 @@
|
||||
<FxCompile Include="filterEnvMapCS.hlsl">
|
||||
<Filter>CS</Filter>
|
||||
</FxCompile>
|
||||
<FxCompile Include="emittedparticle_emitCS_FROMMESH.hlsl">
|
||||
<Filter>CS</Filter>
|
||||
</FxCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="PS">
|
||||
|
||||
@@ -8,8 +8,11 @@ RWSTRUCTUREDBUFFER(deadBuffer, uint, 3);
|
||||
RWRAWBUFFER(counterBuffer, 4);
|
||||
|
||||
TEXTURE2D(randomTex, float4, TEXSLOT_ONDEMAND0);
|
||||
|
||||
#ifdef EMIT_FROM_MESH
|
||||
TYPEDBUFFER(meshIndexBuffer, uint, TEXSLOT_ONDEMAND1);
|
||||
RAWBUFFER(meshVertexBuffer_POS, TEXSLOT_ONDEMAND2);
|
||||
#endif // EMIT_FROM_MESH
|
||||
|
||||
|
||||
[numthreads(THREADCOUNT_EMIT, 1, 1)]
|
||||
@@ -23,6 +26,7 @@ void main(uint3 DTid : SV_DispatchThreadID)
|
||||
|
||||
const float3 randoms = randomTex.SampleLevel(sampler_linear_wrap, float2((float)DTid.x / (float)THREADCOUNT_EMIT, g_xFrame_Time + xEmitterRandomness), 0).rgb;
|
||||
|
||||
#ifdef EMIT_FROM_MESH
|
||||
// random triangle on emitter surface:
|
||||
uint tri = (uint)(((xEmitterMeshIndexCount - 1) / 3) * randoms.x);
|
||||
|
||||
@@ -74,6 +78,14 @@ void main(uint3 DTid : SV_DispatchThreadID)
|
||||
pos = mul(xEmitterWorld, float4(pos, 1)).xyz;
|
||||
nor = normalize(mul((float3x3)xEmitterWorld, nor));
|
||||
|
||||
#else
|
||||
|
||||
// Just emit from center point:
|
||||
float3 pos = mul(xEmitterWorld, float4(0, 0, 0, 1)).xyz;
|
||||
float3 nor = 0;
|
||||
|
||||
#endif // EMIT_FROM_MESH
|
||||
|
||||
float particleStartingSize = xParticleSize + xParticleSize * (randoms.y - 0.5f) * xParticleRandomFactor;
|
||||
|
||||
// create new particle:
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
#define EMIT_FROM_MESH
|
||||
#include "emittedparticle_emitCS.hlsl"
|
||||
@@ -35,7 +35,6 @@ namespace wiECS
|
||||
components.clear();
|
||||
entities.clear();
|
||||
lookup.clear();
|
||||
dead.clear();
|
||||
}
|
||||
|
||||
// Create a new component and retrieve a reference to it:
|
||||
|
||||
+390
-598
File diff suppressed because it is too large
Load Diff
@@ -4,9 +4,14 @@
|
||||
#include "wiIntersectables.h"
|
||||
#include "ShaderInterop_EmittedParticle.h"
|
||||
#include "wiImageEffects.h"
|
||||
#include "wiSceneSystem_Decl.h"
|
||||
#include "wiECS.h"
|
||||
|
||||
class wiArchive;
|
||||
|
||||
namespace wiSceneSystem
|
||||
{
|
||||
|
||||
class wiEmittedParticle
|
||||
{
|
||||
public:
|
||||
@@ -20,23 +25,23 @@ public:
|
||||
|
||||
private:
|
||||
ParticleCounters debugData = {};
|
||||
wiGraphicsTypes::GPUBuffer* debugDataReadbackBuffer = nullptr;
|
||||
wiGraphicsTypes::GPUBuffer* debugDataReadbackIndexBuffer = nullptr;
|
||||
wiGraphicsTypes::GPUBuffer* debugDataReadbackDistanceBuffer = nullptr;
|
||||
std::unique_ptr<wiGraphicsTypes::GPUBuffer> debugDataReadbackBuffer;
|
||||
std::unique_ptr<wiGraphicsTypes::GPUBuffer> debugDataReadbackIndexBuffer;
|
||||
std::unique_ptr<wiGraphicsTypes::GPUBuffer> debugDataReadbackDistanceBuffer;
|
||||
|
||||
wiGraphicsTypes::GPUBuffer* particleBuffer = nullptr;
|
||||
wiGraphicsTypes::GPUBuffer* aliveList[2] = { nullptr, nullptr };
|
||||
wiGraphicsTypes::GPUBuffer* deadList = nullptr;
|
||||
wiGraphicsTypes::GPUBuffer* distanceBuffer = nullptr; // for sorting
|
||||
wiGraphicsTypes::GPUBuffer* sphPartitionCellIndices = nullptr; // for SPH
|
||||
wiGraphicsTypes::GPUBuffer* sphPartitionCellOffsets = nullptr; // for SPH
|
||||
wiGraphicsTypes::GPUBuffer* densityBuffer = nullptr; // for SPH
|
||||
wiGraphicsTypes::GPUBuffer* counterBuffer = nullptr;
|
||||
wiGraphicsTypes::GPUBuffer* indirectBuffers = nullptr; // kickoffUpdate, simulation, draw
|
||||
wiGraphicsTypes::GPUBuffer* constantBuffer = nullptr;
|
||||
std::unique_ptr<wiGraphicsTypes::GPUBuffer> particleBuffer;
|
||||
std::unique_ptr<wiGraphicsTypes::GPUBuffer> aliveList[2];
|
||||
std::unique_ptr<wiGraphicsTypes::GPUBuffer> deadList;
|
||||
std::unique_ptr<wiGraphicsTypes::GPUBuffer> distanceBuffer; // for sorting
|
||||
std::unique_ptr<wiGraphicsTypes::GPUBuffer> sphPartitionCellIndices; // for SPH
|
||||
std::unique_ptr<wiGraphicsTypes::GPUBuffer> sphPartitionCellOffsets; // for SPH
|
||||
std::unique_ptr<wiGraphicsTypes::GPUBuffer> densityBuffer; // for SPH
|
||||
std::unique_ptr<wiGraphicsTypes::GPUBuffer> counterBuffer;
|
||||
std::unique_ptr<wiGraphicsTypes::GPUBuffer> indirectBuffers; // kickoffUpdate, simulation, draw
|
||||
std::unique_ptr<wiGraphicsTypes::GPUBuffer> constantBuffer;
|
||||
void CreateSelfBuffers();
|
||||
|
||||
static wiGraphicsTypes::ComputeShader *kickoffUpdateCS, *finishUpdateCS, *emitCS, *sphpartitionCS, *sphpartitionoffsetsCS, *sphpartitionoffsetsresetCS, *sphdensityCS, *sphforceCS, *simulateCS, *simulateCS_SORTING, *simulateCS_DEPTHCOLLISIONS, *simulateCS_SORTING_DEPTHCOLLISIONS;
|
||||
static wiGraphicsTypes::ComputeShader *kickoffUpdateCS, *finishUpdateCS, *emitCS, *emitCS_FROMMESH, *sphpartitionCS, *sphpartitionoffsetsCS, *sphpartitionoffsetsresetCS, *sphdensityCS, *sphforceCS, *simulateCS, *simulateCS_SORTING, *simulateCS_DEPTHCOLLISIONS, *simulateCS_SORTING_DEPTHCOLLISIONS;
|
||||
static wiGraphicsTypes::VertexShader *vertexShader;
|
||||
static wiGraphicsTypes::PixelShader *pixelShader[PARTICLESHADERTYPE_COUNT];
|
||||
static wiGraphicsTypes::BlendState blendStates[BLENDMODE_COUNT];
|
||||
@@ -45,35 +50,31 @@ private:
|
||||
|
||||
static wiGraphicsTypes::GraphicsPSO PSO[BLENDMODE_COUNT][PARTICLESHADERTYPE_COUNT];
|
||||
static wiGraphicsTypes::GraphicsPSO PSO_wire;
|
||||
static wiGraphicsTypes::ComputePSO CPSO_kickoffUpdate, CPSO_finishUpdate, CPSO_emit, CPSO_sphpartition, CPSO_sphpartitionoffsets, CPSO_sphpartitionoffsetsreset, CPSO_sphdensity, CPSO_sphforce, CPSO_simulate, CPSO_simulate_SORTING, CPSO_simulate_DEPTHCOLLISIONS, CPSO_simulate_SORTING_DEPTHCOLLISIONS;
|
||||
static wiGraphicsTypes::ComputePSO CPSO_kickoffUpdate, CPSO_finishUpdate, CPSO_emit, CPSO_emit_FROMMESH, CPSO_sphpartition, CPSO_sphpartitionoffsets, CPSO_sphpartitionoffsetsreset, CPSO_sphdensity, CPSO_sphforce, CPSO_simulate, CPSO_simulate_SORTING, CPSO_simulate_DEPTHCOLLISIONS, CPSO_simulate_SORTING_DEPTHCOLLISIONS;
|
||||
|
||||
public:
|
||||
static void LoadShaders();
|
||||
static void SetUpStatic();
|
||||
static void CleanUpStatic();
|
||||
private:
|
||||
static void LoadBuffers();
|
||||
static void SetUpStates();
|
||||
|
||||
float emit;
|
||||
float emit = 0.0f;
|
||||
|
||||
bool buffersUpToDate = false;
|
||||
uint32_t MAX_PARTICLES;
|
||||
uint32_t MAX_PARTICLES = 1000;
|
||||
|
||||
public:
|
||||
wiEmittedParticle();
|
||||
//wiEmittedParticle(const std::string& newName, const std::string& newMat, wiSceneComponents::Object* newObject, float newSize, float newRandomFac, float newNormalFac
|
||||
// ,float newCount, float newLife, float newRandLife, float newScaleX, float newScaleY, float newRot);
|
||||
wiEmittedParticle(const wiEmittedParticle& other);
|
||||
static void SetUpStatic();
|
||||
static void CleanUpStatic();
|
||||
|
||||
void Update(float dt);
|
||||
void Burst(float num);
|
||||
void Restart();
|
||||
|
||||
void UpdateRenderData(GRAPHICSTHREAD threadID);
|
||||
wiECS::Entity meshID = wiECS::INVALID_ENTITY;
|
||||
|
||||
void Draw(GRAPHICSTHREAD threadID);
|
||||
void CleanUp();
|
||||
// Must have a transform and material component, but mesh is optional
|
||||
void UpdateRenderData(const TransformComponent& transform, const MaterialComponent& material, const MeshComponent* mesh, GRAPHICSTHREAD threadID);
|
||||
void Draw(const MaterialComponent& material, GRAPHICSTHREAD threadID);
|
||||
|
||||
bool DEBUG = false;
|
||||
ParticleCounters GetDebugData() { return debugData; }
|
||||
@@ -86,15 +87,16 @@ public:
|
||||
|
||||
PARTICLESHADERTYPE shaderType = SOFT;
|
||||
|
||||
std::string name;
|
||||
//wiSceneComponents::Object* object;
|
||||
std::string materialName;
|
||||
//wiSceneComponents::Material* material;
|
||||
|
||||
float size,random_factor,normal_factor;
|
||||
float count,life,random_life;
|
||||
float scaleX,scaleY,rotation;
|
||||
float motionBlurAmount;
|
||||
float size = 1.0f;
|
||||
float random_factor = 1.0f;
|
||||
float normal_factor = 1.0f;
|
||||
float count = 0.0f;
|
||||
float life = 1.0f;
|
||||
float random_life = 1.0f;
|
||||
float scaleX = 1.0f;
|
||||
float scaleY = 1.0f;
|
||||
float rotation = 0.0f;
|
||||
float motionBlurAmount = 0.0f;
|
||||
float mass = 1.0f;
|
||||
|
||||
float SPH_h = 1.0f; // smoothing radius
|
||||
@@ -105,9 +107,7 @@ public:
|
||||
void SetMaxParticleCount(uint32_t value);
|
||||
uint32_t GetMaxParticleCount() const { return MAX_PARTICLES; }
|
||||
uint32_t GetMemorySizeInBytes() const;
|
||||
|
||||
XMFLOAT3 GetPosition() const;
|
||||
|
||||
void Serialize(wiArchive& archive);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,9 @@
|
||||
|
||||
using namespace std;
|
||||
using namespace wiGraphicsTypes;
|
||||
using namespace wiSceneSystem;
|
||||
|
||||
namespace wiSceneSystem
|
||||
{
|
||||
|
||||
VertexShader *wiHairParticle::vs = nullptr;
|
||||
PixelShader *wiHairParticle::ps[];
|
||||
@@ -24,84 +26,6 @@ GraphicsPSO wiHairParticle::PSO[SHADERTYPE_COUNT][2];
|
||||
GraphicsPSO wiHairParticle::PSO_wire;
|
||||
int wiHairParticle::LOD[3];
|
||||
|
||||
wiHairParticle::wiHairParticle()
|
||||
{
|
||||
cb = nullptr;
|
||||
particleBuffer = nullptr;
|
||||
ib = nullptr;
|
||||
ib_transposed = nullptr;
|
||||
name = "";
|
||||
densityG = "";
|
||||
lenG = "";
|
||||
length = 0;
|
||||
count = 0;
|
||||
//material = nullptr;
|
||||
//object = nullptr;
|
||||
materialName = "";
|
||||
particleCount = 0;
|
||||
}
|
||||
//wiHairParticle::wiHairParticle(const std::string& newName, float newLen, int newCount
|
||||
// , const std::string& newMat, Object* newObject, const std::string& densityGroup, const std::string& lengthGroup)
|
||||
//{
|
||||
// cb = nullptr;
|
||||
// particleBuffer = nullptr;
|
||||
// ib = nullptr;
|
||||
// ib_transposed = nullptr;
|
||||
// drawargs = nullptr;
|
||||
// name=newName;
|
||||
// densityG=densityGroup;
|
||||
// lenG=lengthGroup;
|
||||
// length=newLen;
|
||||
// count=newCount;
|
||||
// material=nullptr;
|
||||
// object = newObject;
|
||||
// materialName = newMat;
|
||||
// particleCount = 0;
|
||||
// for (MeshSubset& subset : object->mesh->subsets)
|
||||
// {
|
||||
// if (!newMat.compare(subset.material->name)) {
|
||||
// material = subset.material;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (material)
|
||||
// {
|
||||
// Generate();
|
||||
// }
|
||||
//}
|
||||
wiHairParticle::wiHairParticle(const wiHairParticle& other)
|
||||
{
|
||||
cb = nullptr;
|
||||
particleBuffer = nullptr;
|
||||
ib = nullptr;
|
||||
ib_transposed = nullptr;
|
||||
drawargs = nullptr;
|
||||
name = other.name + "0";
|
||||
densityG = other.densityG;
|
||||
lenG = other.lenG;
|
||||
length = other.length;
|
||||
count = other.count;
|
||||
//material = other.material;
|
||||
//object = other.object;
|
||||
materialName = other.materialName;
|
||||
particleCount = other.particleCount;
|
||||
//material = other.material;
|
||||
|
||||
//if (material)
|
||||
{
|
||||
Generate();
|
||||
}
|
||||
}
|
||||
|
||||
void wiHairParticle::CleanUp()
|
||||
{
|
||||
SAFE_DELETE(cb);
|
||||
SAFE_DELETE(particleBuffer);
|
||||
SAFE_DELETE(ib);
|
||||
SAFE_DELETE(drawargs);
|
||||
}
|
||||
|
||||
void wiHairParticle::CleanUpStatic()
|
||||
{
|
||||
SAFE_DELETE(vs);
|
||||
@@ -572,33 +496,4 @@ void wiHairParticle::Draw(CameraComponent* camera, SHADERTYPE shaderType, bool t
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
void wiHairParticle::Serialize(wiArchive& archive)
|
||||
{
|
||||
if (archive.IsReadMode())
|
||||
{
|
||||
archive >> length;
|
||||
archive >> count;
|
||||
archive >> name;
|
||||
archive >> densityG;
|
||||
archive >> lenG;
|
||||
archive >> materialName;
|
||||
if (archive.GetVersion() < 15)
|
||||
{
|
||||
archive >> OriginalMatrix_Inverse;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
archive << length;
|
||||
archive << count;
|
||||
archive << name;
|
||||
archive << densityG;
|
||||
archive << lenG;
|
||||
archive << materialName;
|
||||
if (archive.GetVersion() < 15)
|
||||
{
|
||||
archive << OriginalMatrix_Inverse;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
|
||||
class wiArchive;
|
||||
|
||||
namespace wiSceneSystem
|
||||
{
|
||||
|
||||
class wiHairParticle
|
||||
{
|
||||
public:
|
||||
@@ -26,11 +29,11 @@ private:
|
||||
float __pad1;
|
||||
};
|
||||
|
||||
wiGraphicsTypes::GPUBuffer *cb;
|
||||
wiGraphicsTypes::GPUBuffer *particleBuffer;
|
||||
wiGraphicsTypes::GPUBuffer *ib;
|
||||
wiGraphicsTypes::GPUBuffer *ib_transposed;
|
||||
wiGraphicsTypes::GPUBuffer *drawargs;
|
||||
std::unique_ptr<wiGraphicsTypes::GPUBuffer> cb;
|
||||
std::unique_ptr<wiGraphicsTypes::GPUBuffer> particleBuffer;
|
||||
std::unique_ptr<wiGraphicsTypes::GPUBuffer> ib;
|
||||
std::unique_ptr<wiGraphicsTypes::GPUBuffer> ib_transposed;
|
||||
std::unique_ptr<wiGraphicsTypes::GPUBuffer> drawargs;
|
||||
|
||||
static wiGraphicsTypes::VertexShader *vs;
|
||||
static wiGraphicsTypes::PixelShader *ps[SHADERTYPE_COUNT];
|
||||
@@ -45,12 +48,6 @@ public:
|
||||
static void LoadShaders();
|
||||
|
||||
public:
|
||||
wiHairParticle();
|
||||
//wiHairParticle(const std::string& newName, float newLen, int newCount
|
||||
// , const std::string& newMat, wiSceneComponents::Object* newObject, const std::string& densityGroup, const std::string& lengthGroup);
|
||||
wiHairParticle(const wiHairParticle& other);
|
||||
|
||||
void CleanUp();
|
||||
|
||||
void Generate();
|
||||
void ComputeCulling(wiSceneSystem::CameraComponent* camera, GRAPHICSTHREAD threadID);
|
||||
@@ -60,14 +57,9 @@ public:
|
||||
static void SetUpStatic();
|
||||
static void Settings(int lod0,int lod1,int lod2);
|
||||
|
||||
float length;
|
||||
int count;
|
||||
std::string name, densityG, lenG, materialName;
|
||||
//wiSceneComponents::Material* material;
|
||||
float length = 1.0f;
|
||||
XMFLOAT4X4 OriginalMatrix_Inverse;
|
||||
//wiSceneComponents::Object* object;
|
||||
size_t particleCount;
|
||||
|
||||
void Serialize(wiArchive& archive);
|
||||
size_t particleCount = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
+73
-56
@@ -3460,12 +3460,7 @@ void wiRenderer::UpdateRenderData(GRAPHICSTHREAD threadID)
|
||||
device->BindUAVs(CS, sos, 0, ARRAYSIZE(sos), threadID);
|
||||
|
||||
device->Dispatch((UINT)ceilf((float)mesh.vertex_positions.size() / SKINNING_COMPUTE_THREADCOUNT), 1, 1, threadID);
|
||||
device->UAVBarrier(sos, ARRAYSIZE(sos), threadID); // todo: defer
|
||||
//device->TransitionBarrier(sos, ARRAYSIZE(sos), RESOURCE_STATE_UNORDERED_ACCESS, RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER, threadID);
|
||||
}
|
||||
else if (mesh.IsDynamicVB())
|
||||
{
|
||||
|
||||
device->UAVBarrier(sos, ARRAYSIZE(sos), threadID); // todo: defer, to gain from async compute
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3480,15 +3475,17 @@ void wiRenderer::UpdateRenderData(GRAPHICSTHREAD threadID)
|
||||
device->EventEnd(threadID);
|
||||
wiProfiler::GetInstance().EndRange(threadID); // skinning
|
||||
|
||||
//// Particle system simulation/sorting/culling:
|
||||
//for (auto& x : emitterSystems)
|
||||
//{
|
||||
// x->UpdateRenderData(threadID);
|
||||
//}
|
||||
//for (wiHairParticle* hair : mainCameraCulling.culledHairParticleSystems)
|
||||
//{
|
||||
// hair->ComputeCulling(getCamera(), threadID);
|
||||
//}
|
||||
// GPU Particle systems simulation/sorting/culling:
|
||||
for (size_t i = 0; i < scene.emitters.GetCount(); ++i)
|
||||
{
|
||||
wiEmittedParticle& emitter = scene.emitters[i];
|
||||
Entity entity = scene.emitters.GetEntity(i);
|
||||
const TransformComponent& transform = *scene.transforms.GetComponent(entity);
|
||||
const MaterialComponent& material = *scene.materials.GetComponent(entity);
|
||||
const MeshComponent* mesh = scene.meshes.GetComponent(emitter.meshID);
|
||||
|
||||
emitter.UpdateRenderData(transform, material, mesh, threadID);
|
||||
}
|
||||
|
||||
// Compute water simulation:
|
||||
if (ocean != nullptr)
|
||||
@@ -3994,36 +3991,55 @@ void wiRenderer::DrawDebugWorld(CameraComponent* camera, GRAPHICSTHREAD threadID
|
||||
device->EventEnd(threadID);
|
||||
}
|
||||
|
||||
//if (debugEmitters || !renderableBoxes.empty())
|
||||
//{
|
||||
// device->EventBegin("DebugEmitters", threadID);
|
||||
if (debugEmitters)
|
||||
{
|
||||
device->EventBegin("DebugEmitters", threadID);
|
||||
|
||||
// device->BindGraphicsPSO(PSO_debug[DEBUGRENDERING_EMITTER], threadID);
|
||||
MiscCB sb;
|
||||
for (size_t i = 0; i < scene.emitters.GetCount(); ++i)
|
||||
{
|
||||
const wiEmittedParticle& emitter = scene.emitters[i];
|
||||
Entity entity = scene.emitters.GetEntity(i);
|
||||
const TransformComponent& transform = *scene.transforms.GetComponent(entity);
|
||||
const MeshComponent* mesh = scene.meshes.GetComponent(emitter.meshID);
|
||||
|
||||
// MiscCB sb;
|
||||
// for (auto& x : emitterSystems)
|
||||
// {
|
||||
// if (x->object != nullptr && x->object->mesh != nullptr)
|
||||
// {
|
||||
// sb.mTransform = XMMatrixTranspose(XMLoadFloat4x4(&x->object->world)*camera->GetViewProjection());
|
||||
// sb.mColor = XMFLOAT4(0, 1, 0, 1);
|
||||
// device->UpdateBuffer(constantBuffers[CBTYPE_MISC], &sb, threadID);
|
||||
sb.mTransform = XMMatrixTranspose(XMLoadFloat4x4(&transform.world)*camera->GetViewProjection());
|
||||
sb.mColor = XMFLOAT4(0, 1, 0, 1);
|
||||
device->UpdateBuffer(constantBuffers[CBTYPE_MISC], &sb, threadID);
|
||||
|
||||
// GPUBuffer* vbs[] = {
|
||||
// x->object->mesh->vertexBuffer_POS,
|
||||
// };
|
||||
// const UINT strides[] = {
|
||||
// sizeof(MeshComponent::Vertex_POS),
|
||||
// };
|
||||
// device->BindVertexBuffers(vbs, 0, ARRAYSIZE(vbs), strides, nullptr, threadID);
|
||||
// device->BindIndexBuffer(x->object->mesh->indexBuffer, x->object->mesh->GetIndexFormat(), 0, threadID);
|
||||
if (mesh == nullptr)
|
||||
{
|
||||
// No mesh, just draw a box:
|
||||
device->BindGraphicsPSO(PSO_debug[DEBUGRENDERING_CUBE], threadID);
|
||||
GPUBuffer* vbs[] = {
|
||||
&Cube::vertexBuffer,
|
||||
};
|
||||
const UINT strides[] = {
|
||||
sizeof(XMFLOAT4) + sizeof(XMFLOAT4),
|
||||
};
|
||||
device->BindVertexBuffers(vbs, 0, ARRAYSIZE(vbs), strides, nullptr, threadID);
|
||||
device->BindIndexBuffer(&Cube::indexBuffer, INDEXFORMAT_16BIT, 0, threadID);
|
||||
device->DrawIndexed(24, 0, 0, threadID);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Draw mesh wireframe:
|
||||
device->BindGraphicsPSO(PSO_debug[DEBUGRENDERING_EMITTER], threadID);
|
||||
GPUBuffer* vbs[] = {
|
||||
mesh->streamoutBuffer_POS != nullptr ? mesh->streamoutBuffer_POS.get() : mesh->vertexBuffer_POS.get(),
|
||||
};
|
||||
const UINT strides[] = {
|
||||
sizeof(MeshComponent::Vertex_POS),
|
||||
};
|
||||
device->BindVertexBuffers(vbs, 0, ARRAYSIZE(vbs), strides, nullptr, threadID);
|
||||
device->BindIndexBuffer(mesh->indexBuffer.get(), mesh->GetIndexFormat(), 0, threadID);
|
||||
|
||||
// device->DrawIndexed((int)x->object->mesh->indices.size(), 0, 0, threadID);
|
||||
// }
|
||||
// }
|
||||
device->DrawIndexed((int)mesh->indices.size(), 0, 0, threadID);
|
||||
}
|
||||
}
|
||||
|
||||
// device->EventEnd(threadID);
|
||||
//}
|
||||
device->EventEnd(threadID);
|
||||
}
|
||||
|
||||
|
||||
if (debugForceFields)
|
||||
@@ -4101,23 +4117,24 @@ void wiRenderer::DrawDebugWorld(CameraComponent* camera, GRAPHICSTHREAD threadID
|
||||
|
||||
void wiRenderer::DrawSoftParticles(CameraComponent* camera, bool distortion, GRAPHICSTHREAD threadID)
|
||||
{
|
||||
//// todo: remove allocation of vector
|
||||
//vector<wiEmittedParticle*> sortedEmitters(emitterSystems.begin(), emitterSystems.end());
|
||||
//std::sort(sortedEmitters.begin(), sortedEmitters.end(), [&](const wiEmittedParticle* a, const wiEmittedParticle* b) {
|
||||
// return wiMath::DistanceSquared(camera->translation, a->GetPosition()) > wiMath::DistanceSquared(camera->translation, b->GetPosition());
|
||||
//});
|
||||
Scene& scene = GetScene();
|
||||
|
||||
for (size_t i = 0; i < scene.emitters.GetCount(); ++i)
|
||||
{
|
||||
wiEmittedParticle& emitter = scene.emitters[i];
|
||||
Entity entity = scene.emitters.GetEntity(i);
|
||||
const MaterialComponent& material = *scene.materials.GetComponent(entity);
|
||||
|
||||
if (distortion && emitter.shaderType == wiEmittedParticle::SOFT_DISTORTION)
|
||||
{
|
||||
emitter.Draw(material, threadID);
|
||||
}
|
||||
else if (!distortion && (emitter.shaderType == wiEmittedParticle::SOFT || emitter.shaderType == wiEmittedParticle::SIMPLEST || IsWireRender()))
|
||||
{
|
||||
emitter.Draw(material, threadID);
|
||||
}
|
||||
}
|
||||
|
||||
//for (wiEmittedParticle* e : sortedEmitters)
|
||||
//{
|
||||
// if (distortion && e->shaderType == wiEmittedParticle::SOFT_DISTORTION)
|
||||
// {
|
||||
// e->Draw(threadID);
|
||||
// }
|
||||
// else if (!distortion && (e->shaderType == wiEmittedParticle::SOFT || e->shaderType == wiEmittedParticle::SIMPLEST || IsWireRender()))
|
||||
// {
|
||||
// e->Draw(threadID);
|
||||
// }
|
||||
//}
|
||||
}
|
||||
void wiRenderer::DrawTrails(GRAPHICSTHREAD threadID, Texture2D* refracRes)
|
||||
{
|
||||
|
||||
@@ -11,13 +11,7 @@
|
||||
#include <unordered_set>
|
||||
#include <deque>
|
||||
|
||||
class Cube;
|
||||
class Translator;
|
||||
class wiParticle;
|
||||
class wiEmittedParticle;
|
||||
class wiHairParticle;
|
||||
class wiSprite;
|
||||
class TaskThread;
|
||||
class PHYSICS;
|
||||
class wiRenderTarget;
|
||||
class wiOcean;
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
using namespace std;
|
||||
using namespace wiGraphicsTypes;
|
||||
using namespace wiSceneSystem;
|
||||
|
||||
namespace wiRenderer_BindLua
|
||||
{
|
||||
|
||||
@@ -364,7 +364,7 @@ namespace wiSceneSystem
|
||||
assert(SUCCEEDED(hr));
|
||||
|
||||
bd.Usage = USAGE_DEFAULT;
|
||||
bd.BindFlags = BIND_VERTEX_BUFFER | BIND_UNORDERED_ACCESS;
|
||||
bd.BindFlags = BIND_VERTEX_BUFFER | BIND_UNORDERED_ACCESS | BIND_SHADER_RESOURCE;
|
||||
bd.CPUAccessFlags = 0;
|
||||
bd.MiscFlags = RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS;
|
||||
|
||||
@@ -763,9 +763,15 @@ namespace wiSceneSystem
|
||||
|
||||
RunLightUpdateSystem(*cameras.GetComponent(wiRenderer::getCameraID()), transforms, aabb_lights, lights, sunDirection, sunColor);
|
||||
|
||||
RunEmitterUpdateSystem(emitters, dt);
|
||||
|
||||
}
|
||||
void Scene::Clear()
|
||||
{
|
||||
// Preferrably, we wouldn't write all of this, just call clear on every container
|
||||
// But: we want to only delete the owned entities, and there might be others
|
||||
// Think about it, probably there is a better way...
|
||||
|
||||
for (Entity entity : owned_entities)
|
||||
{
|
||||
names.Remove(entity);
|
||||
@@ -789,6 +795,8 @@ namespace wiSceneSystem
|
||||
decals.Remove(entity);
|
||||
aabb_decals.Remove(entity);
|
||||
animations.Remove(entity);
|
||||
emitters.Remove(entity);
|
||||
hairs.Remove(entity);
|
||||
models.Remove(entity);
|
||||
}
|
||||
|
||||
@@ -820,6 +828,8 @@ namespace wiSceneSystem
|
||||
decals.Remove(entity);
|
||||
aabb_decals.Remove(entity);
|
||||
animations.Remove(entity);
|
||||
emitters.Remove(entity);
|
||||
hairs.Remove(entity);
|
||||
models.Remove(entity);
|
||||
}
|
||||
Entity Scene::Entity_FindByName(const std::string& name)
|
||||
@@ -916,8 +926,9 @@ namespace wiSceneSystem
|
||||
|
||||
layers.Create(entity);
|
||||
|
||||
transforms.Create(entity).Translate(position);
|
||||
transforms.GetComponent(entity)->UpdateTransform();
|
||||
TransformComponent& transform = transforms.Create(entity);
|
||||
transform.Translate(position);
|
||||
transform.UpdateTransform();
|
||||
|
||||
aabb_lights.Create(entity).createFromHalfWidth(position, XMFLOAT3(range, range, range));
|
||||
|
||||
@@ -943,8 +954,9 @@ namespace wiSceneSystem
|
||||
|
||||
layers.Create(entity);
|
||||
|
||||
transforms.Create(entity).Translate(position);
|
||||
transforms.GetComponent(entity)->UpdateTransform();
|
||||
TransformComponent& transform = transforms.Create(entity);
|
||||
transform.Translate(position);
|
||||
transform.UpdateTransform();
|
||||
|
||||
ForceFieldComponent& force = forces.Create(entity);
|
||||
force.gravity = 0;
|
||||
@@ -966,8 +978,9 @@ namespace wiSceneSystem
|
||||
|
||||
layers.Create(entity);
|
||||
|
||||
transforms.Create(entity).Translate(position);
|
||||
transforms.GetComponent(entity)->UpdateTransform();
|
||||
TransformComponent& transform = transforms.Create(entity);
|
||||
transform.Translate(position);
|
||||
transform.UpdateTransform();
|
||||
|
||||
aabb_probes.Create(entity);
|
||||
|
||||
@@ -1031,6 +1044,27 @@ namespace wiSceneSystem
|
||||
|
||||
return entity;
|
||||
}
|
||||
Entity Scene::Entity_CreateEmitter(
|
||||
const std::string& name,
|
||||
const XMFLOAT3& position
|
||||
)
|
||||
{
|
||||
Entity entity = CreateEntity();
|
||||
|
||||
owned_entities.insert(entity);
|
||||
|
||||
names.Create(entity) = name;
|
||||
|
||||
emitters.Create(entity);
|
||||
|
||||
TransformComponent& transform = transforms.Create(entity);
|
||||
transform.Translate(position);
|
||||
transform.UpdateTransform();
|
||||
|
||||
materials.Create(entity);
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
void Scene::Component_Attach(Entity entity, Entity parent)
|
||||
{
|
||||
@@ -1694,6 +1728,13 @@ namespace wiSceneSystem
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void RunEmitterUpdateSystem(ComponentManager<wiEmittedParticle>& emitters, float dt)
|
||||
{
|
||||
for (size_t i = 0; i < emitters.GetCount(); ++i)
|
||||
{
|
||||
wiEmittedParticle& emitter = emitters[i];
|
||||
emitter.Update(dt);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#include "ShaderInterop.h"
|
||||
#include "wiFrustum.h"
|
||||
#include "wiRenderTarget.h"
|
||||
#include "wiEmittedParticle.h"
|
||||
#include "wiHairParticle.h"
|
||||
|
||||
#include "wiECS.h"
|
||||
#include "wiSceneSystem_Decl.h"
|
||||
@@ -686,6 +688,8 @@ namespace wiSceneSystem
|
||||
wiECS::ComponentManager<DecalComponent> decals;
|
||||
wiECS::ComponentManager<AABB> aabb_decals;
|
||||
wiECS::ComponentManager<AnimationComponent> animations;
|
||||
wiECS::ComponentManager<wiEmittedParticle> emitters;
|
||||
wiECS::ComponentManager<wiHairParticle> hairs;
|
||||
wiECS::ComponentManager<ModelComponent> models;
|
||||
|
||||
AABB bounds;
|
||||
@@ -714,23 +718,19 @@ namespace wiSceneSystem
|
||||
void Entity_Remove(wiECS::Entity entity);
|
||||
// Finds the first entity by the name (if it exists, otherwise returns INVALID_ENTITY):
|
||||
wiECS::Entity Entity_FindByName(const std::string& name);
|
||||
// Helper function to create a model entity:
|
||||
|
||||
wiECS::Entity Entity_CreateModel(
|
||||
const std::string& name
|
||||
);
|
||||
// Helper function to create a material entity:
|
||||
wiECS::Entity Entity_CreateMaterial(
|
||||
const std::string& name
|
||||
);
|
||||
// Helper function to create a model entity:
|
||||
wiECS::Entity Entity_CreateObject(
|
||||
const std::string& name
|
||||
);
|
||||
// Helper function to create a model entity:
|
||||
wiECS::Entity Entity_CreateMesh(
|
||||
const std::string& name
|
||||
);
|
||||
// Helper function to create a light entity:
|
||||
wiECS::Entity Entity_CreateLight(
|
||||
const std::string& name,
|
||||
const XMFLOAT3& position = XMFLOAT3(0, 0, 0),
|
||||
@@ -738,27 +738,27 @@ namespace wiSceneSystem
|
||||
float energy = 1,
|
||||
float range = 10
|
||||
);
|
||||
// Helper function to create a force entity:
|
||||
wiECS::Entity Entity_CreateForce(
|
||||
const std::string& name,
|
||||
const XMFLOAT3& position = XMFLOAT3(0, 0, 0)
|
||||
);
|
||||
// Helper function to create an environment capture probe entity:
|
||||
wiECS::Entity Entity_CreateEnvironmentProbe(
|
||||
const std::string& name,
|
||||
const XMFLOAT3& position = XMFLOAT3(0, 0, 0)
|
||||
);
|
||||
// Helper function to create a decal entity:
|
||||
wiECS::Entity Entity_CreateDecal(
|
||||
const std::string& name,
|
||||
const std::string& textureName,
|
||||
const std::string& normalMapName = ""
|
||||
);
|
||||
// Helper function to create a camera entity:
|
||||
wiECS::Entity Entity_CreateCamera(
|
||||
const std::string& name,
|
||||
float width, float height, float nearPlane = 0.01f, float farPlane = 1000.0f, float fov = XM_PIDIV4
|
||||
);
|
||||
wiECS::Entity Entity_CreateEmitter(
|
||||
const std::string& name,
|
||||
const XMFLOAT3& position = XMFLOAT3(0, 0, 0)
|
||||
);
|
||||
|
||||
// Attaches an entity to a parent:
|
||||
void Component_Attach(wiECS::Entity entity, wiECS::Entity parent);
|
||||
@@ -826,6 +826,7 @@ namespace wiSceneSystem
|
||||
wiECS::ComponentManager<LightComponent>& lights,
|
||||
XMFLOAT3& sunDirection, XMFLOAT3& sunColor
|
||||
);
|
||||
void RunEmitterUpdateSystem(wiECS::ComponentManager<wiEmittedParticle>& emitters, float dt);
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user