Skip to content

Commit

Permalink
add a basic particle emitter (#415)
Browse files Browse the repository at this point in the history
Sprite particle emitter + billboard + instancing

---------

Co-authored-by: Sam Joel <30547327+ssamjoel@users.noreply.github.com>
Co-authored-by: t-rvw <429601557@qq.com>
  • Loading branch information
3 people authored Mar 4, 2024
1 parent 096981e commit 370d5a6
Show file tree
Hide file tree
Showing 39 changed files with 1,609 additions and 71 deletions.
13 changes: 13 additions & 0 deletions Engine/BuiltInShaders/shaders/fs_particle.sc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
$input v_color0, v_texcoord0
#include "../common/common.sh"

SAMPLER2D(s_texColor, 0);

void main()
{
vec4 rgba = texture2D(s_texColor, v_texcoord0.xy);

rgba.xyz = rgba.xyz * v_color0.xyz;
rgba.w = rgba.w * v_color0.w;
gl_FragColor = rgba;
}
6 changes: 6 additions & 0 deletions Engine/BuiltInShaders/shaders/fs_particleEmitterShape.sc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include "../common/common.sh"

void main()
{
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
6 changes: 6 additions & 0 deletions Engine/BuiltInShaders/shaders/fs_particleforcefield.sc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include "../common/common.sh"

void main()
{
gl_FragColor = vec4(0.0, 1.0, 1.0, 1.0);
}
13 changes: 13 additions & 0 deletions Engine/BuiltInShaders/shaders/fs_wo_billboardparticle.sc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
$input v_color0, v_texcoord0
#include "../common/common.sh"

SAMPLER2D(s_texColor, 0);

void main()
{
vec4 rgba = texture2D(s_texColor, v_texcoord0.xy);

rgba.xyz = rgba.xyz * v_color0.xyz;
rgba.w = rgba.w * v_color0.w;
gl_FragColor = rgba;
}
8 changes: 7 additions & 1 deletion Engine/BuiltInShaders/shaders/varying.def.sc
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,10 @@ vec2 a_texcoord0 : TEXCOORD0;
vec4 a_color0 : COLOR0;
vec4 a_color1 : COLOR1;
ivec4 a_indices : BLENDINDICES;
vec4 a_weight : BLENDWEIGHT;
vec4 a_weight : BLENDWEIGHT;

vec4 i_data0 : TEXCOORD7;
vec4 i_data1 : TEXCOORD6;
vec4 i_data2 : TEXCOORD5;
vec4 i_data3 : TEXCOORD4;
vec4 i_data4 : TEXCOORD3;
29 changes: 29 additions & 0 deletions Engine/BuiltInShaders/shaders/vs_particle.sc
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#if defined(PARTICLEINSTANCE)
$input a_position, a_color0, a_texcoord0, i_data0, i_data1 ,i_data2 ,i_data3 ,i_data4
#else
$input a_position, a_color0, a_texcoord0
#endif

$output v_color0, v_texcoord0

#if defined(PARTICLEINSTANCE)
#include "../common/common.sh"
#else
#include "../common/common.sh"
uniform vec4 u_particleColor;
#endif

void main()
{
#if defined(PARTICLEINSTANCE)
mat4 model = mtxFromCols(i_data0, i_data1, i_data2, i_data3);
vec4 worldPos = mul(model,vec4(a_position,1.0));
gl_Position = mul(u_viewProj, worldPos);
v_color0 = a_color0*i_data4;
#else
gl_Position = mul(u_modelViewProj, vec4(a_position,1.0));
v_color0 = a_color0 * u_particleColor;
#endif

v_texcoord0 = a_texcoord0;
}
10 changes: 10 additions & 0 deletions Engine/BuiltInShaders/shaders/vs_particleEmitterShape.sc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
$input a_position//, a_color1

#include "../common/common.sh"

uniform vec4 u_shapeRange;

void main()
{
gl_Position = mul(u_modelViewProj, vec4(a_position*u_shapeRange.xyz, 1.0));
}
8 changes: 8 additions & 0 deletions Engine/BuiltInShaders/shaders/vs_particleforcefield.sc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
$input a_position//, a_color1

#include "../common/common.sh"

void main()
{
gl_Position = mul(u_modelViewProj, vec4(a_position, 1.0));
}
56 changes: 56 additions & 0 deletions Engine/BuiltInShaders/shaders/vs_wo_billboardparticle.sc
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#if defined(PARTICLEINSTANCE)
$input a_position, a_color0, a_texcoord0, i_data0, i_data1 ,i_data2 ,i_data3 ,i_data4
#else
$input a_position, a_color0, a_texcoord0
#endif
$output v_color0, v_texcoord0

#include "../common/common.sh"

#if defined(PARTICLEINSTANCE)
uniform vec4 u_particlePos;
uniform vec4 u_particleScale;
#else
uniform vec4 u_particleColor;
#endif

void main()
{
#if defined(PARTICLEINSTANCE)
mat4 model = mtxFromCols(i_data0, i_data1, i_data2, i_data3);
mat4 billboardMatrix;
billboardMatrix[0] = vec4(
u_view[0][0]*u_particleScale.x,
u_view[1][0]*u_particleScale.x,
u_view[2][0]*u_particleScale.x,
0.0
);
billboardMatrix[1] = vec4(
u_view[0][1]*u_particleScale.y,
u_view[1][1]*u_particleScale.y,
u_view[2][1]*u_particleScale.y,
0.0
);
billboardMatrix[2] = vec4(
u_view[0][2]*u_particleScale.z,
u_view[1][2]*u_particleScale.z,
u_view[2][2]*u_particleScale.z,
0.0
);
billboardMatrix[3] = vec4(
u_particlePos.x,
u_particlePos.y,
u_particlePos.z,
1.0
);
model = mul(model,billboardMatrix);
vec4 worldPos = mul(model,vec4(a_position,1.0));
gl_Position = mul(u_viewProj, worldPos);
v_color0 = a_color0*i_data4;
#else
gl_Position = mul(u_modelViewProj, vec4(a_position,1.0));
v_color0 = a_color0 * u_particleColor;
#endif

v_texcoord0 = a_texcoord0;
}
75 changes: 53 additions & 22 deletions Engine/Source/Editor/ECWorld/ECWorldConsumer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,39 +74,31 @@ void ECWorldConsumer::Execute(const cd::SceneDatabase* pSceneDatabase)
}
};

