Add flips particle rendering for vulkan

This commit is contained in:
Benau 2022-10-14 10:17:58 +08:00
parent 46f44b5d59
commit 1fc460ff4e
5 changed files with 87 additions and 15 deletions

View File

@ -23,8 +23,12 @@
#include "IParticleSystemSceneNode.h"
#include <algorithm>
#include <cmath>
#include <limits>
#include "../source/Irrlicht/os.h"
#include "quaternion.h"
namespace GE
{
// ============================================================================
@ -71,11 +75,11 @@ void ObjectData::init(irr::scene::ISceneNode* node, int material_id,
// ============================================================================
void ObjectData::init(irr::scene::IBillboardSceneNode* node, int material_id,
const irr::core::quaternion& rotation)
const btQuaternion& rotation)
{
memcpy(&m_translation_x, &node->getAbsoluteTransformation()[12],
sizeof(float) * 3);
memcpy(m_rotation, &rotation, sizeof(irr::core::quaternion));
memcpy(m_rotation, &rotation[0], sizeof(btQuaternion));
irr::core::vector2df billboard_size = node->getSize();
m_scale_x = billboard_size.X / 2.0f;
m_scale_y = billboard_size.Y / 2.0f;
@ -95,13 +99,62 @@ void ObjectData::init(irr::scene::IBillboardSceneNode* node, int material_id,
m_custom_vertex_color = output;
} // init
// ============================================================================
std::vector<float> g_flips_data;
// ============================================================================
void ObjectData::init(const irr::scene::SParticle& particle, int material_id,
const irr::core::quaternion& rotation)
const btQuaternion& rotation,
const irr::core::vector3df& view_position, bool flips,
bool backface_culling)
{
memcpy(&m_translation_x, &particle.pos, sizeof(float) * 3);
memcpy(m_rotation, &rotation, sizeof(irr::core::quaternion));
m_scale_x = particle.size.Width / 2.0f;
float scale_x = particle.size.Width / 2.0f;
if (flips)
{
// Following stk_particle.cpp
const unsigned particle_index = particle.startTime;
const float lifetime = particle.startSize.Width;
const float pi = 3.14159265358979323846f;
while (particle_index + 1 > g_flips_data.size())
{
// Maximum 3 rotation around axis (0, 1, 0) during lifetime
g_flips_data.push_back(pi * 2.0f * 3.0f * os::Randomizer::frand() *
(g_flips_data.size() % 2 == 0 ? 1.0f : -1.0f));
}
float angle = fmodf(lifetime * g_flips_data[particle_index],
pi * 2.0f);
btQuaternion rotated(btVector3(0.0f, 1.0f, 0.0f), angle);
rotated = btQuaternion(rotation[0], rotation[1], rotation[2],
-rotation[3]) * rotated;
rotated.normalize();
// Conjugated quaternion in glsl
rotated[3] = -rotated[3];
memcpy(m_rotation, &rotated[0], sizeof(btQuaternion));
if (backface_culling)
{
irr::core::quaternion q(rotated[0], rotated[1], rotated[2],
-rotated[3]);
irr::core::matrix4 m;
q.getMatrix(m, particle.pos);
irr::core::vector3df tri[3] =
{
irr::core::vector3df( 1.0f, -1.0f, 0.0f),
irr::core::vector3df( 1.0f, 1.0f, 0.0f),
irr::core::vector3df(-1.0f, 1.0f, 0.0f)
};
m.transformVect(tri[0]);
m.transformVect(tri[1]);
m.transformVect(tri[2]);
irr::core::vector3df normal = (tri[1] - tri[0])
.crossProduct(tri[2] - tri[0]);
float dot_product = (tri[0] - view_position).dotProduct(normal);
if (dot_product < 0.0f)
scale_x = -scale_x;
}
}
else
memcpy(m_rotation, &rotation[0], sizeof(btQuaternion));
m_scale_x = scale_x;
m_scale_y = particle.size.Height / 2.0f;
m_scale_z = 0.0f;
m_skinning_offset = 0;
@ -400,6 +453,8 @@ start:
k.m_hue_change == key.m_hue_change;
});
}
const PipelineSettings& settings =
m_graphics_pipelines[cur_shader].second;
for (auto& r : q.second)
{
irr::scene::ISceneNode* node = r.first;
@ -449,10 +504,12 @@ start:
goto start;
}
ObjectData* obj = (ObjectData*)mapped_addr;
bool flips = pn->getFlips();
for (unsigned i = 0; i < ps; i++)
{
obj[i].init(particles[i], material_id,
m_billboard_rotation);
m_billboard_rotation, m_view_position, flips,
settings.m_backface_culling);
written_size += sizeof(ObjectData);
mapped_addr += sizeof(ObjectData);
}
@ -507,8 +564,6 @@ start:
}
else
cmd.firstInstance = it->m_first_instance;
const PipelineSettings& settings =
m_graphics_pipelines[cur_shader].second;
std::string sorting_key =
std::string(1, settings.m_drawing_priority) + cur_shader;
m_cmds.push_back({ cmd, cur_shader, sorting_key, p.first,
@ -699,7 +754,8 @@ void GEVulkanDrawCall::prepare(GEVulkanCameraSceneNode* cam)
{
reset();
m_culling_tool->init(cam);
m_billboard_rotation = MiniGLM::getQuaternion(cam->getViewMatrix());
m_view_position = cam->getPosition();
m_billboard_rotation = MiniGLM::getBulletQuaternion(cam->getViewMatrix());
} // prepare
// ----------------------------------------------------------------------------

View File

@ -12,11 +12,13 @@
#include "vulkan_wrapper.h"
#include "matrix4.h"
#include "quaternion.h"
#include "vector3d.h"
#include "ESceneNodeTypes.h"
#include "SColor.h"
#include "SMaterial.h"
#include "LinearMath/btQuaternion.h"
namespace irr
{
namespace scene
@ -55,10 +57,12 @@ struct ObjectData
int skinning_offset, int irrlicht_material_id);
// ------------------------------------------------------------------------
void init(irr::scene::IBillboardSceneNode* node, int material_id,
const irr::core::quaternion& rotation);
const btQuaternion& rotation);
// ------------------------------------------------------------------------
void init(const irr::scene::SParticle& particle, int material_id,
const irr::core::quaternion& rotation);
const btQuaternion& rotation,
const irr::core::vector3df& view_position, bool flips,
bool backface_culling);
};
struct PipelineSettings
@ -100,7 +104,9 @@ private:
std::map<TexturesList, GESPMBuffer*> m_billboard_buffers;
irr::core::quaternion m_billboard_rotation;
irr::core::vector3df m_view_position;
btQuaternion m_billboard_rotation;
std::unordered_map<GESPMBuffer*, std::unordered_map<std::string,
std::vector<std::pair<irr::scene::ISceneNode*, int> > > >

