C++ / OpenGL Particle Generator help

Started by
14 comments, last by alx119 6 years, 10 months ago

I wrote a code for a particle generator. It runs, but it doesn't show anything. Here is the code:

Emitter.cpp:

#include "Emitter.h"
 
 
Emitter::Emitter(GLuint nrParticles, glm::vec3 position, GLfloat radius, char *imgName)
{
this->m_Position = position;
this->m_radius = radius;
 
for (int i = 0; i < nrParticles; i++)
{
this->particles.push_back(Particle(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 0.0f), 0.0f, "blur.png"));
}
 
}
 
void Emitter::Draw(Shader &shader)
{
for (int i = 0; i < particles.size() - 1; i++)
{
particles[i].Draw(shader);
}
}
 
void Emitter::Update(GLfloat dt)
{
for (int i = 0; i <= particles.size() - 1; i++)
{
particles[i].Update(dt);
}
}
 
void Emitter::SetParticlesAttributes()
{
 
for (int i = 0; i <= particles.size() - 1; i++)
{
particles[i].setLife(10.0f); //(((rand() % 10) + 1) * 15);
particles[i].setVelocity(glm::vec3(0.0f, 2.0f, 0.0f)); //(((rand() % 10) + 1) * 2));
}
}

Particle.cpp:
#include "Particle.h"
#include "Camera.h"
GLfloat vertices[] = {
0.5f,  0.5f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f,
-0.5f,  0.5f, 0.0f, 0.0f, 1.0f
};
 
//Camera camera(glm::vec3(0.0f, 0.0f, 10.0f));
Vbo vbo;
Ebo ebo;
 
Texture texture;
 
GLuint indices[] = {  // Note that we start from 0!
0, 1, 3,   // First Triangle
1, 2, 3    // Second Triangle
};
 
Particle::Particle(glm::vec3 position, glm::vec3 velocity, GLfloat life, GLchar *imgName)
{
this->m_Position = position;
this->m_Velocity = velocity;
this->m_Life = life;
 
this->vao.Init(1);
vbo.Init(1);
ebo.Init(1);
 
this->vao.Bind();
vbo.Bind(vertices, 20);
ebo.Bind(indices, 6);
this->vao.AttribPointer(0, 3, 5, 0);
this->vao.AttribPointer(1, 2, 5, 3);
this->vao.UnBind();
 
texture.Init(1, imgName);
 
}
 
void Particle::Draw(Shader &shader)
{
 
shader.Use();
 
glm::mat4 model;
glm::mat4 view;
glm::mat4 projection;
 
model = glm::translate(model, glm::vec3(this->m_Position));
model = glm::scale(model, glm::vec3(30.0f, 30.0f, 0.0f));
view = glm::lookAt(glm::vec3(0.0f, 0.0f, 3.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
projection = glm::perspective(45.0f, (float)1600 / (float)1200, 0.1f, 100.0f);
 
GLuint modelLoc(glGetUniformLocation(shader.Program, "model"));
GLuint viewLoc(glGetUniformLocation(shader.Program, "view"));
GLuint projLoc(glGetUniformLocation(shader.Program, "projection"));
 
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));
 
texture.Bind();
glUniform1i(glGetUniformLocation(shader.Program, "ourTexture"), 0);
 
this->vao.Bind();
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
this->vao.UnBind();
 
}
 
void Particle::Update(GLfloat dt)
{
if (this->m_Life > 0)
{
this->m_Position += m_Velocity;
}
else
{
//m_Life -= dt;
}
}
 
void Particle::setLife(GLfloat life)
{
this->m_Life = life;
}
GLfloat Particle::getLife()
{
return this->m_Life;
}
 
void Particle::setPosition(glm::vec3 position)
{
this->m_Position = position;
}
glm::vec3 Particle::getPosition()
{
return this->m_Position;
}
 
void Particle::setVelocity(glm::vec3 velocity)
{
this->m_Velocity = velocity;
}
glm::vec3 Particle::getVelocity()
{
return this->m_Velocity;
}

Main.cpp:
#include <iostream> 
#include <glad/glad.h>
#include<KHR\khrplatform.h>
//GLFW
#include <glfw3.h>
 
#include "Shader.h"
#include "Camera.h"
 
// GLM
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "stb_image.h"
 
#include "Emitter.h"
 
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow *window);
 
// settings
const unsigned int SCR_WIDTH = 1600;
const unsigned int SCR_HEIGHT = 1200;
 
Emitter *e1;
 