// There are multiple kinds of cases in the SceneDatabase:
// 1. No nodes but have meshes in the SceneDatabase.
// 2. Only a root node with multiple meshes.
// 3. Node hierarchy.
// Another case is that we want to skip Node/Mesh which alreay parsed previously.
std::set<uint32_t> parsedMeshIDs;
// Parse particle emitter and skip its mesh shapes.
std::set<cd::MeshID> parsedMeshIDs;
for (auto& particleEmitter : pSceneDatabase->GetParticleEmitters())
{
engine::Entity emitterEntity = m_pSceneWorld->GetWorld()->CreateEntity();
const auto& mesh = pSceneDatabase->GetMesh(particleEmitter.GetMeshID().Data());
AddParticleEmitter(emitterEntity, mesh, m_pSceneWorld->GetParticleMaterialType()->GetRequiredVertexFormat(), particleEmitter);
parsedMeshIDs.insert(mesh.GetID());
}

// Parse meshes in normal usage.
for (const auto& mesh : pSceneDatabase->GetMeshes())
{
if (m_meshMinID > mesh.GetID().Data())
{
continue;
}

ParseMesh(mesh.GetID(), cd::Transform::Identity());
parsedMeshIDs.insert(mesh.GetID().Data());
}

for (const auto& node : pSceneDatabase->GetNodes())
{
if (m_nodeMinID > node.GetID().Data())
if (parsedMeshIDs.contains(mesh.GetID()))
{
continue;
}

for (cd::MeshID meshID : node.GetMeshIDs())
{
if (parsedMeshIDs.find(meshID.Data()) != parsedMeshIDs.end())
{
continue;
}

ParseMesh(meshID, node.GetTransform());
}
ParseMesh(mesh.GetID(), cd::Transform::Identity());
parsedMeshIDs.insert(mesh.GetID().Data());
}

