在寫 Render code 之前我們先來寫 Shader 吧
vertex shader:
#version 330 core
layout (location = 0) in vec4 vertex; // <vec2 position, vec2 texCoords>
out vec2 TexCoords;
out vec4 ParticleColor;
uniform mat4 transform;
uniform mat4 projection;
uniform vec4 color;
uniform float scale;
void main()
{
TexCoords = vertex.zw;
ParticleColor = color;
gl_Position = projection * transform * vec4((vertex.xy), 0.0, 1.0);
}
fragment shader
#version 330 core
in vec2 TexCoords;
in vec4 ParticleColor;
out vec4 color;
uniform sampler2D sprite;
void main()
{
color = (texture(sprite, TexCoords) * ParticleColor);
}
以上的 Shader 應該都很簡單清楚,都跟之前的差不多
Render 的 code
void EmitterSystem::render(entt::registry ®istry) {
auto group = registry.view<TransformComponent, EmitterComponent>();
for (auto entity : group) {
auto &transform = registry.get<TransformComponent>(entity);
auto &emitter = registry.get<EmitterComponent>(entity);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
shader -> bind();
for (auto &particles : emitter.particles) {
if(particles.life > 0.f) {
shader->setFloat2("offset", particles.pos);
shader->setFloat4("color", particles.currentColor);
glm::mat4 trans(1.f);
trans = glm::translate(trans, glm::vec3(particles.pos.x, particles.pos.y, 1.0f));
trans = glm::rotate(trans, glm::radians(particles.angle), glm::vec3(0.f, 0.f, 1.f));
trans = glm::scale(trans, glm::vec3(particles.currentSize ,particles.currentSize,1.0f));
shader->setMat4("transform", trans);
emitter.texture->bind();
vertexArray->bind();
glDrawArrays(GL_TRIANGLES, 0, 6);
vertexArray->unbind();
}
}
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
} // End EmitterSystem::render()
我們整個的遊戲流程大概會是這樣
void Game::Init() {
ResourceManager::loadShader("ptShader.glsl", "ptfShader.glsl", "particle");
auto& particleShader = ResourceManager::getShader("particle");
particleShader->bind();
particleShader->setInt("sprite", 0);
particleShader->setMat4("projection", projection);
ResourceManager::loadTexture("particle.png", "particle");
particleSystem.init(ResourceManager::getShader("particle"));
}
void Game::ProcessInput() {
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Q)) {
std::ifstream is("Fire.json");
std::string str((std::istreambuf_iterator<char>(is)), std::istreambuf_iterator<char>());
std::stringstream oos(str);
cereal::JSONInputArchive ar(oos);
EmitterData data;
ar(data);
auto emit = registry.create();
registry.emplace<TransformComponent>(emit, glm::vec2(sf::Mouse::getPosition(window_).x, sf::Mouse::getPosition(window_).y), glm::vec2(100.f, 100.f));
registry.emplace<EmitterComponent>(emit, ResourceManager::getTexture("5"), data);
registry.emplace<TagComponent>(emit);
emitterSystem.initEmitter(registry, emit);
}
}
void Game::Update(float) {
particleSystem.update(registry, dt);
}
void Game::Render() {
particleSystem.render(registry);
}
這樣就完成了!