int main()
{
// glfw: initialize and configure
// ------------------------------
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
//glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X
 
// glfw window creation
// --------------------
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
 
// glad: load all OpenGL function pointers
// ---------------------------------------
 
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
 
// build and compile our shader zprogram
// ------------------------------------
Shader shader("particle.vs", "particle.frag");
e1 = new Emitter(100, glm::vec3(0.0f), 30.0f, "blur.png");
 
// render loop
// -----------
while (!glfwWindowShouldClose(window))
{
GLfloat dt = glfwGetTime();
// input
// -----
processInput(window);
e1->Update(dt);
 
// render
// ------
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
 
e1->Draw(shader);
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
// -------------------------------------------------------------------------------
glfwSwapBuffers(window);
glfwPollEvents();
}
 
// optional: de-allocate all resources once they've outlived their purpose:
// ------------------------------------------------------------------------
 
// glfw: terminate, clearing all previously allocated GLFW resources.
// ------------------------------------------------------------------
glfwTerminate();
return 0;
}
 
// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
void processInput(GLFWwindow *window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
 
if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS)
{
std::cout << "Space Pressed" << std::endl;
e1->SetParticlesAttributes();
}
}
 
// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
// make sure the viewport matches the new window dimensions; note that width and 
// height will be significantly larger than specified on retina displays.
glViewport(0, 0, width, height);
}

I tried to debugged it, but I didn't succeed to figure out the problem. :(
Little help please ? :D
Advertisement

You could try using CodeXL to see if your OpenGL commands are actually handles by the gpu. This should also show you the GPU state and such so that you can see what is actually wrong.

Renderdoc is another tool for this but the openGL support for that is not optimal had it been d3d or vullkan you could have used that tool which is really good at debugging graphics and is used in the industry by AAA game companies.

Worked on titles: CMR:DiRT2, DiRT 3, DiRT: Showdown, GRID 2, theHunter, theHunter: Primal, Mad Max, Watch Dogs: Legion

@fleabay: I copied from a tutorial just the main.cpp. The rest of the classes I wrote them. :P

@NightCreature83: I'm pretty sure the OpenGL commands are handled by the gpu because is not the first time when I use them. I already created a snake and a pong game. :P

Tell us what you have tried.

I see you have a few other similar topics, the pattern is that you get blocked and post your full program here, looking for someone else to spot the problem.

This approach is inefficient. You need to wait for someone to spot your error, which is a waste of your time. Also you have different people reading large amounts of code every time, as you cannot narrow down the source of the issue.

A better approach would be to invest some time into learning how to debug these situations for yourself.

For example, in a recent thread you were strongly advised to add more error checking code. Start there, before you do anything else.

Part of this is learning to use your tools, such as a debugger. As a beginner, I remember finding the debugger rather intimidating so I learned to use "printf debugging", which is basically inserting print statements at different points to allow you to understand how your program is running and what values different variables might have at the time. While it is worth your time investing in a proper debugger, even using printf debugging you'll be able to find and fix many bugs.

There are techniques to speed up debugging, for example disabling portions of your program so you can focus on a smaller part and checking that for correctness. For example, start by checking that a single static particle will draw as expected, before enabling multiple particles and movement.

@rip-off: I know, I'm posting the code here and waiting for somebody to give me a clue. But in this time I still try to figure it what is the problem.:P
I tried to not use the emitter object and to create just a single particle object and it works. It draws the particle. But with the emitter object, it doesn't draw. Not even one.
Also I used "couts" to see if is updating the positions of the particles, and is updating.

So that is a good start! There is more narrowing down to do. Here are some examples:

* Have you tried an emitter with just one particle?
* Have you tried two particles without the emitter?
* Have you tried making the particles stationary?

@fleabay: I copied from a tutorial just the main.cpp. The rest of the classes I wrote them. :P

@NightCreature83: I'm pretty sure the OpenGL commands are handled by the gpu because is not the first time when I use them. I already created a snake and a pong game. :P

I have used D3D11 for a while now I still use these tools to figure out what goes wrong if something isnt showing up as I expect them to show up. Using tools only makes it easier to find the location where your problem is and thus much easier to solve your issue.

Worked on titles: CMR:DiRT2, DiRT 3, DiRT: Showdown, GRID 2, theHunter, theHunter: Primal, Mad Max, Watch Dogs: Legion

@rip-off: All three of them I tried. Something is wrong.I think from the emitter. What I realized is when I try let's say with 10 particles, and I use "cout" after the draws method it gives me Draw 0, 1, 2... 8. So it doesn't print the 10th draw which should be "Draw 9".

Progress, excellent!

So, take another look at the code:

void Emitter::Draw(Shader &shader)
{
    for (int i = 0; i < particles.size() - 1; i++)
    {
        particles[i].Draw(shader);
    }
}
 
void Emitter::Update(GLfloat dt)
{
    for (int i = 0; i <= particles.size() - 1; i++)
    {
        particles[i].Update(dt);
    }
}
 
void Emitter::SetParticlesAttributes()
{
    for (int i = 0; i <= particles.size() - 1; i++)
    {
        particles[i].setLife(10.0f); //(((rand() % 10) + 1) * 15);
        particles[i].setVelocity(glm::vec3(0.0f, 2.0f, 0.0f)); //(((rand() % 10) + 1) * 2));
    }
}
 

Can you spot any reason why Draw might not draw the last element? In particular, can you see any differences between the Draw() function and the others?

This topic is closed to new replies.

Advertisement