perf: avoid useless copy of particle positions in renderpass

This commit is contained in:
Matias 2025-07-16 22:57:26 +02:00
parent 4885426233
commit e0475aa880
No known key found for this signature in database
GPG Key ID: ED35A6AC65A06B69
4 changed files with 46 additions and 33 deletions

View File

@ -17,7 +17,9 @@ class CWobblyWindow {
static inline float s_dampingStrength = 12.f;
static inline float s_drag = 0.4f;
std::vector<SParticle> m_particles;
std::vector<float> m_particlePositions;
std::vector<Vector2D> m_particleVelocities;
std::vector<Vector2D> m_targetPositions;
std::optional<Vector2D> m_grabPosition {std::nullopt};
Vector2D m_windowMovement;
@ -25,5 +27,7 @@ class CWobblyWindow {
CWobblyWindow();
bool step(Time::steady_tp time);
void applyMovement(const Vector2D& movement);
};
#endif

View File

@ -73,10 +73,7 @@ void hkRenderWindow(
wobble.m_grabPosition = std::nullopt;
}
wobble.m_windowMovement = (pos - g_windowPositions[pWindow]) / windowSize;
for (auto&& particle : wobble.m_particles) {
particle.position -= wobble.m_windowMovement;
}
wobble.applyMovement((pos - g_windowPositions[pWindow]) / windowSize);
// update last pos
g_windowPositions[pWindow] = pos;

View File

@ -165,16 +165,13 @@ void CRenderWobblyWindowPassElement::draw(const CRegion& damage) {
// TODO: these should never be nan
// if (not std::isnan(wobble.m_particles[0].position.x)) {
// TODO: we need the particle positions in their own vec, to avoid this copy
std::vector<float> verts;
verts.reserve(vertsPerRow * vertsPerRow * 2);
for (auto&& particle : wobble.m_particles) {
verts.push_back(particle.position.x);
verts.push_back(particle.position.y);
}
GLCALL(glBindBuffer(GL_ARRAY_BUFFER, s_VBO));
GLCALL(glBufferSubData(GL_ARRAY_BUFFER, 0, verts.size() * sizeof(float), verts.data()));
GLCALL(glBufferSubData(
GL_ARRAY_BUFFER,
0,
wobble.m_particlePositions.size() * sizeof(float),
wobble.m_particlePositions.data()
));
// }
} else {
// restore default verts

View File

@ -5,11 +5,15 @@
CWobblyWindow::CWobblyWindow() {
auto&& verts = CRenderWobblyWindowPassElement::s_baseVerts;
m_particles.reserve(verts.size() / 2);
m_targetPositions.reserve(verts.size() / 2);
// copy directly
m_particlePositions = verts;
// init empty
m_particleVelocities.resize(verts.size() / 2);
m_targetPositions.reserve(verts.size() / 2);
for (unsigned int i {}; i < verts.size(); i += 2) {
m_particles.push_back(SParticle {Vector2D {verts[i], verts[i + 1]}, {}});
m_targetPositions.push_back(Vector2D {verts[i], verts[i + 1]});
}
}
@ -22,42 +26,44 @@ bool CWobblyWindow::step(Time::steady_tp time) {
Vector2D totalVel {};
for (unsigned int i {}; i < m_particles.size(); i++) {
auto&& particle = m_particles[i];
auto&& particlePositon = particle.position;
for (unsigned int i {}; i < m_particlePositions.size() / 2; i++) {
// TODO: avoid float -> double promotion
const auto& pos = Vector2D {m_particlePositions[i * 2], m_particlePositions[i * 2 + 1]};
auto&& vel = m_particleVelocities[i];
auto&& targetPosition = m_targetPositions[i];
const Vector2D directionToTarget = targetPosition - particlePositon;
const Vector2D directionToTarget = targetPosition - pos;
if (m_grabPosition.has_value()) {
const float distanceToDragPosition = m_grabPosition.value().distance(particlePositon);
const float distanceToDragPosition = m_grabPosition.value().distance(pos);
const float dragStrength = std::clamp(distanceToDragPosition, 0.f, 1.f);
particle.position += m_windowMovement * dragStrength;
m_particlePositions[i * 2] += m_windowMovement.x * dragStrength;
m_particlePositions[i * 2 + 1] += m_windowMovement.y * dragStrength;
}
const Vector2D springForce =
directionToTarget * s_springStrength - particle.velocity * s_dampingStrength;
particle.velocity += springForce * dt;
const Vector2D springForce = directionToTarget * s_springStrength - vel * s_dampingStrength;
vel += springForce * dt;
// Apply drag
const Vector2D dragForceVector = (particle.velocity * particle.velocity) * -s_drag;
const Vector2D dragForceVector = (vel * vel) * -s_drag;
// * Area
auto dir = particle.velocity;
auto dir = vel;
float magnitude = dir.normalize();
if (magnitude != 0)
particle.velocity += (dragForceVector * dir) * dt;
vel += (dragForceVector * dir) * dt;
// Apply velocity
particle.position += particle.velocity * dt;
m_particlePositions[i * 2] += vel.x * dt;
m_particlePositions[i * 2 + 1] += vel.y * dt;
totalVel += particle.velocity;
totalVel += vel;
}
const bool shouldEnd =
m_windowMovement.size() == 0 and totalVel.size() / m_particles.size() < .001f;
const bool shouldEnd = m_windowMovement.size() == 0
and totalVel.size() / (m_particlePositions.size() / 2.f) < .001f;
// std::println(
// "Top left: {}, totalVel: {}",
@ -68,3 +74,12 @@ bool CWobblyWindow::step(Time::steady_tp time) {
return shouldEnd;
}
void CWobblyWindow::applyMovement(const Vector2D& movement) {
m_windowMovement = movement;
for (unsigned int i = 0; i < m_particlePositions.size() / 2; i++) {
m_particlePositions[i * 2] -= movement.x;
m_particlePositions[i * 2 + 1] -= movement.y;
}
}