for (const auto& camera : pSceneDatabase->GetCameras())
Expand Down Expand Up @@ -398,4 +390,43 @@ void ECWorldConsumer::AddBlendShape(engine::Entity entity, const cd::Mesh* pMesh
blendShapeComponent.Build();
}

void ECWorldConsumer::AddParticleEmitter(engine::Entity entity, const cd::Mesh& mesh, const cd::VertexFormat& vertexFormat, const cd::ParticleEmitter& emitter)
{
engine::World* pWorld = m_pSceneWorld->GetWorld();
engine::MaterialType* pMaterialType = m_pSceneWorld->GetParticleMaterialType();
engine::NameComponent& nameComponent = pWorld->CreateComponent<engine::NameComponent>(entity);
nameComponent.SetName(emitter.GetName());
auto& particleEmitterComponent = pWorld->CreateComponent<engine::ParticleEmitterComponent>(entity);
// TODO : Some initialization here.
auto& transformComponent = pWorld->CreateComponent<engine::TransformComponent>(entity);
cd::Vec3f pos = emitter.GetPosition();
cd::Vec3f rotation = emitter.GetFixedRotation();
cd::Vec3f scale = emitter.GetFixedScale();
auto fixedRotation = cd::Math::RadianToDegree(rotation);
cd::Quaternion rotationQuat = cd::Quaternion::FromPitchYawRoll(fixedRotation.x(), fixedRotation.y(), fixedRotation.z());
transformComponent.GetTransform().SetTranslation(pos);
transformComponent.GetTransform().SetRotation(rotationQuat);
transformComponent.GetTransform().SetScale(scale);
transformComponent.Build();

particleEmitterComponent.SetRequiredVertexFormat(&vertexFormat);
////const cd::VertexFormat *requriredVertexFormat = emitter.GetVertexFormat();
////particleEmitterComponent.SetRequiredVertexFormat(requriredVertexFormat);
////particleEmitterComponent.GetParticleSystem().Init();
if (nameof::nameof_enum(emitter.GetType()) == "Sprite") { particleEmitterComponent.SetEmitterParticleType(engine::ParticleType::Sprite); }
else if (nameof::nameof_enum(emitter.GetType()) == "Ribbon") { particleEmitterComponent.SetEmitterParticleType(engine::ParticleType::Ribbon); }
else if (nameof::nameof_enum(emitter.GetType()) == "Ring") { particleEmitterComponent.SetEmitterParticleType(engine::ParticleType::Ring); }
else if (nameof::nameof_enum(emitter.GetType()) == "Model") { particleEmitterComponent.SetEmitterParticleType(engine::ParticleType::Model); }
else if (nameof::nameof_enum(emitter.GetType()) == "Track") { particleEmitterComponent.SetEmitterParticleType(engine::ParticleType::Track); }

particleEmitterComponent.SetSpawnCount(emitter.GetMaxCount());
particleEmitterComponent.SetEmitterColor(emitter.GetColor()/255.0f);
particleEmitterComponent.SetEmitterVelocity(emitter.GetVelocity());
particleEmitterComponent.SetEmitterAcceleration(emitter.GetAccelerate());
particleEmitterComponent.SetMeshData(&mesh);
particleEmitterComponent.SetMaterialType(pMaterialType);
particleEmitterComponent.ActivateShaderFeature(engine::ShaderFeature::PARTICLE_INSTANCE);
particleEmitterComponent.Build();
}

}
3 changes: 2 additions & 1 deletion Engine/Source/Editor/ECWorld/ECWorldConsumer.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class Material;
class Mesh;
class Morph;
class Node;
class ParticleEmitter;
class SceneDatabase;
class Texture;
class VertexFormat;
Expand Down Expand Up @@ -69,7 +70,7 @@ class ECWorldConsumer final : public cdtools::IConsumer
void AddAnimation(engine::Entity entity, const cd::Animation& animation, const cd::SceneDatabase* pSceneDatabase);
void AddMaterial(engine::Entity entity, const cd::Material* pMaterial, engine::MaterialType* pMaterialType, const cd::SceneDatabase* pSceneDatabase);
void AddBlendShape(engine::Entity entity, const cd::Mesh* pMesh, const cd::BlendShape& blendShape, const cd::SceneDatabase* pSceneDatabase);

