SFML community forums

Help => Graphics => Topic started by: Cl9 on December 01, 2013, 05:40:23 pm

Title: Weird lines in particle test
Post by: Cl9 on December 01, 2013, 05:40:23 pm
Hello, I've wanted to make a small particle system in SFML. I created the first version using the sf::RectangleShape class to make the little particles and it worked fine but was quite slow (started impacting FPS at around 1500 particles) so I re-wrote a bit of it using vertex arrays which appears to be much faster but the actual window has weird black lines in it:
(http://i43.tinypic.com/2lj44g0.png)


Here's my source file, please note that this is only a rough experiment and so is a bit messy:

Code: [Select]
#include <iostream>
#include <string>
#include <stdio.h>
#include <vector>
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
using namespace std;
sf::Vector2f Randomize(int Boundary1, int Boundary2)
{
    return sf::Vector2f((0 +((rand() % Boundary1))), (0 +((rand() % Boundary2))));
}

int RandomizeInt(int Boundary1, int Boundary2)
{
    return (Boundary1 +((rand() % Boundary2)));
}

struct PI
{
    sf::Color Colour = sf::Color::Yellow;
    int X = 0;
    int Y = 0;
    int LifeTime = 20000;
};

int main()
{
    int FPS = 0; //Setting up variables for measuring the FPS
    sf::Clock FPSClock;
    sf::Time FPSTime;

sf::Music music;
if (!music.openFromFile("sound.ogg"))
    return -1; // error
music.play();



    bool MousePressed = false;
    sf::Clock EffectClock;
    sf::Time EffectTime;

    int ActiveParticles = 0; //How many particles are active

    int ParticleCap = 0; //The limit of how many particles can be placed
    cout << "\nParticle Cap: ";
    cin >> ParticleCap;

    PI ParticleInfo[ParticleCap]; //Our particle information such as colour and lifetime.

    sf::VertexArray Pixel(sf::Points, ParticleCap);

    sf::RenderWindow window(sf::VideoMode(800, 600), "Partical System");
    window.setVerticalSyncEnabled(true);

    while (window.isOpen())
    {
        sf::Vector2i MousePosition = sf::Mouse::getPosition(window); //Storing mouse coords for later use

        if (sf::Mouse::isButtonPressed(sf::Mouse::Left) && MousePressed == false) //Checking if mouse is pressed
        {
            for(int a = 0; a < ParticleCap; a++) //Updating particle information
            {
                Pixel[a].position = sf::Vector2f(MousePosition.x,MousePosition.y);
                ParticleInfo[a].X = MousePosition.x;
                ParticleInfo[a].Y = MousePosition.y;
            }
            MousePressed = true;

            EffectClock.restart();
        }
        else if(!sf::Mouse::isButtonPressed(sf::Mouse::Left) && MousePressed == true)
        {
            MousePressed = false;
        }

        sf::Event event; //Polling window events to check for user input
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                window.close();
        }

        EffectTime = EffectClock.getElapsedTime();
        for(int a = 0; a < ParticleCap; a++) //Updating particle information
        {

            ParticleInfo[a].LifeTime = RandomizeInt(0,40);
            ParticleInfo[a].X = ParticleInfo[a].X + RandomizeInt(0,6) - 3;
            ParticleInfo[a].Y = ParticleInfo[a].Y + RandomizeInt(0,6) - 3;
            Pixel[a].color = ParticleInfo[a].Colour;
            if(EffectTime.asMilliseconds() > ParticleInfo[a].LifeTime)
            {
                //Pixel[a].position = sf::Vector2f(-1,-1);
                ParticleInfo[a].X = MousePosition.x;
                ParticleInfo[a].Y = MousePosition.y;
                Pixel[a].position = sf::Vector2f(ParticleInfo[a].X, ParticleInfo[a].Y);
                EffectClock.restart();
            }
            else
            {
                Pixel[a].position = sf::Vector2f(ParticleInfo[a].X, ParticleInfo[a].Y - 6);
                ParticleInfo[a].Y = ParticleInfo[a].Y - 6;
            }
        }


        window.clear(sf::Color::Black);
        window.draw(Pixel);
        window.display();


        FPS++; //Calculating FPS and displaying it
        FPSTime = FPSClock.getElapsedTime();
        if(FPSTime.asSeconds() >= 1)
        {
            cout << "\nFPS: " << FPS << endl;
            FPSClock.restart();
            FPS = 0;
        }
    }

    return 0;
}


Why is this?
Title: Re: Weird lines in particle test
Post by: Sqasher on December 01, 2013, 06:35:04 pm
I don't have those weird lines, so it could be a driver issue.

(http://i.imgur.com/Zj6UezV.jpg)

If you don't want the particles to form a yellow block, you can increase the spawning area and the lifetime and decrease the number of particles.
ParticleInfo[a].LifeTime = RandomizeInt(15,40);
ParticleInfo[a].X = ParticleInfo[a].X + RandomizeInt(0,20) - 10;
ParticleInfo[a].Y = ParticleInfo[a].Y + RandomizeInt(0,20) - 10;

(http://i.imgur.com/E0RHiUN.jpg)
Title: Re: Weird lines in particle test
Post by: Cl9 on December 01, 2013, 07:26:52 pm
Hm, what compiler are you using?

Altering the way that the particles are spread does not alter the lines in the window and the lines don't move with the particles, they stay stationary. All of my drivers are up to data.
Title: Re: Weird lines in particle test
Post by: Nexus on December 01, 2013, 07:33:54 pm
What if you minimize the code example to a sf::Points vertex array that contains static points? For example if you build a rectangle out of points, do the black lines still appear? Avoid everything that's not directly necessary, and keep the code as small as possible.

If they do not, the problem may also be related to the random generator. Linear congruential generators produce extremely bad random numbers, recognizable patterns are typical for them. You could try with an engine from <random> instead.
Title: Re: Weird lines in particle test
Post by: Cl9 on December 01, 2013, 08:34:40 pm
Oh, I've made shapes out of vertexes before and they do not appear. I've tried seeding the generator and that hasn't changed it.
Title: Re: Weird lines in particle test
Post by: Nexus on December 01, 2013, 08:59:59 pm
It's not about seeding, the regular patterns are an inherent property of linear congruential generators.

I'm not sure if it's that in your case -- that's why I stated you should try the random engines from the <random> header (http://en.cppreference.com/w/cpp/numeric/random) and see if they change something. If you happen use Thor, you could also call thor::random() (http://www.bromeon.ch/libraries/thor/v2.0/doc/_random_8hpp.html).
Title: Re: Weird lines in particle test
Post by: Sqasher on December 01, 2013, 09:03:06 pm
I'm using MinGW 4.8 32bit on Windows 7 with a nVidia GeForce GTX 680 and the latest drivers.

I commented the music part out, but that shouldn't make any difference.

This code should give you a completely white window:
#include <SFML/Graphics.hpp>

int main() {
        int windowWidth = 800;
        int windowHeight = 600;

        sf::VertexArray vertices(sf::PrimitiveType::Points);

        for (int y = 0; y <= windowHeight; ++y) {
                for (int x = 0; x <= windowWidth; ++x) {
                        vertices.append(sf::Vertex(sf::Vector2f(x, y), sf::Color::White));
                }
        }

        sf::RenderWindow window(sf::VideoMode(windowWidth, windowHeight), "Test", sf::Style::Close);
        window.setVerticalSyncEnabled(true);

        while (window.isOpen()) {
                sf::Event event;
                while (window.pollEvent(event)) {
                        if (event.type == sf::Event::Closed) {
                                window.close();
                        }
                }
                window.clear();
                window.draw(vertices);
                window.display();
        }

        return 0;
}
Title: Re: Weird lines in particle test
Post by: Cl9 on December 01, 2013, 09:36:39 pm
Interesting...
(http://i41.tinypic.com/28vxbfm.png)

Why's this?
Title: Re: Weird lines in particle test
Post by: Laurent on December 01, 2013, 09:42:21 pm
Probably a driver issue. Can you try the same test, but with sf::Vector2f(x + 0.5, y + 0.5) for coordinates?
Title: Re: Weird lines in particle test
Post by: Nexus on December 01, 2013, 09:44:25 pm
Strange. What if you choose the correct vertex positions (i.e. center of pixels, not left-upper corner) and don't draw vertices outside the window? That is:
    for (int y = 0; y < windowHeight; ++y) {
        for (int x = 0; x < windowWidth; ++x) {
            vertices.append(sf::Vertex(sf::Vector2f(x+0.5f, y+0.5f), sf::Color::White));
        }
    }
Title: Re: Weird lines in particle test
Post by: Cl9 on December 01, 2013, 09:59:41 pm
It is a completely white screen if I do that.
Title: Re: Weird lines in particle test
Post by: Nexus on December 01, 2013, 10:09:47 pm
Ok, then do it like that :)

(It's a result of the pixel rasterization. OpenGL leaves some freedom to the decision how pixels "on the border" are handled. Usually however, drivers act consistently -- I'm not sure to what degree they have to).

Title: Re: Weird lines in particle test
Post by: Cl9 on December 01, 2013, 10:24:36 pm
Thankyou for your help everyone :D

Do I have to add the +0.5f after every movement or is there a quicker way of doing it?

Here's what I have now which works great:
Code: [Select]
#include <iostream>
#include <string>
#include <stdio.h>
#include <vector>
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
using namespace std;
sf::Vector2f Randomize(int Boundary1, int Boundary2)
{
    srand(time(NULL));
    return sf::Vector2f((0 +((rand() % Boundary1))), (0 +((rand() % Boundary2))));
}

int RandomizeInt(int Boundary1, int Boundary2)
{
    return (Boundary1 +((rand() % Boundary2)));
}

struct PI
{
    sf::Color Colour = sf::Color::Yellow;
    int X = 0;
    int Y = 0;
    int LifeTime = 20000;
};

int main()
{
    int FPS = 0; //Setting up variables for measuring the FPS
    sf::Clock FPSClock;
    sf::Time FPSTime;

sf::Music music;
if (!music.openFromFile("sound.ogg"))
    return -1; // error
music.play();



    bool MousePressed = false;
    sf::Clock EffectClock;
    sf::Time EffectTime;

    int ActiveParticles = 0; //How many particles are active

    int ParticleCap = 0; //The limit of how many particles can be placed
    cout << "\nParticle Cap: ";
    cin >> ParticleCap;

    PI ParticleInfo[ParticleCap]; //Our particle information such as colour and lifetime.

    sf::VertexArray Pixel(sf::Points, ParticleCap);

    sf::RenderWindow window(sf::VideoMode(800, 600), "Partical System", sf::Style::Default);
    window.setVerticalSyncEnabled(true);

    while (window.isOpen())
    {
        sf::Vector2i MousePosition = sf::Mouse::getPosition(window); //Storing mouse coords for later use

        if (sf::Mouse::isButtonPressed(sf::Mouse::Left) && MousePressed == false) //Checking if mouse is pressed
        {
            for(int a = 0; a < ParticleCap; a++) //Updating particle information
            {
                Pixel[a].position = sf::Vector2f(MousePosition.x+0.5f,MousePosition.y+0.5f);
                ParticleInfo[a].X = MousePosition.x+0.5f;
                ParticleInfo[a].Y = MousePosition.y+0.5f;
            }
            MousePressed = true;

            EffectClock.restart();
        }
        else if(!sf::Mouse::isButtonPressed(sf::Mouse::Left) && MousePressed == true)
        {
            MousePressed = false;
        }

        sf::Event event; //Polling window events to check for user input
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                window.close();
        }

        EffectTime = EffectClock.getElapsedTime();
        for(int a = 0; a < ParticleCap; a++) //Updating particle information
        {

            ParticleInfo[a].LifeTime = RandomizeInt(0,40);
            ParticleInfo[a].X = ParticleInfo[a].X + RandomizeInt(0,6) - 3;
            ParticleInfo[a].Y = ParticleInfo[a].Y + RandomizeInt(0,6) - 3;
            Pixel[a].color = ParticleInfo[a].Colour;
            if(EffectTime.asMilliseconds() > ParticleInfo[a].LifeTime)
            {
                //Pixel[a].position = sf::Vector2f(-1,-1);
                ParticleInfo[a].X = MousePosition.x;
                ParticleInfo[a].Y = MousePosition.y;
                Pixel[a].position = sf::Vector2f(ParticleInfo[a].X+0.5f, ParticleInfo[a].Y+0.5f);
                EffectClock.restart();
            }
            else
            {
                Pixel[a].position = sf::Vector2f(ParticleInfo[a].X+0.5f, (ParticleInfo[a].Y - 6)+0.5f);
                ParticleInfo[a].Y = (ParticleInfo[a].Y - 6)+0.5f;
            }
        }


        window.clear(sf::Color::Black);
        window.draw(Pixel);
        window.display();


        FPS++; //Calculating FPS and displaying it
        FPSTime = FPSClock.getElapsedTime();
        if(FPSTime.asSeconds() >= 1)
        {
            cout << "\nFPS: " << FPS << endl;
            FPSClock.restart();
            FPS = 0;
        }
    }

    return 0;
}

Thanks, and sorry for the late replies... I've been filling in college application forms...