View File

@ -505,6 +505,7 @@ public:
const core::vector3df& pivotPoint = core::vector3df(0.0f,0.0f,0.0f) ) = 0;
virtual core::array<SParticle>& getParticles() = 0;
virtual bool getFlips() const { return false; }
};
} // end namespace scene

View File

@ -508,7 +508,10 @@ void STKParticle::OnRegisterSceneNode()
Buffer->BoundingBox.reset(AbsoluteTransformation.getTranslation());
for (unsigned i = 0; i < m_particles_generating.size(); i++)
{
if (m_particles_generating[i].m_size == 0.0f)
if (m_particles_generating[i].m_size == 0.0f ||
std::isnan(m_particles_generating[i].m_position.X) ||
std::isnan(m_particles_generating[i].m_position.Y) ||
std::isnan(m_particles_generating[i].m_position.Z))
{
continue;
}
@ -529,6 +532,12 @@ void STKParticle::OnRegisterSceneNode()
p.color.setGreen(core::clamp((int)(ret.Y * 255.0f), 0, 255));
p.color.setBlue(core::clamp((int)(ret.Z * 255.0f), 0, 255));
p.color.setAlpha(core::clamp((int)(alpha * 255.0f), 0, 255));
if (irr_driver->getVideoDriver()->getDriverType() == video::EDT_VULKAN)
{
// Only used in ge_vulkan_draw_call.cpp
p.startTime = i;
p.startSize.Width = m_particles_generating[i].m_lifetime;
}
Particles.push_back(p);
}
core::matrix4 inv(AbsoluteTransformation, core::matrix4::EM4CONST_INVERSE);

View File

@ -137,7 +137,7 @@ public:
// ------------------------------------------------------------------------
void setFlips() { m_flips = true; }
// ------------------------------------------------------------------------
bool getFlips() const { return m_flips; }
virtual bool getFlips() const { return m_flips; }
// ------------------------------------------------------------------------
unsigned getMaxCount() const { return m_max_count; }
// ------------------------------------------------------------------------