Skip to content

Commit

Permalink
animated particles - closes #1007
Browse files Browse the repository at this point in the history
  • Loading branch information
nem0 committed Oct 2, 2016
1 parent 6708922 commit 65e3c49
Show file tree
Hide file tree
Showing 8 changed files with 212 additions and 30 deletions.
1 change: 1 addition & 0 deletions src/engine/property_descriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ LUMIX_ENGINE_API int getIntPropertyMax();


template <typename T> inline IPropertyDescriptor::Type toPropertyType();
template <> inline IPropertyDescriptor::Type toPropertyType<int>() { return IPropertyDescriptor::INTEGER; }
template <> inline IPropertyDescriptor::Type toPropertyType<Int2>() { return IPropertyDescriptor::INT2; }
template <> inline IPropertyDescriptor::Type toPropertyType<Vec2>() { return IPropertyDescriptor::VEC2; }
template <> inline IPropertyDescriptor::Type toPropertyType<Vec3>() { return IPropertyDescriptor::VEC3; }
Expand Down
1 change: 1 addition & 0 deletions src/renderer/editor/plugins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2295,6 +2295,7 @@ LUMIX_STUDIO_ENTRY(renderer)
app.registerComponent("particle_emitter_plane", "Render/Particle emitter/Plane");
app.registerComponent("particle_emitter_force", "Render/Particle emitter/Force");
app.registerComponent("particle_emitter_attractor", "Render/Particle emitter/Attractor");
app.registerComponent("particle_emitter_subimage", "Render/Particle emitter/Subimage");
app.registerComponent("particle_emitter_linear_movement", "Render/Particle emitter/Linear movement");
app.registerComponent("particle_emitter_random_rotation", "Render/Particle emitter/Random rotation");
app.registerComponent("particle_emitter_size", "Render/Particle emitter/Size");
Expand Down
30 changes: 29 additions & 1 deletion src/renderer/particle_system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,31 @@ ParticleEmitter::ModuleBase::ModuleBase(ParticleEmitter& emitter)
}


ParticleEmitter::SubimageModule::SubimageModule(ParticleEmitter& emitter)
: ModuleBase(emitter)
, rows(1)
, cols(1)
{
}


void ParticleEmitter::SubimageModule::serialize(OutputBlob& blob)
{
blob.write(rows);
blob.write(cols);
}


void ParticleEmitter::SubimageModule::deserialize(InputBlob& blob, int)
{
blob.read(rows);
blob.read(cols);
}


const ComponentType ParticleEmitter::SubimageModule::s_type = PropertyRegister::getComponentType("particle_emitter_subimage");


