PDA

View Full Version : Light Flares in UT



MichaelK
10-08-2002, 12:51 AM
How these guys from Epic done this? The effect of light flare is cool. Are threr any tutus about it?

MickeyMouse
10-08-2002, 01:45 AM
Here's what I do in my engine

The code below updates last time certain light was visible. Hope it's clear enough...

You should call this after the whole scene is rendered...



int i;
GLdouble mvmatrix[16];
GLdouble x, y, z;
float z2;

glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);

for (i = 0; i < numLights; i++)

if (frustum->testPoint( lights[i].bsphere.mid ))
{
// Project it
gluProject(
lights[i].bsphere.mid[0],
lights[i].bsphere.mid[1],
lights[i].bsphere.mid[2],
mvmatrix, screen->projmatrix, screen->viewport,
&amp;x, &amp;y, &amp;z);

// Fits in screen bounds?
if ((x < 0) &amp;#0124; &amp;#0124; (SCREEN_WIDTH <= x) &amp;#0124; &amp;#0124; (y < 0) &amp;#0124; &amp;#0124; (SCREEN_HEIGHT <= y))
continue;

// Get z value from z-buffer
glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &amp;z2);

// Closer?
if (z > z2)
continue;

// Visible! - update last visiblity time
lights[i].lastTime = clock.time;
}


Now all you need is to display your lights with blend params depending on last visibility time, here you go...



int i;

glBindTexture(GL_TEXTURE_2D, lightTex.id);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glDepthMask(GL_FALSE);
glDisable(GL_DEPTH_TEST);

for (i = 0; i < numLights; i++)
{
if (clock.time - lights[i].lastTime > 500)
continue;

glPushMatrix();

glTranslatef(lights[i].bsphere.mid[0], lights[i].bsphere.mid[1], lights[i].bsphere.mid[2]);
glRotatef(-view->angles[1], 0, 1, 0);
glRotatef(-view->angles[0], 1, 0, 0);
glRotatef(-view->angles[2], 0, 0, 1);

glColor4f(
lights[i].rgb[0],
lights[i].rgb[1],
lights[i].rgb[2],
(500.0f - (clock.time - lights[i].lastTime)) * 0.002f);

glScalef(
lights[i].bsphere.radius,
lights[i].bsphere.radius,
lights[i].bsphere.radius);

glBegin(GL_QUADS);

glTexCoord2f(1, 1);
glVertex3f(-1, -1, 0);

glTexCoord2f(0, 1);
glVertex3f(-1, 1, 0);

glTexCoord2f(0, 0);
glVertex3f(1, 1, 0);

glTexCoord2f(1, 0);
glVertex3f(1, -1, 0);

glEnd();

glPopMatrix();

}


Should work although actually you should also do different light corona scaling - until certain distance this should be "distance from viewer" independent.

MickeyMouse
10-08-2002, 01:54 AM
...or maybe I misunderstood you completely http://www.opengl.org/discussion_boards/ubb/smile.gif,...are light flares (what I call light coronas) the kind of lights seen as a circle of some color visible only when an eye of player can see it directly??

sorry if it's not what you asked for...

MichaelK
10-08-2002, 11:13 AM
Yes, this is exactly what i mean. If i see a small light source and a large corona, then when it is covered by a thin object, corona should also disappear.
But, in Your code You use ReadPixels.
Isn it too slow.
UT on my machine reaches 100FPS, so it must be done in different technique.

Pozdrawiam,

NitroGL
10-08-2002, 11:26 AM
glReadPixels isn't that slow when it's only 1x1 pixel area.

MichaelK
10-08-2002, 11:33 AM
OK, but how can i find this 1x1 area?
Thats why i am asking for any tuts.

MichaelK
10-08-2002, 11:35 AM
Sorry, sorry.

The answer is in the code.

Wielkie dzieki, Miki Mouse.

fresh
10-08-2002, 02:12 PM
UT doesn't read the zbuffer. You can tell by moving a character in front of a corona. You'll see that it doesn't disappear. If it were reading the zbuffer it would disappear.

UT traces a line from viewer to light and tests this against the BSP tree. So only scene elements hide the light.

secnuop
10-08-2002, 03:48 PM
Originally posted by fresh:
UT doesn't read the zbuffer. You can tell by moving a character in front of a corona. You'll see that it doesn't disappear. If it were reading the zbuffer it would disappear.

