diff --git a/RavEngine b/RavEngine index 83cb6f9..cc26df9 160000 --- a/RavEngine +++ b/RavEngine @@ -1 +1 @@ -Subproject commit 83cb6f9818fd9c7052e457348fdde1af828e878f +Subproject commit cc26df9c5ed859d1de0a3337285adff18316c8d5 diff --git a/Samples/Rendering/Attributions.md b/Samples/Rendering/Attributions.md index d77ed0f..5398f60 100644 --- a/Samples/Rendering/Attributions.md +++ b/Samples/Rendering/Attributions.md @@ -1,3 +1,4 @@ ### Asset attributions - Helmet model and textures from [KhronosGroup/glTF-Sample-Assets](https://github.com/KhronosGroup/glTF-Sample-Assets) - smoke particle texture by Freepik: https://www.freepik.com/free-vector/cartoon-smoke-element-animation-frames_13763535.htm +- fire particle texture by macrovector: https://www.freepik.com/free-vector/light-fire-flames-animation-collection_10271988.htm \ No newline at end of file diff --git a/Samples/Rendering/main.cpp b/Samples/Rendering/main.cpp index 77a8424..f3e6b5b 100644 --- a/Samples/Rendering/main.cpp +++ b/Samples/Rendering/main.cpp @@ -31,13 +31,21 @@ struct RenderingApp : public RavEngine::App { struct SmokeParticleMaterial : public RavEngine::BillboardParticleMaterial { - SmokeParticleMaterial() : BillboardParticleMaterial("SmokeParticleInit", "SmokeParticleUpdate","default_billboard_particle","default_billboard_particle") {} //TODO: fill with shader names + SmokeParticleMaterial() : BillboardParticleMaterial("SmokeParticleInit", "SmokeParticleUpdate","default_billboard_particle","default_billboard_particle") {} uint16_t ParticleUserDataSize() const final { return 0; // needs no extra data } }; +struct FireParticleMaterial : public RavEngine::BillboardParticleMaterial { + FireParticleMaterial() : BillboardParticleMaterial("FireParticleInit", "FireParticleUpdate", "default_billboard_particle", "default_billboard_particle") {}; + + uint16_t ParticleUserDataSize() const final { + return 0; + } +}; + struct Level : public RavEngine::World { GameObject camRoot, camHeadUD; @@ -104,17 +112,27 @@ struct Level : public RavEngine::World { lightsEntity.GetTransform().LocalRotateDelta(vector3{ deg_to_rad(45), deg_to_rad(45),0 }); - auto continuousParticleEntity = Instantiate(); + auto smokeParticleEntity = Instantiate(); auto smokeMat = RavEngine::New(); smokeMat->spriteTex = Texture::Manager::Get("smoke.png"); smokeMat->spriteDim = { .numSpritesWidth = 3, .numSpritesHeight = 3 }; - auto& smokeEmitter = continuousParticleEntity.EmplaceComponent(8192, smokeMat); // number of particles we want + auto& smokeEmitter = smokeParticleEntity.EmplaceComponent(8192, smokeMat); // number of particles we want //smokeEmitter.mode = ParticleEmitter::Mode::Burst; smokeEmitter.Play(); - smokeParticle = { continuousParticleEntity }; + smokeParticle = { smokeParticleEntity }; + + auto fireParticleEntity = Instantiate(); + auto fireMat = New(); + fireMat->spriteTex = Texture::Manager::Get("fire.png"); + fireMat->spriteDim = { + .numSpritesWidth = 11, + .numSpritesHeight = 1 + }; + auto& fireEmitter = fireParticleEntity.EmplaceComponent(8192, fireMat); + fireEmitter.Play(); SetupInputs(); diff --git a/Samples/Rendering/shaders/FireParticleInit.csh b/Samples/Rendering/shaders/FireParticleInit.csh new file mode 100644 index 0000000..6f46f19 --- /dev/null +++ b/Samples/Rendering/shaders/FireParticleInit.csh @@ -0,0 +1,43 @@ +struct ParticleData{ + vec3 pos; + vec2 scale; + uint animationFrame; +}; + +float rand(in vec2 ip) { + const float seed = 12345678; + uvec2 p = uvec2(floatBitsToUint(ip.x), floatBitsToUint(ip.y)); + uint s = floatBitsToUint(seed); + s ^= (s ^ ((~p.x << s) + (~p.y << s))); + + p ^= (p << 17U); + p ^= ((p ^ s) >> 13U); + p ^= (p << 5U); + p ^= ((s + (s&(p.x^p.y))) >> 3U); + + uint n = (p.x*s+p.y)+((p.x ^ p.y) << ~p.x ^ s) + ((p.x ^ p.y) << ~p.y ^ s); + return float(n*50323U) / float(0xFFFFFFFFU); +} + + +ParticleData init(ParticleInitData initData) +{ + uint particleID = initData.particleID; + + ParticleData data; + data.scale = vec2(0.1,1); + vec4 pos = vec4( + rand(vec2(particleID,particleID)), + rand(vec2(particleID * 2,particleID * 2)), + rand(vec2(particleID / 2,particleID / 2)), + 1 + ); + + pos = initData.emitterModel * pos; + + data.pos = pos.xyz; + + data.animationFrame = 0; + + return data; +} \ No newline at end of file diff --git a/Samples/Rendering/shaders/FireParticleInit.json b/Samples/Rendering/shaders/FireParticleInit.json new file mode 100644 index 0000000..bb23d36 --- /dev/null +++ b/Samples/Rendering/shaders/FireParticleInit.json @@ -0,0 +1,5 @@ +{ + "shader": "FireParticleInit.csh", + "type": "particle-init", + "stage": "compute" +} \ No newline at end of file diff --git a/Samples/Rendering/shaders/FireParticleUpdate.csh b/Samples/Rendering/shaders/FireParticleUpdate.csh new file mode 100644 index 0000000..b0acad3 --- /dev/null +++ b/Samples/Rendering/shaders/FireParticleUpdate.csh @@ -0,0 +1,59 @@ +#include "ravengine_shader.glsl" + +layout(push_constant, std430) uniform UniformBufferObject{ + float fpsScale; +} ubo; + + +struct ParticleData{ + vec3 pos; + vec2 scale; + uint animationFrame; +}; + + +float rand(in vec2 ip) { + const float seed = 12345678; + uvec2 p = uvec2(floatBitsToUint(ip.x), floatBitsToUint(ip.y)); + uint s = floatBitsToUint(seed); + s ^= (s ^ ((~p.x << s) + (~p.y << s))); + + p ^= (p << 17U); + p ^= ((p ^ s) >> 13U); + p ^= (p << 5U); + p ^= ((s + (s&(p.x^p.y))) >> 3U); + + uint n = (p.x*s+p.y)+((p.x ^ p.y) << ~p.x ^ s) + ((p.x ^ p.y) << ~p.y ^ s); + return float(n*50323U) / float(0xFFFFFFFFU); +} + +const float maxLife = 20; + +void update(inout ParticleData data, inout float newLife, uint particleID) +{ + data.scale += ubo.fpsScale * 0.05; + + data.pos.y += ubo.fpsScale * 0.01; + + vec2 movevec = vec2( + rand(vec2(particleID, particleID)) * 2 - 1, + rand(vec2(particleID * 2, particleID * 2)) * 2 - 1 + ); + + float life = maxLife; + + movevec *= 0.02; + + data.pos.x += movevec.x; + data.pos.z += movevec.y; + + newLife += ubo.fpsScale; + + data.animationFrame = uint(remap(newLife,0,life,0,11)); + + if (newLife > life){ + // destroy the particle + + newLife = 0; + } +} \ No newline at end of file diff --git a/Samples/Rendering/shaders/FireParticleUpdate.json b/Samples/Rendering/shaders/FireParticleUpdate.json new file mode 100644 index 0000000..2fa5b01 --- /dev/null +++ b/Samples/Rendering/shaders/FireParticleUpdate.json @@ -0,0 +1,5 @@ +{ + "shader": "FireParticleUpdate.csh", + "type": "particle-update", + "stage": "compute" +} \ No newline at end of file diff --git a/Samples/Rendering/textures/fire.png b/Samples/Rendering/textures/fire.png new file mode 100644 index 0000000..5d57d09 Binary files /dev/null and b/Samples/Rendering/textures/fire.png differ