How can I implement light beams with DirectX 9 or 11?

Started by
3 comments, last by Styves 9 years, 4 months ago

Although lighting is very fundamental in DirectX programming, but there's one pitfall that can sometimes reduce the fun of a game: we can't SEE the LIGHT itself! Instead, only when the light strikes some object in the game scene can we know that it really exists! But sometimes, if we can ''directly see'' the light itself, the effects would be more interesting. For example, in many games, while holdinga flashlight at night, you can directly see the light beam emitted by it.

The problem is: what do we need to do in order to implement it? We already know that in real life, the reason for our being able to see a light beam is that the atmosphere is full of tiny particles; but in games, basically everything exists in vacuum, and it's of course impractical to create many small particles and let them reflect the light. So what can we do?

I think this technique is a bit like producing shadows. But am I right?smile.png

Some things, although seemingly beyond my reach, are never totally non-accomplishable, as long as I am strong enough!

Advertisement

Not really like shadows, no. You may be looking for what are commonly called "god rays," which can be done with blurring in one or more passes in a shader. More commonly, however, for light cones and such, "volumetric light" is used. You create a quad or box, textured with a transparent texture, and render it with alpha blending so the background scene shows through.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

I once implemented volumetric light effect . My method was this:

- Render enough planes . These planes are parallel to the near plane which means they are always facing the camera . How many you may ask? The more the better ;)

- When rendering each of these planes in the pixel shader determine the attenuation of the light on it. Also you can use a shadow map to get shadows.

This way you get fairly good result .

Nowadays , but I see modern games use more interesting approaches . For example take a look at the Kill Zone : Shadow Fall . They basically use the same idea but without multiple draw calls to render the planes . They ray march through the cone or sphere (based on the Light type) and do the same things (attenuation , Shadows , etc).

for dark scenes, a cone light plus fog works well.

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

The simplest approach IMO would be to use a cone mesh for your flashlight, and use an inscattering pixel shader on it with additive blending - no culling or depth testing.

To get a correct result for your beam though, you only want the light accumulated from the front of the mesh to the back, not from the camera to the back (which is what you'll get if you use the inscatter shader on it's own). To fix this you'll need to subtract the front face results from the back face (you can use SV_IsFrontFace or VFACE to determine front faces and then multiply the output by -1 if it's a front face). This will remove the contribution from the front faces, giving you only the inscattering through the beam from the front to the back. You'll also need to use the depth buffer to avoid your beams going through surfaces (volumeDepth = min( sceneDepth, meshDepth )). smile.png

Essentially what I'm describing is this.

If you need something with a little more flexibility, you can ray march your light volume or voxelize it (in light space, view space or world space). All of the approaches come with their own benefits and tradeoffs, so it's really up to you to decide which will suit your needs. For a simple flashlight I'd go with the beam approach because it can be done at full resolution, is very fast, doesn't suffer from limited resolution or limited sampling and has perfect temporal stability since it's essentially just a cone mesh with a fancy shader on it.

Edit: Here's some pseudo-code. Make sure your winding order is correct when picking the front faces or this won't work properly!


float sceneDepth = tex2D( depthMap, IN.texCoord.xy ); // Linear depth, make sure it's 0-Far Plane and not 0-1 for this shader.
float meshDepth = IN.meshDepth; // Same as above, but from the vertex shader of this mesh.

float volumeDepth = min(meshDepth, sceneDepth); // Minimum of scene depth and mesh depth for the inscattering integral.

float3 viewDir = normalize( IN.viewDir.xyz ); // world position - camera position


float inscattering = InScatter(cameraPos, viewDir, lightPos, volumeDepth); // Function from Macklin's blog.
inscattering *= isFrontFace ? -1.0f : 1.0f; // isFrontFace = SV_IsFrontFace

return inscattering; // Output

This topic is closed to new replies.

Advertisement