void AddParticleEmitter(engine::Entity entity, const cd::Mesh& mesh, const cd::VertexFormat& vertexFormat, const cd::ParticleEmitter& emitter);
private:
engine::MaterialType* m_pDefaultMaterialType = nullptr;
engine::SceneWorld* m_pSceneWorld = nullptr;
Expand Down
9 changes: 9 additions & 0 deletions Engine/Source/Editor/EditorApp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "Rendering/ShadowMapRenderer.h"
#include "Rendering/TerrainRenderer.h"
#include "Rendering/WorldRenderer.h"
#include "Rendering/ParticleForceFieldRenderer.h"
#include "Rendering/ParticleRenderer.h"
#include "Resources/FileWatcher.h"
#include "Resources/ResourceBuilder.h"
Expand Down Expand Up @@ -260,19 +261,23 @@ void EditorApp::InitMaterialType()
constexpr const char* WorldProgram = "WorldProgram";
constexpr const char* AnimationProgram = "AnimationProgram";
constexpr const char* TerrainProgram = "TerrainProgram";
constexpr const char* ParticleProgram = "ParticleProgram";

constexpr engine::StringCrc WorldProgramCrc{ WorldProgram };
constexpr engine::StringCrc AnimationProgramCrc{ AnimationProgram };
constexpr engine::StringCrc TerrainProgramCrc{ TerrainProgram };
constexpr engine::StringCrc ParticleProgramCrc{ ParticleProgram};

m_pRenderContext->RegisterShaderProgram(WorldProgramCrc, { "vs_PBR", "fs_PBR" });
m_pRenderContext->RegisterShaderProgram(AnimationProgramCrc, { "vs_animation", "fs_animation" });
m_pRenderContext->RegisterShaderProgram(TerrainProgramCrc, { "vs_terrain", "fs_terrain" });
m_pRenderContext->RegisterShaderProgram(ParticleProgramCrc, { "vs_particle","fs_particle" });

m_pSceneWorld = std::make_unique<engine::SceneWorld>();
m_pSceneWorld->CreatePBRMaterialType(WorldProgram, IsAtmosphericScatteringEnable());
m_pSceneWorld->CreateAnimationMaterialType(AnimationProgram);
m_pSceneWorld->CreateTerrainMaterialType(TerrainProgram);
m_pSceneWorld->CreateParticleMaterialType(ParticleProgram);
}

void EditorApp::InitEditorCameraEntity()
Expand Down Expand Up @@ -554,6 +559,10 @@ void EditorApp::InitEngineRenderers()
pParticleRenderer->SetSceneWorld(m_pSceneWorld.get());
AddEngineRenderer(cd::MoveTemp(pParticleRenderer));

auto pParticleForceFieldRenderer = std::make_unique<engine::ParticleForceFieldRenderer>(m_pRenderContext->CreateView(), pSceneRenderTarget);
pParticleForceFieldRenderer->SetSceneWorld(m_pSceneWorld.get());
AddEngineRenderer(cd::MoveTemp(pParticleForceFieldRenderer));

#ifdef ENABLE_DDGI
auto pDDGIRenderer = std::make_unique<engine::DDGIRenderer>(m_pRenderContext->CreateView(), pSceneRenderTarget);
pDDGIRenderer->SetSceneWorld(m_pSceneWorld.get());
Expand Down
Loading

0 comments on commit 370d5a6

Please sign in to comment.