ParticleEmitter::ForceModule::ForceModule(ParticleEmitter& emitter)
: ModuleBase(emitter)
{
Expand Down Expand Up @@ -592,6 +617,7 @@ ParticleEmitter::ParticleEmitter(Entity entity, Universe& universe, IAllocator&
, m_universe(universe)
, m_entity(entity)
, m_size(allocator)
, m_subimage_module(nullptr)
{
init();
}
Expand Down Expand Up @@ -674,6 +700,7 @@ ParticleEmitter::ModuleBase* ParticleEmitter::getModule(ComponentType type)

void ParticleEmitter::addModule(ModuleBase* module)
{
if (module->getType() == SubimageModule::s_type) m_subimage_module = static_cast<SubimageModule*>(module);
m_modules.push(module);
}

Expand Down Expand Up @@ -777,7 +804,8 @@ void ParticleEmitter::deserialize(InputBlob& blob, ResourceManager& manager, boo
"linear_movement",
"alpha",
"size",
"random_rotation"};
"random_rotation",
"subimage"};

for (const char* old_name : OLD_MODULE_NAMES)
{
Expand Down
14 changes: 14 additions & 0 deletions src/renderer/particle_system.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,19 @@ class LUMIX_RENDERER_API ParticleEmitter
};


struct LUMIX_RENDERER_API SubimageModule : public ModuleBase
{
explicit SubimageModule(ParticleEmitter& emitter);
void serialize(OutputBlob& blob) override;
void deserialize(InputBlob& blob, int version) override;
ComponentType getType() const override { return s_type; }
static const ComponentType s_type;

int rows;
int cols;
};


struct LUMIX_RENDERER_API SpawnShapeModule : public ModuleBase
{
explicit SpawnShapeModule(ParticleEmitter& emitter);
Expand Down Expand Up @@ -230,6 +243,7 @@ class LUMIX_RENDERER_API ParticleEmitter
IntInterval m_spawn_count;

Array<ModuleBase*> m_modules;
SubimageModule* m_subimage_module;
Entity m_entity;
bool m_is_valid;

Expand Down
111 changes: 85 additions & 26 deletions src/renderer/pipeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -575,41 +575,100 @@ struct PipelineImpl : public Pipeline
Material* material = emitter.getMaterial();

const bgfx::InstanceDataBuffer* instance_buffer = nullptr;
struct Instance
{
Vec4 pos;
Vec4 alpha_and_rotation;
};
Instance* instance = nullptr;

auto& view = *m_current_view;
for (int i = 0, c = emitter.m_life.size(); i < c; ++i)
static const int subimage_define_idx = m_renderer.getShaderDefineIdx("SUBIMAGE");
if (emitter.m_subimage_module)
{
if (i % PARTICLE_BATCH_SIZE == 0)
struct Instance
{
Vec4 pos;
Vec4 alpha_and_rotation;
Vec4 uv_params0;
Vec4 uv_params1;
};
Instance* instance = nullptr;
int cols = emitter.m_subimage_module->cols;
int rows = emitter.m_subimage_module->rows;
float w = 1.0f / cols;
float h = 1.0f / rows;
material->setDefine(subimage_define_idx, true);
int size = emitter.m_subimage_module->rows * emitter.m_subimage_module->cols;
for (int i = 0, c = emitter.m_life.size(); i < c; ++i)
{
if (instance_buffer)
if (i % PARTICLE_BATCH_SIZE == 0)
{
executeCommandBuffer(material->getCommandBuffer(), material);
executeCommandBuffer(view.command_buffer.buffer, material);

bgfx::setInstanceDataBuffer(instance_buffer, PARTICLE_BATCH_SIZE);
bgfx::setVertexBuffer(m_particle_vertex_buffer);
bgfx::setIndexBuffer(m_particle_index_buffer);
bgfx::setStencil(view.stencil, BGFX_STENCIL_NONE);
bgfx::setState(view.render_state | material->getRenderStates());
++m_stats.draw_call_count;
m_stats.instance_count += PARTICLE_BATCH_SIZE;
m_stats.triangle_count += PARTICLE_BATCH_SIZE * 2;
bgfx::submit(view.bgfx_id, material->getShaderInstance().getProgramHandle(view.pass_idx));
if (instance_buffer)
{
executeCommandBuffer(material->getCommandBuffer(), material);
executeCommandBuffer(view.command_buffer.buffer, material);

bgfx::setInstanceDataBuffer(instance_buffer, PARTICLE_BATCH_SIZE);
bgfx::setVertexBuffer(m_particle_vertex_buffer);
bgfx::setIndexBuffer(m_particle_index_buffer);
bgfx::setStencil(view.stencil, BGFX_STENCIL_NONE);
bgfx::setState(view.render_state | material->getRenderStates());
++m_stats.draw_call_count;
m_stats.instance_count += PARTICLE_BATCH_SIZE;
m_stats.triangle_count += PARTICLE_BATCH_SIZE * 2;
bgfx::submit(view.bgfx_id, material->getShaderInstance().getProgramHandle(view.pass_idx));
}

instance_buffer = bgfx::allocInstanceDataBuffer(PARTICLE_BATCH_SIZE, sizeof(Instance));
instance = (Instance*)instance_buffer->data;
}

instance_buffer = bgfx::allocInstanceDataBuffer(PARTICLE_BATCH_SIZE, sizeof(Instance));
instance = (Instance*)instance_buffer->data;
instance->pos.set(emitter.m_position[i], emitter.m_size[i]);
instance->alpha_and_rotation.set(emitter.m_alpha[i], emitter.m_rotation[i], 0, 0);
float fidx = emitter.m_rel_life[i] * size;
int idx = int(fidx);
float t = fidx - idx;
float row0 = h * (idx / cols);
float col0 = w * (idx % cols);
float row1 = h * ((idx + 1) / cols);
float col1 = w * ((idx + 1) % cols);
instance->uv_params0.set(col0, row0, w, h);
instance->uv_params1.set(col1, row1, t, 0);
++instance;
}
}
else
{
struct Instance
{
Vec4 pos;
Vec4 alpha_and_rotation;
};
Instance* instance = nullptr;
material->setDefine(subimage_define_idx, false);
for (int i = 0, c = emitter.m_life.size(); i < c; ++i)
{
if (i % PARTICLE_BATCH_SIZE == 0)
{
if (instance_buffer)
{
executeCommandBuffer(material->getCommandBuffer(), material);
executeCommandBuffer(view.command_buffer.buffer, material);

bgfx::setInstanceDataBuffer(instance_buffer, PARTICLE_BATCH_SIZE);
bgfx::setVertexBuffer(m_particle_vertex_buffer);
bgfx::setIndexBuffer(m_particle_index_buffer);
bgfx::setStencil(view.stencil, BGFX_STENCIL_NONE);
bgfx::setState(view.render_state | material->getRenderStates());
++m_stats.draw_call_count;
m_stats.instance_count += PARTICLE_BATCH_SIZE;
m_stats.triangle_count += PARTICLE_BATCH_SIZE * 2;
bgfx::submit(view.bgfx_id, material->getShaderInstance().getProgramHandle(view.pass_idx));
}

instance_buffer = bgfx::allocInstanceDataBuffer(PARTICLE_BATCH_SIZE, sizeof(Instance));
instance = (Instance*)instance_buffer->data;
}

instance->pos = Vec4(emitter.m_position[i], emitter.m_size[i]);
instance->alpha_and_rotation = Vec4(emitter.m_alpha[i], emitter.m_rotation[i], 0, 0);
++instance;
instance->pos = Vec4(emitter.m_position[i], emitter.m_size[i]);
instance->alpha_and_rotation = Vec4(emitter.m_alpha[i], emitter.m_rotation[i], 0, 0);
++instance;
}
}

executeCommandBuffer(material->getCommandBuffer(), material);
Expand Down
71 changes: 68 additions & 3 deletions src/renderer/render_scene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ static const ComponentType PARTICLE_EMITTER_ALPHA_TYPE = PropertyRegister::getCo
static const ComponentType PARTICLE_EMITTER_FORCE_HASH = PropertyRegister::getComponentType("particle_emitter_force");
static const ComponentType PARTICLE_EMITTER_ATTRACTOR_HASH =
PropertyRegister::getComponentType("particle_emitter_attractor");
static const ComponentType PARTICLE_EMITTER_SUBIMAGE_HASH =
PropertyRegister::getComponentType("particle_emitter_subimage");
static const ComponentType PARTICLE_EMITTER_LINEAR_MOVEMENT_HASH =
PropertyRegister::getComponentType("particle_emitter_linear_movement");
static const ComponentType PARTICLE_EMITTER_SPAWN_SHAPE_HASH =
Expand Down Expand Up @@ -338,6 +340,7 @@ class RenderSceneImpl : public RenderScene
ParticleEmitter::PlaneModule::s_type,
ParticleEmitter::RandomRotationModule::s_type,
ParticleEmitter::SizeModule::s_type,
ParticleEmitter::SubimageModule::s_type,
ParticleEmitter::SpawnShapeModule::s_type};

for (auto& module : EMITTER_MODULES)
Expand Down Expand Up @@ -837,6 +840,10 @@ class RenderSceneImpl : public RenderScene
{
m_universe.addComponent(emitter->m_entity, PARTICLE_EMITTER_FORCE_HASH, this, cmp);
}
else if (module->getType() == ParticleEmitter::SubimageModule::s_type)
{
m_universe.addComponent(emitter->m_entity, PARTICLE_EMITTER_SUBIMAGE_HASH, this, cmp);
}
else if (module->getType() == ParticleEmitter::SpawnShapeModule::s_type)
{
m_universe.addComponent(emitter->m_entity, PARTICLE_EMITTER_SPAWN_SHAPE_HASH, this, cmp);
Expand Down Expand Up @@ -1276,6 +1283,21 @@ class RenderSceneImpl : public RenderScene
}


void destroyParticleEmitterSubimage(ComponentHandle component)
{
auto* emitter = m_particle_emitters[{component.index}];
auto* module = emitter->getModule(PARTICLE_EMITTER_SUBIMAGE_HASH);

ASSERT(module);

LUMIX_DELETE(m_allocator, module);
emitter->m_modules.eraseItem(module);
emitter->m_subimage_module = nullptr;
m_universe.destroyComponent(emitter->m_entity, PARTICLE_EMITTER_SUBIMAGE_HASH, this, component);
cleanup(emitter);
}


void destroyParticleEmitterAttractor(ComponentHandle component)
{
auto* emitter = m_particle_emitters[{component.index}];
Expand Down Expand Up @@ -1440,6 +1462,34 @@ class RenderSceneImpl : public RenderScene
}


void setParticleEmitterSubimageRows(ComponentHandle cmp, const int& value) override
{
auto* module = getEmitterModule<ParticleEmitter::SubimageModule>(cmp);
if (module) module->rows = value;
}


void setParticleEmitterSubimageCols(ComponentHandle cmp, const int& value) override
{
auto* module = getEmitterModule<ParticleEmitter::SubimageModule>(cmp);
if (module) module->cols = value;
}


int getParticleEmitterSubimageRows(ComponentHandle cmp) override
{
auto* module = getEmitterModule<ParticleEmitter::SubimageModule>(cmp);
return module ? module->rows : 1;
}


int getParticleEmitterSubimageCols(ComponentHandle cmp) override
{
auto* module = getEmitterModule<ParticleEmitter::SubimageModule>(cmp);
return module ? module->cols : 1;
}


void setParticleEmitterAcceleration(ComponentHandle cmp, const Vec3& value) override
{
auto* module = getEmitterModule<ParticleEmitter::ForceModule>(cmp);
Expand Down Expand Up @@ -1703,8 +1753,19 @@ class RenderSceneImpl : public RenderScene
auto* emitter = m_particle_emitters.at(index);
auto module = LUMIX_NEW(m_allocator, ParticleEmitter::ForceModule)(*emitter);
emitter->addModule(module);
m_universe.addComponent(entity, PARTICLE_EMITTER_FORCE_HASH, this, { entity.index });
return{ entity.index };
m_universe.addComponent(entity, PARTICLE_EMITTER_FORCE_HASH, this, {entity.index});
return {entity.index};
}


ComponentHandle createParticleEmitterSubimage(Entity entity)
{
int index = allocateParticleEmitter(entity);
auto* emitter = m_particle_emitters.at(index);
auto module = LUMIX_NEW(m_allocator, ParticleEmitter::SubimageModule)(*emitter);
emitter->addModule(module);
m_universe.addComponent(entity, PARTICLE_EMITTER_SUBIMAGE_HASH, this, {entity.index});
return {entity.index};
}


Expand Down Expand Up @@ -4290,7 +4351,8 @@ static struct
ComponentType type;
ComponentHandle(RenderSceneImpl::*creator)(Entity);
void (RenderSceneImpl::*destroyer)(ComponentHandle);
} COMPONENT_INFOS[] = {{MODEL_INSTANCE_TYPE, &RenderSceneImpl::createModelInstance, &RenderSceneImpl::destroyModelInstance},
} COMPONENT_INFOS[] = {
{MODEL_INSTANCE_TYPE, &RenderSceneImpl::createModelInstance, &RenderSceneImpl::destroyModelInstance},
{GLOBAL_LIGHT_TYPE, &RenderSceneImpl::createGlobalLight, &RenderSceneImpl::destroyGlobalLight},
{POINT_LIGHT_TYPE, &RenderSceneImpl::createPointLight, &RenderSceneImpl::destroyPointLight},
{DECAL_TYPE, &RenderSceneImpl::createDecal, &RenderSceneImpl::destroyDecal},
Expand All @@ -4306,6 +4368,9 @@ static struct
{PARTICLE_EMITTER_ATTRACTOR_HASH,
&RenderSceneImpl::createParticleEmitterAttractor,
&RenderSceneImpl::destroyParticleEmitterAttractor},
{PARTICLE_EMITTER_SUBIMAGE_HASH,
&RenderSceneImpl::createParticleEmitterSubimage,
&RenderSceneImpl::destroyParticleEmitterSubimage},
{PARTICLE_EMITTER_SIZE_HASH,
&RenderSceneImpl::createParticleEmitterSize,
&RenderSceneImpl::destroyParticleEmitterSize},
Expand Down
5 changes: 5 additions & 0 deletions src/renderer/render_scene.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ enum class RenderSceneVersion : int32
INDEPENDENT_PARTICLE_MODULES,
CAMERA_AND_TERRAIN_REFACTOR,
DECAL,
PARTICLE_EMITTER_SUBIMAGE_MODULE,

LATEST,
INVALID = -1,
Expand Down Expand Up @@ -297,8 +298,12 @@ class LUMIX_RENDERER_API RenderScene : public IScene
virtual void setParticleEmitterSpawnPeriod(ComponentHandle cmp, const Vec2& value) = 0;
virtual void setParticleEmitterInitialSize(ComponentHandle cmp, const Vec2& value) = 0;
virtual void setParticleEmitterMaterialPath(ComponentHandle cmp, const Path& path) = 0;
virtual void setParticleEmitterSubimageRows(ComponentHandle cmp, const int& value) = 0;
virtual void setParticleEmitterSubimageCols(ComponentHandle cmp, const int& value) = 0;
virtual Path getParticleEmitterMaterialPath(ComponentHandle cmp) = 0;
virtual int getParticleEmitterPlaneCount(ComponentHandle cmp) = 0;
virtual int getParticleEmitterSubimageRows(ComponentHandle cmp) = 0;
virtual int getParticleEmitterSubimageCols(ComponentHandle cmp) = 0;
virtual void addParticleEmitterPlane(ComponentHandle cmp, int index) = 0;
virtual void removeParticleEmitterPlane(ComponentHandle cmp, int index) = 0;
virtual Entity getParticleEmitterPlaneEntity(ComponentHandle cmp, int index) = 0;
Expand Down
9 changes: 9 additions & 0 deletions src/renderer/renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,15 @@ static void registerProperties(IAllocator& allocator)
&RenderScene::getParticleEmitterAcceleration,
&RenderScene::setParticleEmitterAcceleration));

PropertyRegister::add("particle_emitter_subimage",
LUMIX_NEW(allocator, SimplePropertyDescriptor<int, RenderScene>)("Rows",
&RenderScene::getParticleEmitterSubimageRows,
&RenderScene::setParticleEmitterSubimageRows));
PropertyRegister::add("particle_emitter_subimage",
LUMIX_NEW(allocator, SimplePropertyDescriptor<int, RenderScene>)("Columns",
&RenderScene::getParticleEmitterSubimageCols,
&RenderScene::setParticleEmitterSubimageCols));

PropertyRegister::add("particle_emitter_size",
LUMIX_NEW(allocator, SampledFunctionDescriptor<RenderScene>)("Size",
&RenderScene::getParticleEmitterSize,
Expand Down

0 comments on commit 65e3c49

Please sign in to comment.