UT traces a line from viewer to light and tests this against the BSP tree. So only scene elements hide the light.

That's possible. But it's also possible that the zbuffer read was done before drawing the dynamic elements (i.e. characters), right? Just a thought.

Good observation though.

fresh
10-08-2002, 04:37 PM
If you're gonna read the zbuffer you might as well do it properly and draw everything. I don't see why they'd chose to read the zbuffer before drawing the characters. It looks like crap when you see a corona shine through a character.

Reading the zbuffer forces a flush in the graphics pipeline. I'm 99.9% certain they'r enot reading the zbuffer.

jwatte
10-08-2002, 08:35 PM
You don't want to be running more than one frame behind anyway. The engine I work on does something like this for lens flare (more or less same as corona):

1) read back where light source was last frame, in screen space
2) clear Z
3) draw skybox
4) draw terrain
5) draw objects
6) if light source Z value == distance to light, make corona more visible, else make corona less visible (to fade in/out over a few frames)
7) draw lens flare/corona with visibility calculated, if visible at all
8) run physics
9) swapbuffers

You will note that this version gives excellent overlap between the CPU and the GPU, and it still uses Z buffer read (which is a problem on cards like i845 and Kyro, though...)

dorbie
10-09-2002, 12:38 AM
I believe they ray cast with a low pass filter (z or color readback could work too but might be inefficient). In other words they test a ray between the viewer and potentially visible lights each frame (or at least every few frames) When the light is visible they enable the flare, fading it in over several frames, when the light is not visible they do not disable the flare, they fade it out. This avoids the flare flicking on and off suddenly which would be distracting and look unreal (excuse the pun).

The disadvantage of doing this is the flare is often partly visible for a few moments even when the light is obviously hidden from view. Doing the right thing (testing for the exposed area of the flare) would be too expensive for many lights, but has been done....

When rendering, the flare is simply drawn last as a bilboard with no z testing or writing.

The 'state of the art' way to accomplish this kind of effect in an even more compelling way was shown by ATI in their HDR (high dynamic range) rendering demo albeit on a high end card, where a convolution filter can be applied in hardware (using straightforward multitexture taps from the same texture) over an image that renders beyond the brightest intended visible range for the whole scene (I believe they actually drew a smaller snapshot for this particular stage). It is much more convincing than simple point lights, the whole sky or portions of it can bloom around the scene in a very compelling way. And of course your lights can bloom/flare too.

Similar things have been done elsewhere, for example rendering the Sun's glare in the "Nature" demo, by drawing the sun hidden by the scene to a very small texture and using that to apply the glare in eye space.


[This message has been edited by dorbie (edited 10-09-2002).]

MichaelK
10-09-2002, 02:55 AM
[]Similar things have been done elsewhere, for example rendering the Sun's glare in the "Nature" demo, by drawing the sun
hidden by the scene to a very small texture and using that to apply the glare in eye space.[]

Hmm, thats interesting. You say that this small texture is expanded and used as a glare?
I have heard that it can be achieved by:
-rendering to small texture (say 16x16)
- read it and average all pixels,
- modulate the color with sun glare,

BUT, isnt reading the texture (downloading) to average the intensity of glare as much ineficent as reading Z-buffer?
Also ive heard that rendering to texture on GeForce2 "runs like crap".

Best regards. Michal Krol.

[This message has been edited by MichaelK (edited 10-09-2002).]

Lars
10-09-2002, 05:56 AM
You can also use the Pixel Data Range Extension (see new nvOGLSpecs on developer.nvidia.com) from Nvidia to accelarate the zbuffer access.

And the big advantage is, it also works with alphatested pixels (trees). The method with raycasting wouldnt work here. And HDR isn't possible on every hardware...my poor gf2go :-(

Lars

fresh
10-09-2002, 10:18 AM
jwatte, yes you're right it's no big deal to read back the zbuffer (despite what devrel wants you to believe! http://www.opengl.org/discussion_boards/ubb/smile.gif ). I have used this method in a previous game with no speed loss. I was just saying that in the specific case of UT, it appears that they're not reading the zbuffer. You can tell by the fact that only the static scene elements seem to occlude the coronas, and not dynamic objects like characters. My point is that if you're gonna read the zbuffer, you might as well do it right and do the read after you finish drawing everything.