fix spark

This commit is contained in:
Vlad 2025-12-11 20:09:41 +06:00
parent b855cff0e6
commit 115cbbb7fa
4 changed files with 760 additions and 673 deletions

122
Game.cpp
View File

@ -117,20 +117,20 @@ namespace ZL
return boxCoordsArr;
}
Game::Game()
Game::Game()
: window(nullptr)
, glContext(nullptr)
, newTickCount(0)
, lastTickCount(0)
{
{
std::vector<Vector3f> emissionPoints = {
Vector3f{-2.1f, 0.9f, 5.0f},
Vector3f{2.1f, 0.9f, 5.0f}
};
sparkEmitter = SparkEmitter(emissionPoints, 100.0f);
}
}
Game::~Game() {
Game::~Game() {
if (glContext) {
SDL_GL_DeleteContext(glContext);
}
@ -138,9 +138,9 @@ Game::~Game() {
SDL_DestroyWindow(window);
}
SDL_Quit();
}
}
void Game::setup() {
void Game::setup() {
glContext = SDL_GL_CreateContext(ZL::Environment::window);
ZL::BindOpenGlFunctions();
@ -200,30 +200,15 @@ void Game::setup() {
sparkTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/spark.png", CONST_ZIP_FILE));
/*singleSpark.data.PositionData.push_back({-1, -1, 0});
singleSpark.data.PositionData.push_back({ -1, 1, 0 });
singleSpark.data.PositionData.push_back({ 1, 1, 0 });
singleSpark.data.PositionData.push_back({ -1, -1, 0 });
singleSpark.data.PositionData.push_back({ 1, 1, 0 });
singleSpark.data.PositionData.push_back({ 1, -1, 0 });
singleSpark.data.TexCoordData.push_back({0,0});
singleSpark.data.TexCoordData.push_back({ 0,1 });
singleSpark.data.TexCoordData.push_back({1,1});
singleSpark.data.TexCoordData.push_back({0,0});
singleSpark.data.TexCoordData.push_back({ 1,1 });
singleSpark.data.TexCoordData.push_back({ 1,0 });
singleSpark.RefreshVBO();*/
sparkQuad.data = CreateRect2D({ 0, 0 }, { 0.08f, 0.08f }, 0);
sparkQuad.RefreshVBO();
renderer.InitOpenGL();
}
}
void Game::drawCubemap()
{
void Game::drawCubemap()
{
static const std::string defaultShaderName = "default";
static const std::string envShaderName = "env";
static const std::string vPositionName = "vPosition";
@ -254,19 +239,52 @@ void Game::drawCubemap()
renderer.shaderManager.PopShader();
CheckGlError();
}
}
void Game::drawEffects()
{
if (sparkEmitter.getActiveParticleCount() == 0) {
return;
}
sparkQuad.data.PositionData.clear();
sparkQuad.data.TexCoordData.clear();
const auto& particles = sparkEmitter.getParticles();
for (const auto& particle : particles) {
if (!particle.active) continue;
Vector3f pos = particle.position;
float size = 0.04f * particle.scale;
sparkQuad.data.PositionData.push_back({ pos.v[0] - size, pos.v[1] - size, pos.v[2] });
sparkQuad.data.TexCoordData.push_back({ 0.0f, 0.0f });
sparkQuad.data.PositionData.push_back({ pos.v[0] - size, pos.v[1] + size, pos.v[2] });
sparkQuad.data.TexCoordData.push_back({ 0.0f, 1.0f });
sparkQuad.data.PositionData.push_back({ pos.v[0] + size, pos.v[1] + size, pos.v[2] });
sparkQuad.data.TexCoordData.push_back({ 1.0f, 1.0f });
sparkQuad.data.PositionData.push_back({ pos.v[0] - size, pos.v[1] - size, pos.v[2] });
sparkQuad.data.TexCoordData.push_back({ 0.0f, 0.0f });
sparkQuad.data.PositionData.push_back({ pos.v[0] + size, pos.v[1] + size, pos.v[2] });
sparkQuad.data.TexCoordData.push_back({ 1.0f, 1.0f });
sparkQuad.data.PositionData.push_back({ pos.v[0] + size, pos.v[1] - size, pos.v[2] });
sparkQuad.data.TexCoordData.push_back({ 1.0f, 0.0f });
}
if (sparkQuad.data.PositionData.empty()) return;
sparkQuad.RefreshVBO();
void Game::drawEffects()
{
static const std::string defaultShaderName = "default";
static const std::string vPositionName = "vPosition";
static const std::string vTexCoordName = "vTexCoord";
static const std::string textureUniformName = "Texture";
if (sparkEmitter.getActiveParticleCount() == 0) {
return;
}
renderer.shaderManager.PushShader(defaultShaderName);
renderer.RenderUniform1i(textureUniformName, 0);
renderer.EnableVertexAttribArray(vPositionName);
@ -278,28 +296,22 @@ void Game::drawEffects()
glBindTexture(GL_TEXTURE_2D, sparkTexture->getTexID());
const auto& particles = sparkEmitter.getParticles();
for (const auto& particle : particles) {
if (!particle.active) continue;
renderer.PushMatrix();
renderer.LoadIdentity();
renderer.TranslateMatrix({ 0, 0, -1.0f * Environment::zoom });
renderer.TranslateMatrix(particle.position);
renderer.ScaleMatrix(particle.scale);
renderer.RotateMatrix(Environment::inverseShipMatrix);
renderer.DrawVertexRenderStruct(sparkQuad);
renderer.PopMatrix();
}
renderer.PopProjectionMatrix();
renderer.DisableVertexAttribArray(vPositionName);
renderer.DisableVertexAttribArray(vTexCoordName);
renderer.shaderManager.PopShader();
CheckGlError();
}
}
void Game::drawShip()
{
void Game::drawShip()
{
static const std::string defaultShaderName = "default";
static const std::string envShaderName = "env";
static const std::string vPositionName = "vPosition";
@ -332,10 +344,10 @@ void Game::drawShip()
renderer.shaderManager.PopShader();
CheckGlError();
}
}
void Game::drawBoxes()
{
void Game::drawBoxes()
{
static const std::string defaultShaderName = "default";
static const std::string envShaderName = "env";
static const std::string vPositionName = "vPosition";
@ -373,9 +385,9 @@ void Game::drawBoxes()
renderer.shaderManager.PopShader();
CheckGlError();
}
}
void Game::drawScene() {
void Game::drawScene() {
static const std::string defaultShaderName = "default";
static const std::string envShaderName = "env";
static const std::string vPositionName = "vPosition";
@ -394,9 +406,9 @@ void Game::drawScene() {
drawBoxes();
CheckGlError();
}
}
void Game::processTickCount() {
void Game::processTickCount() {
if (lastTickCount == 0) {
lastTickCount = SDL_GetTicks64();
@ -446,7 +458,7 @@ void Game::processTickCount() {
if (fabs(Environment::shipVelocity) > 0.01f)
{
Vector3f velocityDirection = { 0,0, -Environment::shipVelocity*delta / 1000.f };
Vector3f velocityDirection = { 0,0, -Environment::shipVelocity * delta / 1000.f };
Vector3f velocityDirectionAdjusted = MultMatrixVector(Environment::shipMatrix, velocityDirection);
Environment::shipPosition = Environment::shipPosition + velocityDirectionAdjusted;
@ -454,9 +466,9 @@ void Game::processTickCount() {
lastTickCount = newTickCount;
}
}
}
void Game::render() {
void Game::render() {
SDL_GL_MakeCurrent(ZL::Environment::window, glContext);
ZL::CheckGlError();
@ -467,8 +479,8 @@ void Game::render() {
processTickCount();
SDL_GL_SwapWindow(ZL::Environment::window);
}
void Game::update() {
}
void Game::update() {
SDL_Event event;
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
@ -522,6 +534,6 @@ void Game::update() {
}
}
render();
}
}
} // namespace ZL

8
Game.h
View File

@ -16,8 +16,8 @@ namespace ZL {
};
class Game {
public:
class Game {
public:
Game();
~Game();
@ -27,7 +27,7 @@ public:
bool shouldExit() const { return Environment::exitGameLoop; }
private:
private:
void processTickCount();
void drawScene();
void drawCubemap();
@ -62,6 +62,6 @@ private:
//VertexRenderStruct singleSpark;
SparkEmitter sparkEmitter;
VertexRenderStruct sparkQuad;
};
};
} // namespace ZL

View File

@ -6,28 +6,59 @@
namespace ZL {
SparkEmitter::SparkEmitter()
: emissionRate(100.0f), isActive(true) {
particles.resize(200);
: emissionRate(100.0f), isActive(true), buffersDirty(true), maxParticles(200) {
particles.resize(maxParticles);
positionBuffer.resize(maxParticles * 4, 0.0f);
texCoordBuffer.resize(maxParticles * 2, 0.0f);
lastEmissionTime = std::chrono::steady_clock::now();
}
SparkEmitter::SparkEmitter(const std::vector<Vector3f>& positions, float rate)
: emissionPoints(positions), emissionRate(rate), isActive(true) {
particles.resize(positions.size() * 100);
: emissionPoints(positions), emissionRate(rate), isActive(true),
buffersDirty(true), maxParticles(positions.size() * 100) {
particles.resize(maxParticles);
positionBuffer.resize(maxParticles * 4, 0.0f);
texCoordBuffer.resize(maxParticles * 2, 0.0f);
lastEmissionTime = std::chrono::steady_clock::now();
}
void SparkEmitter::setEmissionPoints(const std::vector<Vector3f>& positions) {
emissionPoints = positions;
particles.resize(positions.size() * 100);
maxParticles = positions.size() * 100;
particles.resize(maxParticles);
positionBuffer.resize(maxParticles * 4, 0.0f);
texCoordBuffer.resize(maxParticles * 2, 0.0f);
buffersDirty = true;
}
void SparkEmitter::setEmissionRate(float rateMs) {
emissionRate = rateMs;
void SparkEmitter::updateBuffers() {
if (!buffersDirty) return;
size_t bufferIndex = 0;
for (const auto& particle : particles) {
if (particle.active) {
positionBuffer[bufferIndex * 4] = particle.position.v[0];
positionBuffer[bufferIndex * 4 + 1] = particle.position.v[1];
positionBuffer[bufferIndex * 4 + 2] = particle.position.v[2];
positionBuffer[bufferIndex * 4 + 3] = particle.scale;
texCoordBuffer[bufferIndex * 2] = 0.0f;
texCoordBuffer[bufferIndex * 2 + 1] = 0.0f;
bufferIndex++;
}
}
void SparkEmitter::setActive(bool active) {
isActive = active;
for (size_t i = bufferIndex; i < maxParticles; i++) {
positionBuffer[i * 4] = 0.0f;
positionBuffer[i * 4 + 1] = 0.0f;
positionBuffer[i * 4 + 2] = 0.0f;
positionBuffer[i * 4 + 3] = 0.0f;
texCoordBuffer[i * 2] = 0.0f;
texCoordBuffer[i * 2 + 1] = 0.0f;
}
buffersDirty = false;
}
void SparkEmitter::update(float deltaTimeMs) {
@ -40,8 +71,11 @@ namespace ZL {
lastEmissionTime = currentTime;
}
bool anyChanged = false;
for (auto& particle : particles) {
if (particle.active) {
Vector3f oldPosition = particle.position;
particle.position.v[0] += particle.velocity.v[0] * deltaTimeMs / 1000.0f;
particle.position.v[1] += particle.velocity.v[1] * deltaTimeMs / 1000.0f;
particle.position.v[2] += particle.velocity.v[2] * deltaTimeMs / 1000.0f;
@ -50,16 +84,29 @@ namespace ZL {
if (particle.lifeTime >= particle.maxLifeTime) {
particle.active = false;
anyChanged = true;
}
else {
float lifeRatio = particle.lifeTime / particle.maxLifeTime;
particle.scale = 1.0f - lifeRatio * 0.8f;
if (oldPosition.v[0] != particle.position.v[0] ||
oldPosition.v[1] != particle.position.v[1] ||
oldPosition.v[2] != particle.position.v[2]) {
anyChanged = true;
}
}
}
}
if (anyChanged) {
buffersDirty = true;
}
}
void SparkEmitter::emit() {
if (emissionPoints.empty()) return;
bool emitted = false;
for (int i = 0; i < emissionPoints.size(); ++i) {
bool particleFound = false;
@ -72,6 +119,7 @@ namespace ZL {
particle.position = emissionPoints[i];
particle.emitterIndex = i;
particleFound = true;
emitted = true;
break;
}
}
@ -92,14 +140,19 @@ namespace ZL {
particles[oldestIndex].lifeTime = 0;
particles[oldestIndex].position = emissionPoints[i];
particles[oldestIndex].emitterIndex = i;
emitted = true;
}
}
if (emitted) {
buffersDirty = true;
}
}
void SparkEmitter::initParticle(SparkParticle& particle, int emitterIndex) {
particle.velocity = getRandomVelocity(emitterIndex);
particle.scale = 1.0f;
particle.maxLifeTime = 800.0f + (rand() % 400); // От 800 до 1200 мс
particle.maxLifeTime = 800.0f + (rand() % 400);
particle.emitterIndex = emitterIndex;
}
@ -144,4 +197,15 @@ namespace ZL {
return count;
}
size_t SparkEmitter::getActiveParticleBufferIndex(size_t particleIndex) const {
size_t activeIndex = 0;
for (size_t i = 0; i <= particleIndex; i++) {
if (particles[i].active) {
if (i == particleIndex) return activeIndex;
activeIndex++;
}
}
return 0;
}
} // namespace ZL

View File

@ -14,6 +14,7 @@ namespace ZL {
float maxLifeTime;
bool active;
int emitterIndex;
Vector2f texCoord;
SparkParticle() : position({ 0,0,0 }), velocity({ 0,0,0 }), scale(1.0f),
lifeTime(0), maxLifeTime(1000.0f), active(false), emitterIndex(0) {
@ -28,13 +29,16 @@ namespace ZL {
float emissionRate;
bool isActive;
std::vector<float> positionBuffer;
std::vector<float> texCoordBuffer;
bool buffersDirty;
int maxParticles;
public:
SparkEmitter();
SparkEmitter(const std::vector<Vector3f>& positions, float rate = 100.0f);
void setEmissionPoints(const std::vector<Vector3f>& positions);
void setEmissionRate(float rateMs);
void setActive(bool active);
void update(float deltaTimeMs);
void emit();
@ -42,6 +46,13 @@ namespace ZL {
const std::vector<SparkParticle>& getParticles() const;
size_t getActiveParticleCount() const;
const float* getPositionBuffer() const { return positionBuffer.data(); }
const float* getTexCoordBuffer() const { return texCoordBuffer.data(); }
size_t getBufferSize() const { return positionBuffer.size() / 4; }
void updateBuffers();
size_t getActiveParticleBufferIndex(size_t particleIndex) const;
private:
void initParticle(SparkParticle& particle, int emitterIndex);
Vector3f getRandomVelocity(int emitterIndex);