View Full Version : Seamus McNally's fire effect
SteveH
02-07-2009, 12:48 PM
Hi, I've been working on this for a while and have run into a problem that I can't spot.
I'm using OpenGL and C++ and I'm not looking for optimizations just yet, just a solution to make this work. I originally had a working implementation where I just stored a buffer of unsigned bytes and just used a standard putpixel type function to render my particles, blurred it as necessary, then used glDrawPixels to render.
I'd like to have everything drawn using glBegin and glEnd calls now so I can have things like burning text. As a result, I've modified the way the code works and abstracted the blurring process and apply it to the whole screen using glReadPixels and glDrawPixels. This is my code as is. It works, but there's no blurring effect.
unsigned char* buffer = new unsigned char[640*480*3]; // this is created elsewhere obviously.
// main rendering loop.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glReadPixels(0,0,640,480,GL_RGB,GL_UNSIGNED_BYTE,b uffer);
unsigned char pixel = 0;
for (int i=1923;i<640*480*3-3;i++)
{
pixel = ((buffer[i] + buffer[i+3] + buffer[i-3] + buffer[i-1920]) >> 2) - 1;
if (pixel >= 255)
pixel = 0;
if (pixel <= 0)
pixel = 0;
buffer[i] = pixel;
}
glDrawPixels(640,480,GL_RGB,GL_UNSIGNED_BYTE,buffe r);
SwapBuffers(hDC);
And of course, assume that before glReadPixels is called, I'm making calls to glBegin(GL_POINTS); setting the color and vertex data and then calling glEnd(); As I said, it renders the points just fine, but with no blur effect.
SteveH
02-13-2009, 11:42 AM
Nobody has any input? This seems like a fairly straightforward problem... Surely someone here should have an answer...?
Reedbeta
02-13-2009, 12:42 PM
The code looks fine to me. The only thing I can think of is maybe the raster position is set to something weird and the DrawPixels call is putting all its pixels off-screen, or something of that sort. Does it work if you set the blurred image as a texture and render a full-screen quad?
monjardin
02-13-2009, 12:55 PM
Try this:
unsigned char* buffer = new unsigned char[640*480*3]; // this is created elsewhere obviously.
// main rendering loop.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glReadPixels(0,0,640,480,GL_RGB,GL_UNSIGNED_BYTE,b uffer);
unsigned int pixel = 0;
for (int i=1923;i<640*480*3-3;i++)
{
pixel = (((unsigned int) buffer[i] + buffer[i+3] + buffer[i-3] + buffer[i-1920]) >> 2) - 1;
buffer[i] = pixel >= 255 ? 0 : pixel;
}
glDrawPixels(640,480,GL_RGB,GL_UNSIGNED_BYTE,buffe r);
SwapBuffers(hDC);
kusma
02-15-2009, 03:00 AM
The code seems to be confused about the resolution it's processing. The buffer allocated and read with glReadPixels seems to use 640 by 480, but the offsets to i seems to assume a screen width of 1920.
edit: never mind. 640 * 3 is 1920, I got confused and assumed you were working with FullHD-resolutions.
SteveH
02-15-2009, 07:38 PM
No the code works as long as I'm not using glReadPixels. If I just update my buffer pixel by pixel and implement the blur, then call glDrawPixels it works perfectly, but I don't want to have to write text pixel by pixel, so I'm looking to use glReadPixels to grab the entire screen, apply my blur to everything, then write it back with glDrawPixels.
I tried rendering to a texture and then just making a fullscreen quad, but that just made the entire screen change to the color of whatever pixel happened to be currently written to the buffer.
I could be wrong about this but I thought glReadPixels didn't need to be prefaced with a glRasterPos2i.
Reedbeta
02-15-2009, 07:51 PM
It doesn't. I was thinking the glDrawPixels call was going off.
Regarding the fullscreen quad, you did set up texture coordinates for it, right? So the whole image gets mapped to the whole quad?
SteveH
02-16-2009, 04:38 PM
Here's what I'm at now and it's not even close to working. Not even the flashing lights anymore.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glReadPixels(0, 0, 640, 480, GL_RGB, GL_UNSIGNED_BYTE, buffer);
unsigned int pixel = 0;
for (int i=1923;i<640*480*3-3;i++)
{
pixel = ((buffer[i] + buffer[i+3] + buffer[i-3] + buffer[i+1920]) >> 2) - 1;
if (pixel >= 255) pixel = 0;
if (pixel < 0) pixel = 0;
buffer[i] = pixel;
}
for (i=0;i<1923;i++)
buffer[i] = 0;
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 640, 480, GL_RGB, GL_UNSIGNED_BYTE, buffer);
glBegin(GL_QUADS);
glTexCoord2f(0, 0); glVertex2f(0, 0);
glTexCoord2f(1, 0); glVertex2f(640, 0);
glTexCoord2f(1, 1); glVertex2f(640, 480);
glTexCoord2f(0, 1); glVertex2f(0, 480);
glEnd();
SwapBuffers(hdc);
To create the texture, I do this:
glEnable(GL_TEXTURE_2D);
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 640, 480, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
And then of course, before all the rendering is done, I do something like this:
glBegin(GL_POINTS);
for (int i=0;i<particles.size();i++)
{
if (particles[i].isAlive())
{
glColor3ub(particles[i].r, particles[i].g, particles[i].b);
glVertex2f(particles[i].x, particles[i].y);
}
}
glEnd();
Any ideas?
Reedbeta
02-16-2009, 07:02 PM
Before you render the quad at the end, do you set up an appropriate projection matrix so that coordinates [0, 640] x [0, 480] are mapped to the screen? I would actually recommend setting the projection matrix to the identity, and using vertex coordinates (-1, -1), (1, -1), (1, 1), (-1, 1). Also don't forget to disable depth testing before drawing the quad, if you're using it elsewhere.
SteveH
02-16-2009, 09:48 PM
But I'm using an orthographic projection matrix set to 640 by 480. In order to make it 1, 1 wouldn't it have to be a 3 dimensional matrix? And if so, wouldn't that make things run slower?
Reedbeta
02-16-2009, 10:13 PM
Ahh, okay. If you're setting an orthographic projection, that should be fine. However, based on what you said earlier, that it works if you render the image on the CPU and then use glDrawPixels, I think the problem is elsewhere. You might as well go back to glDrawPixels.
wouldn't it have to be a 3 dimensional matrix? And if so, wouldn't that make things run slower?
No, what I was recommending is setting the projection matrix to the identity. It would be equivalent to an orthographic projection with left, bottom, right, top = -1, -1, 1, 1. For performance it shouldn't make a difference whether you use an orthographic or perspective matrix. The GPU does the same calculations either way.
SteveH
02-17-2009, 11:12 AM
Well the problem with just using glDrawPixels is that I can't use effects like burning text or burning anything, except individual pixels that I manually write to a buffer.
Reedbeta
02-17-2009, 01:06 PM
I'm talking strictly about how you get the final pixels to the screen, after whatever effects you may run. I'm saying glDrawPixels is just as good for that as my suggested approach of setting a texture image and drawing a quad. In other words your original problem of the blur not showing up is caused by something further up the pipeline. I don't know what it might be.
vBulletin, Copyright ©2000-2010, Jelsoft Enterprises Ltd.