6
\$\begingroup\$

I have a small test environment where small point lights are scattered. Players should able to collect them.

The collectible lights are rendered using a simple billboard technique where two triangles with a uniform color are rendered facing the camera and a gaussian is used as an alpha-map.

0/1     1/1
+---------+
¦        /¦
¦      /  ¦
¦    /    ¦ u/v texture coordinates for alpha map (gaussian)   
¦  /      ¦ every vertex has same color rgb(1, 1, 1)
¦/        ¦
+---------+
0/0     1/0

When a player collects a light, the idea is that the collected light is merged with the lights he already has collected. The players are currently rendered with the same method as the collectible lights, the collected light has influence when the lighting is calculated => higher light intensity.

Light as it looks now

What I'm looking to do is to visualize the lights better. They look really boring the way they are rendered currently. Only good thing about them is that they do not influence the performance :-)

The process of the light merge could for example be visualized in a way where all collected lights circle around as small pulsating glowing particles - sticking together to some extent - maybe some nice lines which travel with them - you know, like such a thing should look like if it is a central part of a game.

The problem is that I don't really find many resources over advanced shader effects. Most information found is over the basics (diffuse / specular shader - maybe some blurring) or does not involve the HLSL language which I use in XNA 4.0.

I would appreciate any links to resources which could help me making more awesome light effects which could actually run on the xbox without running into performance issues. Basically, any techniques which involve rendering cool light orbs / beams etc. would be fine for the moment if the result i visually appealing.

\$\endgroup\$
2
  • \$\begingroup\$ Something like andrewrussell.net/dark ? \$\endgroup\$ Commented Apr 9, 2011 at 5:17
  • \$\begingroup\$ Not exactly, however - I like the atmosphere :-) I've added a screenshot of my current lights to the question. It's an FPS game, where you have to compete with each other about this collectible lights. The problem is that you start to glow stronger if you collect more lights and you get more visible then and are more easily to be shot. \$\endgroup\$
    – Etan
    Commented Apr 9, 2011 at 8:37

2 Answers 2

10
\$\begingroup\$

Neat idea for the game. The problem is that light really doesn't look like this. Light decay is NOT gausian :). That's for the begining. What i want to propose is adding simple (but relatively physicaly correct) fog or dust. Mean volumetric effect. You will have to implement volumetric raycasting on the gpu. Don't panic. It is not that hard as it might sound.

I have created this in our engine for you as a example how it might look like. It is realtime. And can be realtime for few lights with cube map shadow map. (low fps is caused by output)

enter image description here

What do you see here is fog (or dust) containing lights. Lights are represented only by their position, color and intensity. They have cubic decay, which looks natural and fits to the definition of the Radiance. Lights has different intensity, exactly what you wanted.

Volumetric raycasting casts ray for every pixel and samples through the volume. It is usualy used for smoke, dust or fire on offline rendering, but can be done on gpu in realtime. You dont have actual volume, but you have to sample for the shadows contained in the shadow maps. If you want only fog, it can be done with O(1) complexity (per pixel shader)

You sample on ray like this:

//pseudo ugly pixel shader code
samplePoint = zNear;  //position on zNear (in worldSpace)
color = 0;
until(z-buffur_value || zFar)
{
    lightDecay = getLightDecay(samplePoint,lightPosition); 
    shadow = getShadow(samplePoint); //like regular shadow mapping, you have world space position and want to know if there is shadow or not.
    color.rgb += (1 - color.a) * (lightColor * lightIntensity * lightDecay * shadow);
    color.a += (1 - color.a) * (1 - opacity); //opacity is the same in your case. If rendering something like clouds it is loaded from the 3D texture. I suggest value like 0.01 or similar..
    samplePoint += direction * step;
}

It is not hard actually and can be done as a pixel shader (offscreen). You have to stop sampling rays at z-buffer value (so it has to be applied after the opaque scene render). And alpha blended with opaque scene render.

It is pretty solution to this. It also attenuates lights which are far from player, solves the intensity correctly and i think it looks cool.

For more info you maybe like read my paper about implementation of volumetric effects into game engine (well something similar to game engine :)).

There is also awesome book about volumetric rendering. I'm in love with it. Also this site contains pdf tutorials which are quite good introduction to the volume graphics.

Improvement: Adding colors to lights and perlin noise to the volume to look more natural (left without perlin|right with perlin)

enter image description hereenter image description here
(hmm those gifs are too low quality that there is no significant difference).

