Shader and Particles Help, using ofxGpuParticles

Not sure if this is a beginner or advanced question. I’m pretty good with ofx but horrible with shaders.

Currently I’m using @neilmendoza’s excellent ofxGpuParticles.

I see the fragment shader just makes every point white with a 10% alpha. If i had a texture that had the same resolution as the particle system, how can I make it so each point was the color of one point on the texture, so it starts off with an image and then you can see it dissolving? It seems like it should be simple but it eludes me.

Thanks for any help, i’m kind of facing a deadline :frowning:

I did this exact thing a couple months back. I don’t have the exact code with me now but I can point you in the right direction. This is what it looks like to the best of my memory:

testApp.cpp (based on the example he provides)

void testApp::setup()
{
ofBackground(0);
ofSetFrameRate(60);

unsigned w = 1000;
unsigned h = 1000;

float* particlePosns = new float[w * h * 4];
ofColor* colors = new ofColor[w * h];
for (unsigned y = 0; y < h; ++y)
{
    for (unsigned x = 0; x < w; ++x)
    {
        unsigned idx = y * w + x;

        particlePosns[idx * 4] = 400.f * x / (float)w - 200.f;
        particlePosns[idx * 4 + 1] = 400.f * y / (float)h - 200.f;
        particlePosns[idx * 4 + 2] = 0.f;
        particlePosns[idx * 4 + 3] = 0.f;

        colors[idx] =  image.getColor(x, y);

    }
}
particles.init(w, h, colors);
particles.loadDataTexture(ofxGpuParticles::POSITION, particlePosns);
delete[] particlePosns;
delete[] colors;

// initial velocities
particles.zeroDataTexture(ofxGpuParticles::VELOCITY);

// listen for update event to set additonal update uniforms
ofAddListener(particles.updateEvent, this, &testApp::onParticlesUpdate);
}

GpuParticles.h

void init(unsigned width, unsigned height, ofColor* colors,
              ofPrimitiveMode primitive = OF_PRIMITIVE_POINTS, bool 
              loadShaders = true, unsigned numDataTextures = 2);

GpuParticles.cpp

void GpuParticles::init(unsigned width, unsigned height, ofColor* colors, ofPrimitiveMode primitive, bool loadShaders, unsigned numDataTextures)
{
    ...
     mesh.clear();
    for (int y = 0; y < height; ++y)
    {
        for (int x = 0; x < width; ++x)
        {
            mesh.addVertex(ofVec3f(200.f * x / (float)width - 100.f, 200.f * 
                y / (float)height - 100.f, -500.f));
            mesh.addTexCoord(ofVec2f(x, y));
            mesh.addColor(colors[x + y * width]);
        }
    }
...

That code is untested, but it should be pretty close. Hopefully that’s enough to get you started and debugging.

Edit: I posted this because you said you were on a tight deadline so I figured it was better than nothing. I’ll have a chance to look at the actual, working code again on Monday if you’re still having trouble with it, and it’s not too late.

2 Likes

Monday would be great! The hard deadline isn’t until a week and a half but there are milestones that i’m behind on. @tabularasa1992, you’re a lifesaver.

Didn’t you have to rewrite the shader? It seems the shader is setting all the vertices to white

Yes, you’re right. All you have to do to the shader is in draw.frag. Change the line

gl_FragColor = vec4(1.0, 1.0, 1.0, 0.1);

to

gl_FragColor = gl_Color;

Also, a couple of changes to testApp.cpp:

void testApp::setup()
{
ofBackground(0);
ofSetFrameRate(60);

unsigned w = 1000;
unsigned h = 1000;

float* particlePosns = new float[w * h * 4];
ofColor* colors = new ofColor[w * h];

//Load the image first.
ofImage image;
image.loadImage("path/to/my/image");

//Regardless of the max width and height you set earlier, make sure x and y only increment up to your image width and height, else you will get errors.

for (unsigned y = 0; y < image.getHeight(); ++y)
{
    for (unsigned x = 0; x < image.getWidth(); ++x)
    {
        //Alpha test for transparency's sake.
        ofColor cur = image.getColor(x, y);
        if (cur.a > 0){
            cur.a = 255;
            unsigned idx = y * w + x;

            particlePosns[idx * 4] = 400.f * x / (float)w - 200.f;
            particlePosns[idx * 4 + 1] = 400.f * y / (float)h - 200.f;
            particlePosns[idx * 4 + 2] = 0.f;
            particlePosns[idx * 4 + 3] = 0.f;

            colors[idx] =  cur;
        }
    }
}
//Pass the colors into the ofxGpuParticles class.
particles.init(w, h, colors);
particles.loadDataTexture(ofxGpuParticles::POSITION, particlePosns);
delete[] particlePosns;
delete[] colors;

// initial velocities
particles.zeroDataTexture(ofxGpuParticles::VELOCITY);

// listen for update event to set additonal update uniforms
ofAddListener(particles.updateEvent, this, &testApp::onParticlesUpdate);
}

Oh and one more thing. If you’re loading a picture, doing additive blending when you draw will make it look washed out. Comment that out (or delete it) in your testApp.cpp draw function:

void testApp::draw()
{
    cam.begin();
    //ofEnableBlendMode(OF_BLENDMODE_ADD);
    particles.draw();
    //ofDisableBlendMode();
    cam.end();
}

That should be it. A fresh program using that code works for me, but let me know if you have any trouble.

Thanks, @tabularasa1992. I ended up doing a lot of that. I think i like additive blending, but you’re right it does look washed out. I am doing this with 3 dimensional data, so maybe i can modulate its brightness/alpha by its distance.

Ok cool, I’m glad you got it working. Good luck with your project!

I’ll try to post something as soon as I can to show what it is. Thanks, @tabularasa1992!

Hi, I am struggling with the same issues. I want to create particles from image. I have got strange results. Can somebody help me with this? @vertgo Did you manage it?


Here is a whole code:
https://github.com/sebasobotka/ofxGpuParticles