edit (some performance notes): it can be done as one pass per light, which is usefull if lights has lots of aditional textures (light color - projective texturing, intensity curves etc.). But this is frame rate killer, it can (and should) be done in one pass for all lights if you have enough texture units available (i think you have in your game). Than it can have about 45-60fps i hope.

Sampling doesn't have to be linear. You can make sampling logartmic (or similar function).

makeEveryStepALittleBigger = 1.05;
samplePoint += direction * step;
step *= makeEveryStepALittleBigger; //this should be actualy based on camera FOV

This however destroy physical correctness and "opacity correction" has to be done. Which is:

curentAlpha = 1 - pow((1 - opacity), delta);

where delta is difference between step1 and step2.

And if you dont mind little noise, you can add depth jittering which allows you to use much lower number of samples (that is pretty good and easier solution).

That was fun...

\$\endgroup\$
9
  • \$\begingroup\$ For the vertex shader, will I render two triangles over the near-plane of the camera? So that for every pixel in the near-plane, a ray can be traced to the light? \$\endgroup\$
    – Etan
    Commented Apr 10, 2011 at 10:43
  • 1
    \$\begingroup\$ @Etan Yes exactly. Except that ray is not traced to the light but just in its direction = (pixel_position_on_near_plane_in_world_space - cameraPos). And than makes samples on the ray and ask lights for shadow, intensity etc. as in pseudocode. \$\endgroup\$
    – Notabene
    Commented Apr 10, 2011 at 10:47
  • \$\begingroup\$ So: 1. create vertices (-1, -1, zNear) / (-1, 1, zNear) / (1, -1, zNear) / (1, 1, zNear) 2. create two triangles over this vertices in clockwise orientation 3. in my vertex shader, apply inverse projection matrix to it, then inverse camera view matrix to get world coordinates 4. in my pixel shader, shoot a ray from the calculated position to the light and calculate color \$\endgroup\$
    – Etan
    Commented Apr 10, 2011 at 11:11
  • 1
    \$\begingroup\$ Yes. This is one of many solutions. Ray directions can be also computed analyticaly: gamedev.stackexchange.com/questions/8974/…. But your solutions is nice. Maybe look at the book realtime volume rendering on google books and find some raycaster examples there. I'm not sure how much i'm allowed to share my solutions with you, because they are property of my studio, so i'm just trying to point you to the right direction and sources \$\endgroup\$
    – Notabene
    Commented Apr 10, 2011 at 11:24
  • \$\begingroup\$ I've tried to implement the pseudocode in HLSL. After fiddling with many compiling problems due to SM 2.0 restrictions I got to pastebin.com/XeCLzRPa . Couldn't test it until now, but one of my questions is what the effect of this value.a actually is. Why do you use (1.0 - outColor.a) there, what does it stand for? Rest makes perfectly sense. \$\endgroup\$
    – Etan
    Commented Apr 10, 2011 at 11:57
0
\$\begingroup\$

Motion and such will help, but what it sounds like might be an answer for what you're going for is a way to cause them to look more "glowy".

The key to making something look more lit in your scene is by darkening everything else. From there little things like over-saturation of color (leading to light colors washing out to white) and just plain being more lit than the ambient scene will do a lot to add to the effect.

One of the easiest and least intensive ways I can see to get this effect given what you have described would be to go with an additive blend with the scene. Make your individual motes of light have a 70-80% alpha center, before lowering the alpha rather quickly as you travel outward. Make sure if you do this to leave a rather wide (2-3x size of center) ring of very low alpha.

Now this area will be almost imperceptible when blended with the scene alone, but as you gather multiple together, the different slightly shaded areas will overlap causing a more general glow to the whole collection. On top of that, the field does not have to be uniform, and you can leave streaks of slightly more alpha areas in the texture to cause light beams to be hinted at. You'll probably want to rotate the texture over time so the lines don't look static, but overall the effect will cause the bits of light to look more like just that and less like little floating balls.

Hopefully this helps. It's not exactly advanced shader work, but I find sometimes the more simple effects can give a quite satisfactory look. Consider throwing in a soft particle effect as well to allow the lights to leave slight trails or other effects in the player's vision. Happy coding!

\$\endgroup\$
1
  • \$\begingroup\$ The problem with darkening the rest of the scene is, that the only light comes from the players :-) So, it's a very dark environment. For this soft particle effect in your last sentence: This is exactly what my question is: Do you know any tutorials which explain how to do "simple" particle effects in xna 4.0? Also, what model should I use for the players? I don't think that I can use the billboards as now if I should rotate them over time. \$\endgroup\$
    – Etan
    Commented Apr 8, 2011 at 22:30

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .